1 // Copyright 2015 the V8 project authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "src/objects.h"
6
7 #include <cmath>
8 #include <iomanip>
9 #include <memory>
10 #include <sstream>
11 #include <vector>
12
13 #include "src/objects-inl.h"
14
15 #include "src/accessors.h"
16 #include "src/allocation-site-scopes.h"
17 #include "src/api-arguments-inl.h"
18 #include "src/api-natives.h"
19 #include "src/api.h"
20 #include "src/arguments.h"
21 #include "src/ast/ast.h"
22 #include "src/ast/scopes.h"
23 #include "src/base/bits.h"
24 #include "src/base/utils/random-number-generator.h"
25 #include "src/bootstrapper.h"
26 #include "src/builtins/builtins.h"
27 #include "src/code-stubs.h"
28 #include "src/compiler.h"
29 #include "src/counters-inl.h"
30 #include "src/counters.h"
31 #include "src/date.h"
32 #include "src/debug/debug.h"
33 #include "src/deoptimizer.h"
34 #include "src/elements.h"
35 #include "src/execution.h"
36 #include "src/field-index-inl.h"
37 #include "src/field-index.h"
38 #include "src/field-type.h"
39 #include "src/frames-inl.h"
40 #include "src/globals.h"
41 #include "src/ic/ic.h"
42 #include "src/identity-map.h"
43 #include "src/interpreter/bytecode-array-iterator.h"
44 #include "src/interpreter/bytecode-decoder.h"
45 #include "src/interpreter/interpreter.h"
46 #include "src/isolate-inl.h"
47 #include "src/keys.h"
48 #include "src/log.h"
49 #include "src/lookup-inl.h"
50 #include "src/macro-assembler.h"
51 #include "src/map-updater.h"
52 #include "src/messages.h"
53 #include "src/objects-body-descriptors-inl.h"
54 #include "src/objects/api-callbacks.h"
55 #include "src/objects/arguments-inl.h"
56 #include "src/objects/bigint.h"
57 #include "src/objects/code-inl.h"
58 #include "src/objects/compilation-cache-inl.h"
59 #include "src/objects/debug-objects-inl.h"
60 #include "src/objects/frame-array-inl.h"
61 #include "src/objects/hash-table-inl.h"
62 #include "src/objects/js-array-inl.h"
63 #ifdef V8_INTL_SUPPORT
64 #include "src/objects/js-collator.h"
65 #endif // V8_INTL_SUPPORT
66 #include "src/objects/js-collection-inl.h"
67 #include "src/objects/js-generator-inl.h"
68 #ifdef V8_INTL_SUPPORT
69 #include "src/objects/js-list-format.h"
70 #include "src/objects/js-locale.h"
71 #endif // V8_INTL_SUPPORT
72 #include "src/objects/js-regexp-inl.h"
73 #include "src/objects/js-regexp-string-iterator.h"
74 #ifdef V8_INTL_SUPPORT
75 #include "src/objects/js-plural-rules.h"
76 #include "src/objects/js-relative-time-format.h"
77 #endif // V8_INTL_SUPPORT
78 #include "src/objects/literal-objects-inl.h"
79 #include "src/objects/map.h"
80 #include "src/objects/microtask-inl.h"
81 #include "src/objects/module-inl.h"
82 #include "src/objects/promise-inl.h"
83 #include "src/parsing/preparsed-scope-data.h"
84 #include "src/property-descriptor.h"
85 #include "src/prototype.h"
86 #include "src/regexp/jsregexp.h"
87 #include "src/safepoint-table.h"
88 #include "src/snapshot/code-serializer.h"
89 #include "src/snapshot/snapshot.h"
90 #include "src/source-position-table.h"
91 #include "src/string-builder-inl.h"
92 #include "src/string-search.h"
93 #include "src/string-stream.h"
94 #include "src/unicode-cache-inl.h"
95 #include "src/unicode-decoder.h"
96 #include "src/utils-inl.h"
97 #include "src/wasm/wasm-engine.h"
98 #include "src/wasm/wasm-objects.h"
99 #include "src/zone/zone.h"
100
101 #ifdef ENABLE_DISASSEMBLER
102 #include "src/disasm.h"
103 #include "src/disassembler.h"
104 #include "src/eh-frame.h"
105 #endif
106
107 namespace v8 {
108 namespace internal {
109
ComparisonResultToBool(Operation op,ComparisonResult result)110 bool ComparisonResultToBool(Operation op, ComparisonResult result) {
111 switch (op) {
112 case Operation::kLessThan:
113 return result == ComparisonResult::kLessThan;
114 case Operation::kLessThanOrEqual:
115 return result == ComparisonResult::kLessThan ||
116 result == ComparisonResult::kEqual;
117 case Operation::kGreaterThan:
118 return result == ComparisonResult::kGreaterThan;
119 case Operation::kGreaterThanOrEqual:
120 return result == ComparisonResult::kGreaterThan ||
121 result == ComparisonResult::kEqual;
122 default:
123 break;
124 }
125 UNREACHABLE();
126 }
127
operator <<(std::ostream & os,InstanceType instance_type)128 std::ostream& operator<<(std::ostream& os, InstanceType instance_type) {
129 switch (instance_type) {
130 #define WRITE_TYPE(TYPE) \
131 case TYPE: \
132 return os << #TYPE;
133 INSTANCE_TYPE_LIST(WRITE_TYPE)
134 #undef WRITE_TYPE
135 }
136 UNREACHABLE();
137 }
138
OptimalType(Isolate * isolate,Representation representation)139 Handle<FieldType> Object::OptimalType(Isolate* isolate,
140 Representation representation) {
141 if (representation.IsNone()) return FieldType::None(isolate);
142 if (FLAG_track_field_types) {
143 if (representation.IsHeapObject() && IsHeapObject()) {
144 // We can track only JavaScript objects with stable maps.
145 Handle<Map> map(HeapObject::cast(this)->map(), isolate);
146 if (map->is_stable() && map->IsJSReceiverMap()) {
147 return FieldType::Class(map, isolate);
148 }
149 }
150 }
151 return FieldType::Any(isolate);
152 }
153
ToObject(Isolate * isolate,Handle<Object> object,Handle<Context> native_context,const char * method_name)154 MaybeHandle<JSReceiver> Object::ToObject(Isolate* isolate,
155 Handle<Object> object,
156 Handle<Context> native_context,
157 const char* method_name) {
158 if (object->IsJSReceiver()) return Handle<JSReceiver>::cast(object);
159 Handle<JSFunction> constructor;
160 if (object->IsSmi()) {
161 constructor = handle(native_context->number_function(), isolate);
162 } else {
163 int constructor_function_index =
164 Handle<HeapObject>::cast(object)->map()->GetConstructorFunctionIndex();
165 if (constructor_function_index == Map::kNoConstructorFunctionIndex) {
166 if (method_name != nullptr) {
167 THROW_NEW_ERROR(
168 isolate,
169 NewTypeError(
170 MessageTemplate::kCalledOnNullOrUndefined,
171 isolate->factory()->NewStringFromAsciiChecked(method_name)),
172 JSReceiver);
173 }
174 THROW_NEW_ERROR(isolate,
175 NewTypeError(MessageTemplate::kUndefinedOrNullToObject),
176 JSReceiver);
177 }
178 constructor = handle(
179 JSFunction::cast(native_context->get(constructor_function_index)),
180 isolate);
181 }
182 Handle<JSObject> result = isolate->factory()->NewJSObject(constructor);
183 Handle<JSValue>::cast(result)->set_value(*object);
184 return result;
185 }
186
187 // ES6 section 9.2.1.2, OrdinaryCallBindThis for sloppy callee.
188 // static
ConvertReceiver(Isolate * isolate,Handle<Object> object)189 MaybeHandle<JSReceiver> Object::ConvertReceiver(Isolate* isolate,
190 Handle<Object> object) {
191 if (object->IsJSReceiver()) return Handle<JSReceiver>::cast(object);
192 if (object->IsNullOrUndefined(isolate)) {
193 return isolate->global_proxy();
194 }
195 return Object::ToObject(isolate, object);
196 }
197
198 // static
ConvertToNumberOrNumeric(Isolate * isolate,Handle<Object> input,Conversion mode)199 MaybeHandle<Object> Object::ConvertToNumberOrNumeric(Isolate* isolate,
200 Handle<Object> input,
201 Conversion mode) {
202 while (true) {
203 if (input->IsNumber()) {
204 return input;
205 }
206 if (input->IsString()) {
207 return String::ToNumber(isolate, Handle<String>::cast(input));
208 }
209 if (input->IsOddball()) {
210 return Oddball::ToNumber(isolate, Handle<Oddball>::cast(input));
211 }
212 if (input->IsSymbol()) {
213 THROW_NEW_ERROR(isolate, NewTypeError(MessageTemplate::kSymbolToNumber),
214 Object);
215 }
216 if (input->IsBigInt()) {
217 if (mode == Conversion::kToNumeric) return input;
218 DCHECK_EQ(mode, Conversion::kToNumber);
219 THROW_NEW_ERROR(isolate, NewTypeError(MessageTemplate::kBigIntToNumber),
220 Object);
221 }
222 ASSIGN_RETURN_ON_EXCEPTION(
223 isolate, input, JSReceiver::ToPrimitive(Handle<JSReceiver>::cast(input),
224 ToPrimitiveHint::kNumber),
225 Object);
226 }
227 }
228
229 // static
ConvertToInteger(Isolate * isolate,Handle<Object> input)230 MaybeHandle<Object> Object::ConvertToInteger(Isolate* isolate,
231 Handle<Object> input) {
232 ASSIGN_RETURN_ON_EXCEPTION(
233 isolate, input,
234 ConvertToNumberOrNumeric(isolate, input, Conversion::kToNumber), Object);
235 if (input->IsSmi()) return input;
236 return isolate->factory()->NewNumber(DoubleToInteger(input->Number()));
237 }
238
239 // static
ConvertToInt32(Isolate * isolate,Handle<Object> input)240 MaybeHandle<Object> Object::ConvertToInt32(Isolate* isolate,
241 Handle<Object> input) {
242 ASSIGN_RETURN_ON_EXCEPTION(
243 isolate, input,
244 ConvertToNumberOrNumeric(isolate, input, Conversion::kToNumber), Object);
245 if (input->IsSmi()) return input;
246 return isolate->factory()->NewNumberFromInt(DoubleToInt32(input->Number()));
247 }
248
249 // static
ConvertToUint32(Isolate * isolate,Handle<Object> input)250 MaybeHandle<Object> Object::ConvertToUint32(Isolate* isolate,
251 Handle<Object> input) {
252 ASSIGN_RETURN_ON_EXCEPTION(
253 isolate, input,
254 ConvertToNumberOrNumeric(isolate, input, Conversion::kToNumber), Object);
255 if (input->IsSmi()) return handle(Smi::cast(*input)->ToUint32Smi(), isolate);
256 return isolate->factory()->NewNumberFromUint(DoubleToUint32(input->Number()));
257 }
258
259 // static
ConvertToName(Isolate * isolate,Handle<Object> input)260 MaybeHandle<Name> Object::ConvertToName(Isolate* isolate,
261 Handle<Object> input) {
262 ASSIGN_RETURN_ON_EXCEPTION(
263 isolate, input, Object::ToPrimitive(input, ToPrimitiveHint::kString),
264 Name);
265 if (input->IsName()) return Handle<Name>::cast(input);
266 return ToString(isolate, input);
267 }
268
269 // ES6 7.1.14
270 // static
ConvertToPropertyKey(Isolate * isolate,Handle<Object> value)271 MaybeHandle<Object> Object::ConvertToPropertyKey(Isolate* isolate,
272 Handle<Object> value) {
273 // 1. Let key be ToPrimitive(argument, hint String).
274 MaybeHandle<Object> maybe_key =
275 Object::ToPrimitive(value, ToPrimitiveHint::kString);
276 // 2. ReturnIfAbrupt(key).
277 Handle<Object> key;
278 if (!maybe_key.ToHandle(&key)) return key;
279 // 3. If Type(key) is Symbol, then return key.
280 if (key->IsSymbol()) return key;
281 // 4. Return ToString(key).
282 // Extending spec'ed behavior, we'd be happy to return an element index.
283 if (key->IsSmi()) return key;
284 if (key->IsHeapNumber()) {
285 uint32_t uint_value;
286 if (value->ToArrayLength(&uint_value) &&
287 uint_value <= static_cast<uint32_t>(Smi::kMaxValue)) {
288 return handle(Smi::FromInt(static_cast<int>(uint_value)), isolate);
289 }
290 }
291 return Object::ToString(isolate, key);
292 }
293
294 // static
ConvertToString(Isolate * isolate,Handle<Object> input)295 MaybeHandle<String> Object::ConvertToString(Isolate* isolate,
296 Handle<Object> input) {
297 while (true) {
298 if (input->IsOddball()) {
299 return handle(Handle<Oddball>::cast(input)->to_string(), isolate);
300 }
301 if (input->IsNumber()) {
302 return isolate->factory()->NumberToString(input);
303 }
304 if (input->IsSymbol()) {
305 THROW_NEW_ERROR(isolate, NewTypeError(MessageTemplate::kSymbolToString),
306 String);
307 }
308 if (input->IsBigInt()) {
309 return BigInt::ToString(isolate, Handle<BigInt>::cast(input));
310 }
311 ASSIGN_RETURN_ON_EXCEPTION(
312 isolate, input, JSReceiver::ToPrimitive(Handle<JSReceiver>::cast(input),
313 ToPrimitiveHint::kString),
314 String);
315 // The previous isString() check happened in Object::ToString and thus we
316 // put it at the end of the loop in this helper.
317 if (input->IsString()) {
318 return Handle<String>::cast(input);
319 }
320 }
321 }
322
323 namespace {
324
IsErrorObject(Isolate * isolate,Handle<Object> object)325 bool IsErrorObject(Isolate* isolate, Handle<Object> object) {
326 if (!object->IsJSReceiver()) return false;
327 Handle<Symbol> symbol = isolate->factory()->stack_trace_symbol();
328 return JSReceiver::HasOwnProperty(Handle<JSReceiver>::cast(object), symbol)
329 .FromMaybe(false);
330 }
331
AsStringOrEmpty(Isolate * isolate,Handle<Object> object)332 Handle<String> AsStringOrEmpty(Isolate* isolate, Handle<Object> object) {
333 return object->IsString() ? Handle<String>::cast(object)
334 : isolate->factory()->empty_string();
335 }
336
NoSideEffectsErrorToString(Isolate * isolate,Handle<Object> input)337 Handle<String> NoSideEffectsErrorToString(Isolate* isolate,
338 Handle<Object> input) {
339 Handle<JSReceiver> receiver = Handle<JSReceiver>::cast(input);
340
341 Handle<Name> name_key = isolate->factory()->name_string();
342 Handle<Object> name = JSReceiver::GetDataProperty(receiver, name_key);
343 Handle<String> name_str = AsStringOrEmpty(isolate, name);
344
345 Handle<Name> msg_key = isolate->factory()->message_string();
346 Handle<Object> msg = JSReceiver::GetDataProperty(receiver, msg_key);
347 Handle<String> msg_str = AsStringOrEmpty(isolate, msg);
348
349 if (name_str->length() == 0) return msg_str;
350 if (msg_str->length() == 0) return name_str;
351
352 IncrementalStringBuilder builder(isolate);
353 builder.AppendString(name_str);
354 builder.AppendCString(": ");
355 builder.AppendString(msg_str);
356
357 return builder.Finish().ToHandleChecked();
358 }
359
360 } // namespace
361
362 // static
NoSideEffectsToString(Isolate * isolate,Handle<Object> input)363 Handle<String> Object::NoSideEffectsToString(Isolate* isolate,
364 Handle<Object> input) {
365 DisallowJavascriptExecution no_js(isolate);
366
367 if (input->IsString() || input->IsNumeric() || input->IsOddball()) {
368 return Object::ToString(isolate, input).ToHandleChecked();
369 } else if (input->IsFunction()) {
370 // -- F u n c t i o n
371 Handle<String> fun_str;
372 if (input->IsJSBoundFunction()) {
373 fun_str = JSBoundFunction::ToString(Handle<JSBoundFunction>::cast(input));
374 } else {
375 DCHECK(input->IsJSFunction());
376 fun_str = JSFunction::ToString(Handle<JSFunction>::cast(input));
377 }
378
379 if (fun_str->length() > 128) {
380 IncrementalStringBuilder builder(isolate);
381 builder.AppendString(isolate->factory()->NewSubString(fun_str, 0, 111));
382 builder.AppendCString("...<omitted>...");
383 builder.AppendString(isolate->factory()->NewSubString(
384 fun_str, fun_str->length() - 2, fun_str->length()));
385
386 return builder.Finish().ToHandleChecked();
387 }
388 return fun_str;
389 } else if (input->IsSymbol()) {
390 // -- S y m b o l
391 Handle<Symbol> symbol = Handle<Symbol>::cast(input);
392
393 IncrementalStringBuilder builder(isolate);
394 builder.AppendCString("Symbol(");
395 if (symbol->name()->IsString()) {
396 builder.AppendString(handle(String::cast(symbol->name()), isolate));
397 }
398 builder.AppendCharacter(')');
399
400 return builder.Finish().ToHandleChecked();
401 } else if (input->IsJSReceiver()) {
402 // -- J S R e c e i v e r
403 Handle<JSReceiver> receiver = Handle<JSReceiver>::cast(input);
404 Handle<Object> to_string = JSReceiver::GetDataProperty(
405 receiver, isolate->factory()->toString_string());
406
407 if (IsErrorObject(isolate, input) ||
408 *to_string == *isolate->error_to_string()) {
409 // When internally formatting error objects, use a side-effects-free
410 // version of Error.prototype.toString independent of the actually
411 // installed toString method.
412 return NoSideEffectsErrorToString(isolate, input);
413 } else if (*to_string == *isolate->object_to_string()) {
414 Handle<Object> ctor = JSReceiver::GetDataProperty(
415 receiver, isolate->factory()->constructor_string());
416 if (ctor->IsFunction()) {
417 Handle<String> ctor_name;
418 if (ctor->IsJSBoundFunction()) {
419 ctor_name = JSBoundFunction::GetName(
420 isolate, Handle<JSBoundFunction>::cast(ctor))
421 .ToHandleChecked();
422 } else if (ctor->IsJSFunction()) {
423 Handle<Object> ctor_name_obj =
424 JSFunction::GetName(isolate, Handle<JSFunction>::cast(ctor));
425 ctor_name = AsStringOrEmpty(isolate, ctor_name_obj);
426 }
427
428 if (ctor_name->length() != 0) {
429 IncrementalStringBuilder builder(isolate);
430 builder.AppendCString("#<");
431 builder.AppendString(ctor_name);
432 builder.AppendCString(">");
433
434 return builder.Finish().ToHandleChecked();
435 }
436 }
437 }
438 }
439
440 // At this point, input is either none of the above or a JSReceiver.
441
442 Handle<JSReceiver> receiver;
443 if (input->IsJSReceiver()) {
444 receiver = Handle<JSReceiver>::cast(input);
445 } else {
446 // This is the only case where Object::ToObject throws.
447 DCHECK(!input->IsSmi());
448 int constructor_function_index =
449 Handle<HeapObject>::cast(input)->map()->GetConstructorFunctionIndex();
450 if (constructor_function_index == Map::kNoConstructorFunctionIndex) {
451 return isolate->factory()->NewStringFromAsciiChecked("[object Unknown]");
452 }
453
454 receiver = Object::ToObject(isolate, input, isolate->native_context())
455 .ToHandleChecked();
456 }
457
458 Handle<String> builtin_tag = handle(receiver->class_name(), isolate);
459 Handle<Object> tag_obj = JSReceiver::GetDataProperty(
460 receiver, isolate->factory()->to_string_tag_symbol());
461 Handle<String> tag =
462 tag_obj->IsString() ? Handle<String>::cast(tag_obj) : builtin_tag;
463
464 IncrementalStringBuilder builder(isolate);
465 builder.AppendCString("[object ");
466 builder.AppendString(tag);
467 builder.AppendCString("]");
468
469 return builder.Finish().ToHandleChecked();
470 }
471
472 // static
ConvertToLength(Isolate * isolate,Handle<Object> input)473 MaybeHandle<Object> Object::ConvertToLength(Isolate* isolate,
474 Handle<Object> input) {
475 ASSIGN_RETURN_ON_EXCEPTION(isolate, input, ToNumber(isolate, input), Object);
476 if (input->IsSmi()) {
477 int value = std::max(Smi::ToInt(*input), 0);
478 return handle(Smi::FromInt(value), isolate);
479 }
480 double len = DoubleToInteger(input->Number());
481 if (len <= 0.0) {
482 return handle(Smi::kZero, isolate);
483 } else if (len >= kMaxSafeInteger) {
484 len = kMaxSafeInteger;
485 }
486 return isolate->factory()->NewNumber(len);
487 }
488
489 // static
ConvertToIndex(Isolate * isolate,Handle<Object> input,MessageTemplate::Template error_index)490 MaybeHandle<Object> Object::ConvertToIndex(
491 Isolate* isolate, Handle<Object> input,
492 MessageTemplate::Template error_index) {
493 if (input->IsUndefined(isolate)) return handle(Smi::kZero, isolate);
494 ASSIGN_RETURN_ON_EXCEPTION(isolate, input, ToNumber(isolate, input), Object);
495 if (input->IsSmi() && Smi::ToInt(*input) >= 0) return input;
496 double len = DoubleToInteger(input->Number()) + 0.0;
497 auto js_len = isolate->factory()->NewNumber(len);
498 if (len < 0.0 || len > kMaxSafeInteger) {
499 THROW_NEW_ERROR(isolate, NewRangeError(error_index, js_len), Object);
500 }
501 return js_len;
502 }
503
BooleanValue(Isolate * isolate)504 bool Object::BooleanValue(Isolate* isolate) {
505 if (IsSmi()) return Smi::ToInt(this) != 0;
506 DCHECK(IsHeapObject());
507 if (IsBoolean()) return IsTrue(isolate);
508 if (IsNullOrUndefined(isolate)) return false;
509 if (IsUndetectable()) return false; // Undetectable object is false.
510 if (IsString()) return String::cast(this)->length() != 0;
511 if (IsHeapNumber()) return DoubleToBoolean(HeapNumber::cast(this)->value());
512 if (IsBigInt()) return BigInt::cast(this)->ToBoolean();
513 return true;
514 }
515
516
517 namespace {
518
519 // TODO(bmeurer): Maybe we should introduce a marker interface Number,
520 // where we put all these methods at some point?
NumberCompare(double x,double y)521 ComparisonResult NumberCompare(double x, double y) {
522 if (std::isnan(x) || std::isnan(y)) {
523 return ComparisonResult::kUndefined;
524 } else if (x < y) {
525 return ComparisonResult::kLessThan;
526 } else if (x > y) {
527 return ComparisonResult::kGreaterThan;
528 } else {
529 return ComparisonResult::kEqual;
530 }
531 }
532
NumberEquals(double x,double y)533 bool NumberEquals(double x, double y) {
534 // Must check explicitly for NaN's on Windows, but -0 works fine.
535 if (std::isnan(x)) return false;
536 if (std::isnan(y)) return false;
537 return x == y;
538 }
539
NumberEquals(const Object * x,const Object * y)540 bool NumberEquals(const Object* x, const Object* y) {
541 return NumberEquals(x->Number(), y->Number());
542 }
543
NumberEquals(Handle<Object> x,Handle<Object> y)544 bool NumberEquals(Handle<Object> x, Handle<Object> y) {
545 return NumberEquals(*x, *y);
546 }
547
Reverse(ComparisonResult result)548 ComparisonResult Reverse(ComparisonResult result) {
549 if (result == ComparisonResult::kLessThan) {
550 return ComparisonResult::kGreaterThan;
551 }
552 if (result == ComparisonResult::kGreaterThan) {
553 return ComparisonResult::kLessThan;
554 }
555 return result;
556 }
557
558 } // anonymous namespace
559
560 // static
Compare(Isolate * isolate,Handle<Object> x,Handle<Object> y)561 Maybe<ComparisonResult> Object::Compare(Isolate* isolate, Handle<Object> x,
562 Handle<Object> y) {
563 // ES6 section 7.2.11 Abstract Relational Comparison step 3 and 4.
564 if (!Object::ToPrimitive(x, ToPrimitiveHint::kNumber).ToHandle(&x) ||
565 !Object::ToPrimitive(y, ToPrimitiveHint::kNumber).ToHandle(&y)) {
566 return Nothing<ComparisonResult>();
567 }
568 if (x->IsString() && y->IsString()) {
569 // ES6 section 7.2.11 Abstract Relational Comparison step 5.
570 return Just(String::Compare(isolate, Handle<String>::cast(x),
571 Handle<String>::cast(y)));
572 }
573 if (x->IsBigInt() && y->IsString()) {
574 return Just(BigInt::CompareToString(isolate, Handle<BigInt>::cast(x),
575 Handle<String>::cast(y)));
576 }
577 if (x->IsString() && y->IsBigInt()) {
578 return Just(Reverse(BigInt::CompareToString(
579 isolate, Handle<BigInt>::cast(y), Handle<String>::cast(x))));
580 }
581 // ES6 section 7.2.11 Abstract Relational Comparison step 6.
582 if (!Object::ToNumeric(isolate, x).ToHandle(&x) ||
583 !Object::ToNumeric(isolate, y).ToHandle(&y)) {
584 return Nothing<ComparisonResult>();
585 }
586
587 bool x_is_number = x->IsNumber();
588 bool y_is_number = y->IsNumber();
589 if (x_is_number && y_is_number) {
590 return Just(NumberCompare(x->Number(), y->Number()));
591 } else if (!x_is_number && !y_is_number) {
592 return Just(BigInt::CompareToBigInt(Handle<BigInt>::cast(x),
593 Handle<BigInt>::cast(y)));
594 } else if (x_is_number) {
595 return Just(Reverse(BigInt::CompareToNumber(Handle<BigInt>::cast(y), x)));
596 } else {
597 return Just(BigInt::CompareToNumber(Handle<BigInt>::cast(x), y));
598 }
599 }
600
601
602 // static
Equals(Isolate * isolate,Handle<Object> x,Handle<Object> y)603 Maybe<bool> Object::Equals(Isolate* isolate, Handle<Object> x,
604 Handle<Object> y) {
605 // This is the generic version of Abstract Equality Comparison. Must be in
606 // sync with CodeStubAssembler::Equal.
607 while (true) {
608 if (x->IsNumber()) {
609 if (y->IsNumber()) {
610 return Just(NumberEquals(x, y));
611 } else if (y->IsBoolean()) {
612 return Just(NumberEquals(*x, Handle<Oddball>::cast(y)->to_number()));
613 } else if (y->IsString()) {
614 return Just(NumberEquals(
615 x, String::ToNumber(isolate, Handle<String>::cast(y))));
616 } else if (y->IsBigInt()) {
617 return Just(BigInt::EqualToNumber(Handle<BigInt>::cast(y), x));
618 } else if (y->IsJSReceiver()) {
619 if (!JSReceiver::ToPrimitive(Handle<JSReceiver>::cast(y))
620 .ToHandle(&y)) {
621 return Nothing<bool>();
622 }
623 } else {
624 return Just(false);
625 }
626 } else if (x->IsString()) {
627 if (y->IsString()) {
628 return Just(String::Equals(isolate, Handle<String>::cast(x),
629 Handle<String>::cast(y)));
630 } else if (y->IsNumber()) {
631 x = String::ToNumber(isolate, Handle<String>::cast(x));
632 return Just(NumberEquals(x, y));
633 } else if (y->IsBoolean()) {
634 x = String::ToNumber(isolate, Handle<String>::cast(x));
635 return Just(NumberEquals(*x, Handle<Oddball>::cast(y)->to_number()));
636 } else if (y->IsBigInt()) {
637 return Just(BigInt::EqualToString(isolate, Handle<BigInt>::cast(y),
638 Handle<String>::cast(x)));
639 } else if (y->IsJSReceiver()) {
640 if (!JSReceiver::ToPrimitive(Handle<JSReceiver>::cast(y))
641 .ToHandle(&y)) {
642 return Nothing<bool>();
643 }
644 } else {
645 return Just(false);
646 }
647 } else if (x->IsBoolean()) {
648 if (y->IsOddball()) {
649 return Just(x.is_identical_to(y));
650 } else if (y->IsNumber()) {
651 return Just(NumberEquals(Handle<Oddball>::cast(x)->to_number(), *y));
652 } else if (y->IsString()) {
653 y = String::ToNumber(isolate, Handle<String>::cast(y));
654 return Just(NumberEquals(Handle<Oddball>::cast(x)->to_number(), *y));
655 } else if (y->IsBigInt()) {
656 x = Oddball::ToNumber(isolate, Handle<Oddball>::cast(x));
657 return Just(BigInt::EqualToNumber(Handle<BigInt>::cast(y), x));
658 } else if (y->IsJSReceiver()) {
659 if (!JSReceiver::ToPrimitive(Handle<JSReceiver>::cast(y))
660 .ToHandle(&y)) {
661 return Nothing<bool>();
662 }
663 x = Oddball::ToNumber(isolate, Handle<Oddball>::cast(x));
664 } else {
665 return Just(false);
666 }
667 } else if (x->IsSymbol()) {
668 if (y->IsSymbol()) {
669 return Just(x.is_identical_to(y));
670 } else if (y->IsJSReceiver()) {
671 if (!JSReceiver::ToPrimitive(Handle<JSReceiver>::cast(y))
672 .ToHandle(&y)) {
673 return Nothing<bool>();
674 }
675 } else {
676 return Just(false);
677 }
678 } else if (x->IsBigInt()) {
679 if (y->IsBigInt()) {
680 return Just(BigInt::EqualToBigInt(BigInt::cast(*x), BigInt::cast(*y)));
681 }
682 return Equals(isolate, y, x);
683 } else if (x->IsJSReceiver()) {
684 if (y->IsJSReceiver()) {
685 return Just(x.is_identical_to(y));
686 } else if (y->IsUndetectable()) {
687 return Just(x->IsUndetectable());
688 } else if (y->IsBoolean()) {
689 y = Oddball::ToNumber(isolate, Handle<Oddball>::cast(y));
690 } else if (!JSReceiver::ToPrimitive(Handle<JSReceiver>::cast(x))
691 .ToHandle(&x)) {
692 return Nothing<bool>();
693 }
694 } else {
695 return Just(x->IsUndetectable() && y->IsUndetectable());
696 }
697 }
698 }
699
700
StrictEquals(Object * that)701 bool Object::StrictEquals(Object* that) {
702 if (this->IsNumber()) {
703 if (!that->IsNumber()) return false;
704 return NumberEquals(this, that);
705 } else if (this->IsString()) {
706 if (!that->IsString()) return false;
707 return String::cast(this)->Equals(String::cast(that));
708 } else if (this->IsBigInt()) {
709 if (!that->IsBigInt()) return false;
710 return BigInt::EqualToBigInt(BigInt::cast(this), BigInt::cast(that));
711 }
712 return this == that;
713 }
714
715
716 // static
TypeOf(Isolate * isolate,Handle<Object> object)717 Handle<String> Object::TypeOf(Isolate* isolate, Handle<Object> object) {
718 if (object->IsNumber()) return isolate->factory()->number_string();
719 if (object->IsOddball())
720 return handle(Oddball::cast(*object)->type_of(), isolate);
721 if (object->IsUndetectable()) {
722 return isolate->factory()->undefined_string();
723 }
724 if (object->IsString()) return isolate->factory()->string_string();
725 if (object->IsSymbol()) return isolate->factory()->symbol_string();
726 if (object->IsBigInt()) return isolate->factory()->bigint_string();
727 if (object->IsCallable()) return isolate->factory()->function_string();
728 return isolate->factory()->object_string();
729 }
730
731
732 // static
Add(Isolate * isolate,Handle<Object> lhs,Handle<Object> rhs)733 MaybeHandle<Object> Object::Add(Isolate* isolate, Handle<Object> lhs,
734 Handle<Object> rhs) {
735 if (lhs->IsNumber() && rhs->IsNumber()) {
736 return isolate->factory()->NewNumber(lhs->Number() + rhs->Number());
737 } else if (lhs->IsString() && rhs->IsString()) {
738 return isolate->factory()->NewConsString(Handle<String>::cast(lhs),
739 Handle<String>::cast(rhs));
740 }
741 ASSIGN_RETURN_ON_EXCEPTION(isolate, lhs, Object::ToPrimitive(lhs), Object);
742 ASSIGN_RETURN_ON_EXCEPTION(isolate, rhs, Object::ToPrimitive(rhs), Object);
743 if (lhs->IsString() || rhs->IsString()) {
744 ASSIGN_RETURN_ON_EXCEPTION(isolate, rhs, Object::ToString(isolate, rhs),
745 Object);
746 ASSIGN_RETURN_ON_EXCEPTION(isolate, lhs, Object::ToString(isolate, lhs),
747 Object);
748 return isolate->factory()->NewConsString(Handle<String>::cast(lhs),
749 Handle<String>::cast(rhs));
750 }
751 ASSIGN_RETURN_ON_EXCEPTION(isolate, rhs, Object::ToNumber(isolate, rhs),
752 Object);
753 ASSIGN_RETURN_ON_EXCEPTION(isolate, lhs, Object::ToNumber(isolate, lhs),
754 Object);
755 return isolate->factory()->NewNumber(lhs->Number() + rhs->Number());
756 }
757
758
759 // static
OrdinaryHasInstance(Isolate * isolate,Handle<Object> callable,Handle<Object> object)760 MaybeHandle<Object> Object::OrdinaryHasInstance(Isolate* isolate,
761 Handle<Object> callable,
762 Handle<Object> object) {
763 // The {callable} must have a [[Call]] internal method.
764 if (!callable->IsCallable()) return isolate->factory()->false_value();
765
766 // Check if {callable} is a bound function, and if so retrieve its
767 // [[BoundTargetFunction]] and use that instead of {callable}.
768 if (callable->IsJSBoundFunction()) {
769 Handle<Object> bound_callable(
770 Handle<JSBoundFunction>::cast(callable)->bound_target_function(),
771 isolate);
772 return Object::InstanceOf(isolate, object, bound_callable);
773 }
774
775 // If {object} is not a receiver, return false.
776 if (!object->IsJSReceiver()) return isolate->factory()->false_value();
777
778 // Get the "prototype" of {callable}; raise an error if it's not a receiver.
779 Handle<Object> prototype;
780 ASSIGN_RETURN_ON_EXCEPTION(
781 isolate, prototype,
782 Object::GetProperty(isolate, callable,
783 isolate->factory()->prototype_string()),
784 Object);
785 if (!prototype->IsJSReceiver()) {
786 THROW_NEW_ERROR(
787 isolate,
788 NewTypeError(MessageTemplate::kInstanceofNonobjectProto, prototype),
789 Object);
790 }
791
792 // Return whether or not {prototype} is in the prototype chain of {object}.
793 Maybe<bool> result = JSReceiver::HasInPrototypeChain(
794 isolate, Handle<JSReceiver>::cast(object), prototype);
795 if (result.IsNothing()) return MaybeHandle<Object>();
796 return isolate->factory()->ToBoolean(result.FromJust());
797 }
798
799 // static
InstanceOf(Isolate * isolate,Handle<Object> object,Handle<Object> callable)800 MaybeHandle<Object> Object::InstanceOf(Isolate* isolate, Handle<Object> object,
801 Handle<Object> callable) {
802 // The {callable} must be a receiver.
803 if (!callable->IsJSReceiver()) {
804 THROW_NEW_ERROR(isolate,
805 NewTypeError(MessageTemplate::kNonObjectInInstanceOfCheck),
806 Object);
807 }
808
809 // Lookup the @@hasInstance method on {callable}.
810 Handle<Object> inst_of_handler;
811 ASSIGN_RETURN_ON_EXCEPTION(
812 isolate, inst_of_handler,
813 JSReceiver::GetMethod(Handle<JSReceiver>::cast(callable),
814 isolate->factory()->has_instance_symbol()),
815 Object);
816 if (!inst_of_handler->IsUndefined(isolate)) {
817 // Call the {inst_of_handler} on the {callable}.
818 Handle<Object> result;
819 ASSIGN_RETURN_ON_EXCEPTION(
820 isolate, result,
821 Execution::Call(isolate, inst_of_handler, callable, 1, &object),
822 Object);
823 return isolate->factory()->ToBoolean(result->BooleanValue(isolate));
824 }
825
826 // The {callable} must have a [[Call]] internal method.
827 if (!callable->IsCallable()) {
828 THROW_NEW_ERROR(
829 isolate, NewTypeError(MessageTemplate::kNonCallableInInstanceOfCheck),
830 Object);
831 }
832
833 // Fall back to OrdinaryHasInstance with {callable} and {object}.
834 Handle<Object> result;
835 ASSIGN_RETURN_ON_EXCEPTION(
836 isolate, result,
837 JSReceiver::OrdinaryHasInstance(isolate, callable, object), Object);
838 return result;
839 }
840
841 // static
GetMethod(Handle<JSReceiver> receiver,Handle<Name> name)842 MaybeHandle<Object> Object::GetMethod(Handle<JSReceiver> receiver,
843 Handle<Name> name) {
844 Handle<Object> func;
845 Isolate* isolate = receiver->GetIsolate();
846 ASSIGN_RETURN_ON_EXCEPTION(
847 isolate, func, JSReceiver::GetProperty(isolate, receiver, name), Object);
848 if (func->IsNullOrUndefined(isolate)) {
849 return isolate->factory()->undefined_value();
850 }
851 if (!func->IsCallable()) {
852 THROW_NEW_ERROR(isolate, NewTypeError(MessageTemplate::kPropertyNotFunction,
853 func, name, receiver),
854 Object);
855 }
856 return func;
857 }
858
859 namespace {
860
CreateListFromArrayLikeFastPath(Isolate * isolate,Handle<Object> object,ElementTypes element_types)861 MaybeHandle<FixedArray> CreateListFromArrayLikeFastPath(
862 Isolate* isolate, Handle<Object> object, ElementTypes element_types) {
863 if (element_types == ElementTypes::kAll) {
864 if (object->IsJSArray()) {
865 Handle<JSArray> array = Handle<JSArray>::cast(object);
866 uint32_t length;
867 if (!array->HasArrayPrototype(isolate) ||
868 !array->length()->ToUint32(&length) || !array->HasFastElements() ||
869 !JSObject::PrototypeHasNoElements(isolate, *array)) {
870 return MaybeHandle<FixedArray>();
871 }
872 return array->GetElementsAccessor()->CreateListFromArrayLike(
873 isolate, array, length);
874 } else if (object->IsJSTypedArray()) {
875 Handle<JSTypedArray> array = Handle<JSTypedArray>::cast(object);
876 size_t length = array->length_value();
877 if (array->WasNeutered() ||
878 length > static_cast<size_t>(FixedArray::kMaxLength)) {
879 return MaybeHandle<FixedArray>();
880 }
881 return array->GetElementsAccessor()->CreateListFromArrayLike(
882 isolate, array, static_cast<uint32_t>(length));
883 }
884 }
885 return MaybeHandle<FixedArray>();
886 }
887
888 } // namespace
889
890 // static
CreateListFromArrayLike(Isolate * isolate,Handle<Object> object,ElementTypes element_types)891 MaybeHandle<FixedArray> Object::CreateListFromArrayLike(
892 Isolate* isolate, Handle<Object> object, ElementTypes element_types) {
893 // Fast-path for JSArray and JSTypedArray.
894 MaybeHandle<FixedArray> fast_result =
895 CreateListFromArrayLikeFastPath(isolate, object, element_types);
896 if (!fast_result.is_null()) return fast_result;
897 // 1. ReturnIfAbrupt(object).
898 // 2. (default elementTypes -- not applicable.)
899 // 3. If Type(obj) is not Object, throw a TypeError exception.
900 if (!object->IsJSReceiver()) {
901 THROW_NEW_ERROR(isolate,
902 NewTypeError(MessageTemplate::kCalledOnNonObject,
903 isolate->factory()->NewStringFromAsciiChecked(
904 "CreateListFromArrayLike")),
905 FixedArray);
906 }
907
908 // 4. Let len be ? ToLength(? Get(obj, "length")).
909 Handle<JSReceiver> receiver = Handle<JSReceiver>::cast(object);
910 Handle<Object> raw_length_number;
911 ASSIGN_RETURN_ON_EXCEPTION(isolate, raw_length_number,
912 Object::GetLengthFromArrayLike(isolate, receiver),
913 FixedArray);
914 uint32_t len;
915 if (!raw_length_number->ToUint32(&len) ||
916 len > static_cast<uint32_t>(FixedArray::kMaxLength)) {
917 THROW_NEW_ERROR(isolate,
918 NewRangeError(MessageTemplate::kInvalidArrayLength),
919 FixedArray);
920 }
921 // 5. Let list be an empty List.
922 Handle<FixedArray> list = isolate->factory()->NewFixedArray(len);
923 // 6. Let index be 0.
924 // 7. Repeat while index < len:
925 for (uint32_t index = 0; index < len; ++index) {
926 // 7a. Let indexName be ToString(index).
927 // 7b. Let next be ? Get(obj, indexName).
928 Handle<Object> next;
929 ASSIGN_RETURN_ON_EXCEPTION(isolate, next,
930 JSReceiver::GetElement(isolate, receiver, index),
931 FixedArray);
932 switch (element_types) {
933 case ElementTypes::kAll:
934 // Nothing to do.
935 break;
936 case ElementTypes::kStringAndSymbol: {
937 // 7c. If Type(next) is not an element of elementTypes, throw a
938 // TypeError exception.
939 if (!next->IsName()) {
940 THROW_NEW_ERROR(isolate,
941 NewTypeError(MessageTemplate::kNotPropertyName, next),
942 FixedArray);
943 }
944 // 7d. Append next as the last element of list.
945 // Internalize on the fly so we can use pointer identity later.
946 next = isolate->factory()->InternalizeName(Handle<Name>::cast(next));
947 break;
948 }
949 }
950 list->set(index, *next);
951 // 7e. Set index to index + 1. (See loop header.)
952 }
953 // 8. Return list.
954 return list;
955 }
956
957
958 // static
GetLengthFromArrayLike(Isolate * isolate,Handle<JSReceiver> object)959 MaybeHandle<Object> Object::GetLengthFromArrayLike(Isolate* isolate,
960 Handle<JSReceiver> object) {
961 Handle<Object> val;
962 Handle<Name> key = isolate->factory()->length_string();
963 ASSIGN_RETURN_ON_EXCEPTION(
964 isolate, val, JSReceiver::GetProperty(isolate, object, key), Object);
965 return Object::ToLength(isolate, val);
966 }
967
968 // static
HasProperty(LookupIterator * it)969 Maybe<bool> JSReceiver::HasProperty(LookupIterator* it) {
970 for (; it->IsFound(); it->Next()) {
971 switch (it->state()) {
972 case LookupIterator::NOT_FOUND:
973 case LookupIterator::TRANSITION:
974 UNREACHABLE();
975 case LookupIterator::JSPROXY:
976 return JSProxy::HasProperty(it->isolate(), it->GetHolder<JSProxy>(),
977 it->GetName());
978 case LookupIterator::INTERCEPTOR: {
979 Maybe<PropertyAttributes> result =
980 JSObject::GetPropertyAttributesWithInterceptor(it);
981 if (result.IsNothing()) return Nothing<bool>();
982 if (result.FromJust() != ABSENT) return Just(true);
983 break;
984 }
985 case LookupIterator::ACCESS_CHECK: {
986 if (it->HasAccess()) break;
987 Maybe<PropertyAttributes> result =
988 JSObject::GetPropertyAttributesWithFailedAccessCheck(it);
989 if (result.IsNothing()) return Nothing<bool>();
990 return Just(result.FromJust() != ABSENT);
991 }
992 case LookupIterator::INTEGER_INDEXED_EXOTIC:
993 // TypedArray out-of-bounds access.
994 return Just(false);
995 case LookupIterator::ACCESSOR:
996 case LookupIterator::DATA:
997 return Just(true);
998 }
999 }
1000 return Just(false);
1001 }
1002
1003 // static
HasOwnProperty(Handle<JSReceiver> object,Handle<Name> name)1004 Maybe<bool> JSReceiver::HasOwnProperty(Handle<JSReceiver> object,
1005 Handle<Name> name) {
1006 if (object->IsJSModuleNamespace()) {
1007 PropertyDescriptor desc;
1008 return JSReceiver::GetOwnPropertyDescriptor(object->GetIsolate(), object,
1009 name, &desc);
1010 }
1011
1012 if (object->IsJSObject()) { // Shortcut.
1013 LookupIterator it = LookupIterator::PropertyOrElement(
1014 object->GetIsolate(), object, name, object, LookupIterator::OWN);
1015 return HasProperty(&it);
1016 }
1017
1018 Maybe<PropertyAttributes> attributes =
1019 JSReceiver::GetOwnPropertyAttributes(object, name);
1020 MAYBE_RETURN(attributes, Nothing<bool>());
1021 return Just(attributes.FromJust() != ABSENT);
1022 }
1023
1024 // static
GetProperty(LookupIterator * it,OnNonExistent on_non_existent)1025 MaybeHandle<Object> Object::GetProperty(LookupIterator* it,
1026 OnNonExistent on_non_existent) {
1027 for (; it->IsFound(); it->Next()) {
1028 switch (it->state()) {
1029 case LookupIterator::NOT_FOUND:
1030 case LookupIterator::TRANSITION:
1031 UNREACHABLE();
1032 case LookupIterator::JSPROXY: {
1033 bool was_found;
1034 MaybeHandle<Object> result =
1035 JSProxy::GetProperty(it->isolate(), it->GetHolder<JSProxy>(),
1036 it->GetName(), it->GetReceiver(), &was_found);
1037 if (!was_found) it->NotFound();
1038 return result;
1039 }
1040 case LookupIterator::INTERCEPTOR: {
1041 bool done;
1042 Handle<Object> result;
1043 ASSIGN_RETURN_ON_EXCEPTION(
1044 it->isolate(), result,
1045 JSObject::GetPropertyWithInterceptor(it, &done), Object);
1046 if (done) return result;
1047 break;
1048 }
1049 case LookupIterator::ACCESS_CHECK:
1050 if (it->HasAccess()) break;
1051 return JSObject::GetPropertyWithFailedAccessCheck(it);
1052 case LookupIterator::ACCESSOR:
1053 return GetPropertyWithAccessor(it);
1054 case LookupIterator::INTEGER_INDEXED_EXOTIC:
1055 return it->isolate()->factory()->undefined_value();
1056 case LookupIterator::DATA:
1057 return it->GetDataValue();
1058 }
1059 }
1060
1061 if (on_non_existent == OnNonExistent::kThrowReferenceError) {
1062 THROW_NEW_ERROR(it->isolate(),
1063 NewReferenceError(MessageTemplate::kNotDefined, it->name()),
1064 Object);
1065 }
1066 return it->isolate()->factory()->undefined_value();
1067 }
1068
1069
1070 // static
GetProperty(Isolate * isolate,Handle<JSProxy> proxy,Handle<Name> name,Handle<Object> receiver,bool * was_found)1071 MaybeHandle<Object> JSProxy::GetProperty(Isolate* isolate,
1072 Handle<JSProxy> proxy,
1073 Handle<Name> name,
1074 Handle<Object> receiver,
1075 bool* was_found) {
1076 *was_found = true;
1077
1078 DCHECK(!name->IsPrivate());
1079 STACK_CHECK(isolate, MaybeHandle<Object>());
1080 Handle<Name> trap_name = isolate->factory()->get_string();
1081 // 1. Assert: IsPropertyKey(P) is true.
1082 // 2. Let handler be the value of the [[ProxyHandler]] internal slot of O.
1083 Handle<Object> handler(proxy->handler(), isolate);
1084 // 3. If handler is null, throw a TypeError exception.
1085 // 4. Assert: Type(handler) is Object.
1086 if (proxy->IsRevoked()) {
1087 THROW_NEW_ERROR(isolate,
1088 NewTypeError(MessageTemplate::kProxyRevoked, trap_name),
1089 Object);
1090 }
1091 // 5. Let target be the value of the [[ProxyTarget]] internal slot of O.
1092 Handle<JSReceiver> target(JSReceiver::cast(proxy->target()), isolate);
1093 // 6. Let trap be ? GetMethod(handler, "get").
1094 Handle<Object> trap;
1095 ASSIGN_RETURN_ON_EXCEPTION(
1096 isolate, trap,
1097 Object::GetMethod(Handle<JSReceiver>::cast(handler), trap_name), Object);
1098 // 7. If trap is undefined, then
1099 if (trap->IsUndefined(isolate)) {
1100 // 7.a Return target.[[Get]](P, Receiver).
1101 LookupIterator it =
1102 LookupIterator::PropertyOrElement(isolate, receiver, name, target);
1103 MaybeHandle<Object> result = Object::GetProperty(&it);
1104 *was_found = it.IsFound();
1105 return result;
1106 }
1107 // 8. Let trapResult be ? Call(trap, handler, «target, P, Receiver»).
1108 Handle<Object> trap_result;
1109 Handle<Object> args[] = {target, name, receiver};
1110 ASSIGN_RETURN_ON_EXCEPTION(
1111 isolate, trap_result,
1112 Execution::Call(isolate, trap, handler, arraysize(args), args), Object);
1113
1114 MaybeHandle<Object> result =
1115 JSProxy::CheckGetSetTrapResult(isolate, name, target, trap_result, kGet);
1116 if (result.is_null()) {
1117 return result;
1118 }
1119
1120 // 11. Return trap_result
1121 return trap_result;
1122 }
1123
1124 // static
CheckGetSetTrapResult(Isolate * isolate,Handle<Name> name,Handle<JSReceiver> target,Handle<Object> trap_result,AccessKind access_kind)1125 MaybeHandle<Object> JSProxy::CheckGetSetTrapResult(Isolate* isolate,
1126 Handle<Name> name,
1127 Handle<JSReceiver> target,
1128 Handle<Object> trap_result,
1129 AccessKind access_kind) {
1130 // 9. Let targetDesc be ? target.[[GetOwnProperty]](P).
1131 PropertyDescriptor target_desc;
1132 Maybe<bool> target_found =
1133 JSReceiver::GetOwnPropertyDescriptor(isolate, target, name, &target_desc);
1134 MAYBE_RETURN_NULL(target_found);
1135 // 10. If targetDesc is not undefined, then
1136 if (target_found.FromJust()) {
1137 // 10.a. If IsDataDescriptor(targetDesc) and targetDesc.[[Configurable]] is
1138 // false and targetDesc.[[Writable]] is false, then
1139 // 10.a.i. If SameValue(trapResult, targetDesc.[[Value]]) is false,
1140 // throw a TypeError exception.
1141 bool inconsistent = PropertyDescriptor::IsDataDescriptor(&target_desc) &&
1142 !target_desc.configurable() &&
1143 !target_desc.writable() &&
1144 !trap_result->SameValue(*target_desc.value());
1145 if (inconsistent) {
1146 if (access_kind == kGet) {
1147 THROW_NEW_ERROR(
1148 isolate,
1149 NewTypeError(MessageTemplate::kProxyGetNonConfigurableData, name,
1150 target_desc.value(), trap_result),
1151 Object);
1152 } else {
1153 isolate->Throw(*isolate->factory()->NewTypeError(
1154 MessageTemplate::kProxySetFrozenData, name));
1155 return MaybeHandle<Object>();
1156 }
1157 }
1158 // 10.b. If IsAccessorDescriptor(targetDesc) and targetDesc.[[Configurable]]
1159 // is false and targetDesc.[[Get]] is undefined, then
1160 // 10.b.i. If trapResult is not undefined, throw a TypeError exception.
1161 if (access_kind == kGet) {
1162 inconsistent = PropertyDescriptor::IsAccessorDescriptor(&target_desc) &&
1163 !target_desc.configurable() &&
1164 target_desc.get()->IsUndefined(isolate) &&
1165 !trap_result->IsUndefined(isolate);
1166 } else {
1167 inconsistent = PropertyDescriptor::IsAccessorDescriptor(&target_desc) &&
1168 !target_desc.configurable() &&
1169 target_desc.set()->IsUndefined(isolate);
1170 }
1171 if (inconsistent) {
1172 if (access_kind == kGet) {
1173 THROW_NEW_ERROR(
1174 isolate,
1175 NewTypeError(MessageTemplate::kProxyGetNonConfigurableAccessor,
1176 name, trap_result),
1177 Object);
1178 } else {
1179 isolate->Throw(*isolate->factory()->NewTypeError(
1180 MessageTemplate::kProxySetFrozenAccessor, name));
1181 return MaybeHandle<Object>();
1182 }
1183 }
1184 }
1185 return isolate->factory()->undefined_value();
1186 }
1187
1188
GetDataProperty(LookupIterator * it)1189 Handle<Object> JSReceiver::GetDataProperty(LookupIterator* it) {
1190 for (; it->IsFound(); it->Next()) {
1191 switch (it->state()) {
1192 case LookupIterator::INTERCEPTOR:
1193 case LookupIterator::NOT_FOUND:
1194 case LookupIterator::TRANSITION:
1195 UNREACHABLE();
1196 case LookupIterator::ACCESS_CHECK:
1197 // Support calling this method without an active context, but refuse
1198 // access to access-checked objects in that case.
1199 if (it->isolate()->context() != nullptr && it->HasAccess()) continue;
1200 V8_FALLTHROUGH;
1201 case LookupIterator::JSPROXY:
1202 it->NotFound();
1203 return it->isolate()->factory()->undefined_value();
1204 case LookupIterator::ACCESSOR:
1205 // TODO(verwaest): For now this doesn't call into AccessorInfo, since
1206 // clients don't need it. Update once relevant.
1207 it->NotFound();
1208 return it->isolate()->factory()->undefined_value();
1209 case LookupIterator::INTEGER_INDEXED_EXOTIC:
1210 return it->isolate()->factory()->undefined_value();
1211 case LookupIterator::DATA:
1212 return it->GetDataValue();
1213 }
1214 }
1215 return it->isolate()->factory()->undefined_value();
1216 }
1217
1218
ToInt32(int32_t * value)1219 bool Object::ToInt32(int32_t* value) {
1220 if (IsSmi()) {
1221 *value = Smi::ToInt(this);
1222 return true;
1223 }
1224 if (IsHeapNumber()) {
1225 double num = HeapNumber::cast(this)->value();
1226 // Check range before conversion to avoid undefined behavior.
1227 if (num >= kMinInt && num <= kMaxInt && FastI2D(FastD2I(num)) == num) {
1228 *value = FastD2I(num);
1229 return true;
1230 }
1231 }
1232 return false;
1233 }
1234
GetOrCreateSharedFunctionInfo(Isolate * isolate,Handle<FunctionTemplateInfo> info,MaybeHandle<Name> maybe_name)1235 Handle<SharedFunctionInfo> FunctionTemplateInfo::GetOrCreateSharedFunctionInfo(
1236 Isolate* isolate, Handle<FunctionTemplateInfo> info,
1237 MaybeHandle<Name> maybe_name) {
1238 Object* current_info = info->shared_function_info();
1239 if (current_info->IsSharedFunctionInfo()) {
1240 return handle(SharedFunctionInfo::cast(current_info), isolate);
1241 }
1242 Handle<Name> name;
1243 Handle<String> name_string;
1244 if (maybe_name.ToHandle(&name) && name->IsString()) {
1245 name_string = Handle<String>::cast(name);
1246 } else if (info->class_name()->IsString()) {
1247 name_string = handle(String::cast(info->class_name()), isolate);
1248 } else {
1249 name_string = isolate->factory()->empty_string();
1250 }
1251 FunctionKind function_kind;
1252 if (info->remove_prototype()) {
1253 function_kind = kConciseMethod;
1254 } else {
1255 function_kind = kNormalFunction;
1256 }
1257 Handle<SharedFunctionInfo> result =
1258 isolate->factory()->NewSharedFunctionInfoForApiFunction(name_string, info,
1259 function_kind);
1260
1261 result->set_length(info->length());
1262 result->DontAdaptArguments();
1263 DCHECK(result->IsApiFunction());
1264
1265 info->set_shared_function_info(*result);
1266 return result;
1267 }
1268
IsTemplateFor(Map * map)1269 bool FunctionTemplateInfo::IsTemplateFor(Map* map) {
1270 // There is a constraint on the object; check.
1271 if (!map->IsJSObjectMap()) return false;
1272 // Fetch the constructor function of the object.
1273 Object* cons_obj = map->GetConstructor();
1274 Object* type;
1275 if (cons_obj->IsJSFunction()) {
1276 JSFunction* fun = JSFunction::cast(cons_obj);
1277 type = fun->shared()->function_data();
1278 } else if (cons_obj->IsFunctionTemplateInfo()) {
1279 type = FunctionTemplateInfo::cast(cons_obj);
1280 } else {
1281 return false;
1282 }
1283 // Iterate through the chain of inheriting function templates to
1284 // see if the required one occurs.
1285 while (type->IsFunctionTemplateInfo()) {
1286 if (type == this) return true;
1287 type = FunctionTemplateInfo::cast(type)->parent_template();
1288 }
1289 // Didn't find the required type in the inheritance chain.
1290 return false;
1291 }
1292
1293
1294 // static
New(Isolate * isolate,int size)1295 Handle<TemplateList> TemplateList::New(Isolate* isolate, int size) {
1296 Handle<FixedArray> list =
1297 isolate->factory()->NewFixedArray(kLengthIndex + size);
1298 list->set(kLengthIndex, Smi::kZero);
1299 return Handle<TemplateList>::cast(list);
1300 }
1301
1302 // static
Add(Isolate * isolate,Handle<TemplateList> list,Handle<i::Object> value)1303 Handle<TemplateList> TemplateList::Add(Isolate* isolate,
1304 Handle<TemplateList> list,
1305 Handle<i::Object> value) {
1306 STATIC_ASSERT(kFirstElementIndex == 1);
1307 int index = list->length() + 1;
1308 Handle<i::FixedArray> fixed_array = Handle<FixedArray>::cast(list);
1309 fixed_array = FixedArray::SetAndGrow(isolate, fixed_array, index, value);
1310 fixed_array->set(kLengthIndex, Smi::FromInt(index));
1311 return Handle<TemplateList>::cast(fixed_array);
1312 }
1313
1314 // static
New(Handle<JSFunction> constructor,Handle<JSReceiver> new_target,Handle<AllocationSite> site)1315 MaybeHandle<JSObject> JSObject::New(Handle<JSFunction> constructor,
1316 Handle<JSReceiver> new_target,
1317 Handle<AllocationSite> site) {
1318 // If called through new, new.target can be:
1319 // - a subclass of constructor,
1320 // - a proxy wrapper around constructor, or
1321 // - the constructor itself.
1322 // If called through Reflect.construct, it's guaranteed to be a constructor.
1323 Isolate* const isolate = constructor->GetIsolate();
1324 DCHECK(constructor->IsConstructor());
1325 DCHECK(new_target->IsConstructor());
1326 DCHECK(!constructor->has_initial_map() ||
1327 constructor->initial_map()->instance_type() != JS_FUNCTION_TYPE);
1328
1329 Handle<Map> initial_map;
1330 ASSIGN_RETURN_ON_EXCEPTION(
1331 isolate, initial_map,
1332 JSFunction::GetDerivedMap(isolate, constructor, new_target), JSObject);
1333 Handle<JSObject> result =
1334 isolate->factory()->NewJSObjectFromMap(initial_map, NOT_TENURED, site);
1335 if (initial_map->is_dictionary_map()) {
1336 Handle<NameDictionary> dictionary =
1337 NameDictionary::New(isolate, NameDictionary::kInitialCapacity);
1338 result->SetProperties(*dictionary);
1339 }
1340 isolate->counters()->constructed_objects()->Increment();
1341 isolate->counters()->constructed_objects_runtime()->Increment();
1342 return result;
1343 }
1344
1345 // 9.1.12 ObjectCreate ( proto [ , internalSlotsList ] )
1346 // Notice: This is NOT 19.1.2.2 Object.create ( O, Properties )
ObjectCreate(Isolate * isolate,Handle<Object> prototype)1347 MaybeHandle<JSObject> JSObject::ObjectCreate(Isolate* isolate,
1348 Handle<Object> prototype) {
1349 // Generate the map with the specified {prototype} based on the Object
1350 // function's initial map from the current native context.
1351 // TODO(bmeurer): Use a dedicated cache for Object.create; think about
1352 // slack tracking for Object.create.
1353 Handle<Map> map =
1354 Map::GetObjectCreateMap(isolate, Handle<HeapObject>::cast(prototype));
1355
1356 // Actually allocate the object.
1357 Handle<JSObject> object;
1358 if (map->is_dictionary_map()) {
1359 object = isolate->factory()->NewSlowJSObjectFromMap(map);
1360 } else {
1361 object = isolate->factory()->NewJSObjectFromMap(map);
1362 }
1363 return object;
1364 }
1365
EnsureWritableFastElements(Handle<JSObject> object)1366 void JSObject::EnsureWritableFastElements(Handle<JSObject> object) {
1367 DCHECK(object->HasSmiOrObjectElements() ||
1368 object->HasFastStringWrapperElements());
1369 FixedArray* raw_elems = FixedArray::cast(object->elements());
1370 Heap* heap = object->GetHeap();
1371 if (raw_elems->map() != ReadOnlyRoots(heap).fixed_cow_array_map()) return;
1372 Isolate* isolate = heap->isolate();
1373 Handle<FixedArray> elems(raw_elems, isolate);
1374 Handle<FixedArray> writable_elems = isolate->factory()->CopyFixedArrayWithMap(
1375 elems, isolate->factory()->fixed_array_map());
1376 object->set_elements(*writable_elems);
1377 isolate->counters()->cow_arrays_converted()->Increment();
1378 }
1379
GetHeaderSize(InstanceType type,bool function_has_prototype_slot)1380 int JSObject::GetHeaderSize(InstanceType type,
1381 bool function_has_prototype_slot) {
1382 switch (type) {
1383 case JS_OBJECT_TYPE:
1384 case JS_API_OBJECT_TYPE:
1385 case JS_SPECIAL_API_OBJECT_TYPE:
1386 return JSObject::kHeaderSize;
1387 case JS_GENERATOR_OBJECT_TYPE:
1388 return JSGeneratorObject::kSize;
1389 case JS_ASYNC_GENERATOR_OBJECT_TYPE:
1390 return JSAsyncGeneratorObject::kSize;
1391 case JS_GLOBAL_PROXY_TYPE:
1392 return JSGlobalProxy::kSize;
1393 case JS_GLOBAL_OBJECT_TYPE:
1394 return JSGlobalObject::kSize;
1395 case JS_BOUND_FUNCTION_TYPE:
1396 return JSBoundFunction::kSize;
1397 case JS_FUNCTION_TYPE:
1398 return JSFunction::GetHeaderSize(function_has_prototype_slot);
1399 case JS_VALUE_TYPE:
1400 return JSValue::kSize;
1401 case JS_DATE_TYPE:
1402 return JSDate::kSize;
1403 case JS_ARRAY_TYPE:
1404 return JSArray::kSize;
1405 case JS_ARRAY_BUFFER_TYPE:
1406 return JSArrayBuffer::kSize;
1407 case JS_ARRAY_ITERATOR_TYPE:
1408 return JSArrayIterator::kSize;
1409 case JS_TYPED_ARRAY_TYPE:
1410 return JSTypedArray::kSize;
1411 case JS_DATA_VIEW_TYPE:
1412 return JSDataView::kSize;
1413 case JS_SET_TYPE:
1414 return JSSet::kSize;
1415 case JS_MAP_TYPE:
1416 return JSMap::kSize;
1417 case JS_SET_KEY_VALUE_ITERATOR_TYPE:
1418 case JS_SET_VALUE_ITERATOR_TYPE:
1419 return JSSetIterator::kSize;
1420 case JS_MAP_KEY_ITERATOR_TYPE:
1421 case JS_MAP_KEY_VALUE_ITERATOR_TYPE:
1422 case JS_MAP_VALUE_ITERATOR_TYPE:
1423 return JSMapIterator::kSize;
1424 case JS_WEAK_MAP_TYPE:
1425 return JSWeakMap::kSize;
1426 case JS_WEAK_SET_TYPE:
1427 return JSWeakSet::kSize;
1428 case JS_PROMISE_TYPE:
1429 return JSPromise::kSize;
1430 case JS_REGEXP_TYPE:
1431 return JSRegExp::kSize;
1432 case JS_REGEXP_STRING_ITERATOR_TYPE:
1433 return JSRegExpStringIterator::kSize;
1434 case JS_CONTEXT_EXTENSION_OBJECT_TYPE:
1435 return JSObject::kHeaderSize;
1436 case JS_MESSAGE_OBJECT_TYPE:
1437 return JSMessageObject::kSize;
1438 case JS_ARGUMENTS_TYPE:
1439 return JSObject::kHeaderSize;
1440 case JS_ERROR_TYPE:
1441 return JSObject::kHeaderSize;
1442 case JS_STRING_ITERATOR_TYPE:
1443 return JSStringIterator::kSize;
1444 case JS_MODULE_NAMESPACE_TYPE:
1445 return JSModuleNamespace::kHeaderSize;
1446 #ifdef V8_INTL_SUPPORT
1447 case JS_INTL_COLLATOR_TYPE:
1448 return JSCollator::kSize;
1449 case JS_INTL_LIST_FORMAT_TYPE:
1450 return JSListFormat::kSize;
1451 case JS_INTL_LOCALE_TYPE:
1452 return JSLocale::kSize;
1453 case JS_INTL_PLURAL_RULES_TYPE:
1454 return JSPluralRules::kSize;
1455 case JS_INTL_RELATIVE_TIME_FORMAT_TYPE:
1456 return JSRelativeTimeFormat::kSize;
1457 #endif // V8_INTL_SUPPORT
1458 case WASM_GLOBAL_TYPE:
1459 return WasmGlobalObject::kSize;
1460 case WASM_INSTANCE_TYPE:
1461 return WasmInstanceObject::kSize;
1462 case WASM_MEMORY_TYPE:
1463 return WasmMemoryObject::kSize;
1464 case WASM_MODULE_TYPE:
1465 return WasmModuleObject::kSize;
1466 case WASM_TABLE_TYPE:
1467 return WasmTableObject::kSize;
1468 default:
1469 UNREACHABLE();
1470 }
1471 }
1472
1473 // ES6 9.5.1
1474 // static
GetPrototype(Handle<JSProxy> proxy)1475 MaybeHandle<Object> JSProxy::GetPrototype(Handle<JSProxy> proxy) {
1476 Isolate* isolate = proxy->GetIsolate();
1477 Handle<String> trap_name = isolate->factory()->getPrototypeOf_string();
1478
1479 STACK_CHECK(isolate, MaybeHandle<Object>());
1480
1481 // 1. Let handler be the value of the [[ProxyHandler]] internal slot.
1482 // 2. If handler is null, throw a TypeError exception.
1483 // 3. Assert: Type(handler) is Object.
1484 // 4. Let target be the value of the [[ProxyTarget]] internal slot.
1485 if (proxy->IsRevoked()) {
1486 THROW_NEW_ERROR(isolate,
1487 NewTypeError(MessageTemplate::kProxyRevoked, trap_name),
1488 Object);
1489 }
1490 Handle<JSReceiver> target(JSReceiver::cast(proxy->target()), isolate);
1491 Handle<JSReceiver> handler(JSReceiver::cast(proxy->handler()), isolate);
1492
1493 // 5. Let trap be ? GetMethod(handler, "getPrototypeOf").
1494 Handle<Object> trap;
1495 ASSIGN_RETURN_ON_EXCEPTION(isolate, trap, GetMethod(handler, trap_name),
1496 Object);
1497 // 6. If trap is undefined, then return target.[[GetPrototypeOf]]().
1498 if (trap->IsUndefined(isolate)) {
1499 return JSReceiver::GetPrototype(isolate, target);
1500 }
1501 // 7. Let handlerProto be ? Call(trap, handler, «target»).
1502 Handle<Object> argv[] = {target};
1503 Handle<Object> handler_proto;
1504 ASSIGN_RETURN_ON_EXCEPTION(
1505 isolate, handler_proto,
1506 Execution::Call(isolate, trap, handler, arraysize(argv), argv), Object);
1507 // 8. If Type(handlerProto) is neither Object nor Null, throw a TypeError.
1508 if (!(handler_proto->IsJSReceiver() || handler_proto->IsNull(isolate))) {
1509 THROW_NEW_ERROR(isolate,
1510 NewTypeError(MessageTemplate::kProxyGetPrototypeOfInvalid),
1511 Object);
1512 }
1513 // 9. Let extensibleTarget be ? IsExtensible(target).
1514 Maybe<bool> is_extensible = JSReceiver::IsExtensible(target);
1515 MAYBE_RETURN_NULL(is_extensible);
1516 // 10. If extensibleTarget is true, return handlerProto.
1517 if (is_extensible.FromJust()) return handler_proto;
1518 // 11. Let targetProto be ? target.[[GetPrototypeOf]]().
1519 Handle<Object> target_proto;
1520 ASSIGN_RETURN_ON_EXCEPTION(isolate, target_proto,
1521 JSReceiver::GetPrototype(isolate, target), Object);
1522 // 12. If SameValue(handlerProto, targetProto) is false, throw a TypeError.
1523 if (!handler_proto->SameValue(*target_proto)) {
1524 THROW_NEW_ERROR(
1525 isolate,
1526 NewTypeError(MessageTemplate::kProxyGetPrototypeOfNonExtensible),
1527 Object);
1528 }
1529 // 13. Return handlerProto.
1530 return handler_proto;
1531 }
1532
GetPropertyWithAccessor(LookupIterator * it)1533 MaybeHandle<Object> Object::GetPropertyWithAccessor(LookupIterator* it) {
1534 Isolate* isolate = it->isolate();
1535 Handle<Object> structure = it->GetAccessors();
1536 Handle<Object> receiver = it->GetReceiver();
1537 // In case of global IC, the receiver is the global object. Replace by the
1538 // global proxy.
1539 if (receiver->IsJSGlobalObject()) {
1540 receiver = handle(JSGlobalObject::cast(*receiver)->global_proxy(), isolate);
1541 }
1542
1543 // We should never get here to initialize a const with the hole value since a
1544 // const declaration would conflict with the getter.
1545 DCHECK(!structure->IsForeign());
1546
1547 // API style callbacks.
1548 Handle<JSObject> holder = it->GetHolder<JSObject>();
1549 if (structure->IsAccessorInfo()) {
1550 Handle<Name> name = it->GetName();
1551 Handle<AccessorInfo> info = Handle<AccessorInfo>::cast(structure);
1552 if (!info->IsCompatibleReceiver(*receiver)) {
1553 THROW_NEW_ERROR(isolate,
1554 NewTypeError(MessageTemplate::kIncompatibleMethodReceiver,
1555 name, receiver),
1556 Object);
1557 }
1558
1559 if (!info->has_getter()) return isolate->factory()->undefined_value();
1560
1561 if (info->is_sloppy() && !receiver->IsJSReceiver()) {
1562 ASSIGN_RETURN_ON_EXCEPTION(isolate, receiver,
1563 Object::ConvertReceiver(isolate, receiver),
1564 Object);
1565 }
1566
1567 PropertyCallbackArguments args(isolate, info->data(), *receiver, *holder,
1568 kDontThrow);
1569 Handle<Object> result = args.CallAccessorGetter(info, name);
1570 RETURN_EXCEPTION_IF_SCHEDULED_EXCEPTION(isolate, Object);
1571 if (result.is_null()) return isolate->factory()->undefined_value();
1572 Handle<Object> reboxed_result = handle(*result, isolate);
1573 if (info->replace_on_access() && receiver->IsJSReceiver()) {
1574 RETURN_ON_EXCEPTION(isolate,
1575 Accessors::ReplaceAccessorWithDataProperty(
1576 receiver, holder, name, result),
1577 Object);
1578 }
1579 return reboxed_result;
1580 }
1581
1582 // AccessorPair with 'cached' private property.
1583 if (it->TryLookupCachedProperty()) {
1584 return Object::GetProperty(it);
1585 }
1586
1587 // Regular accessor.
1588 Handle<Object> getter(AccessorPair::cast(*structure)->getter(), isolate);
1589 if (getter->IsFunctionTemplateInfo()) {
1590 SaveContext save(isolate);
1591 isolate->set_context(*holder->GetCreationContext());
1592 return Builtins::InvokeApiFunction(
1593 isolate, false, Handle<FunctionTemplateInfo>::cast(getter), receiver, 0,
1594 nullptr, isolate->factory()->undefined_value());
1595 } else if (getter->IsCallable()) {
1596 // TODO(rossberg): nicer would be to cast to some JSCallable here...
1597 return Object::GetPropertyWithDefinedGetter(
1598 receiver, Handle<JSReceiver>::cast(getter));
1599 }
1600 // Getter is not a function.
1601 return isolate->factory()->undefined_value();
1602 }
1603
1604 // static
redirect(Address address,AccessorComponent component)1605 Address AccessorInfo::redirect(Address address, AccessorComponent component) {
1606 ApiFunction fun(address);
1607 DCHECK_EQ(ACCESSOR_GETTER, component);
1608 ExternalReference::Type type = ExternalReference::DIRECT_GETTER_CALL;
1609 return ExternalReference::Create(&fun, type).address();
1610 }
1611
redirected_getter() const1612 Address AccessorInfo::redirected_getter() const {
1613 Address accessor = v8::ToCData<Address>(getter());
1614 if (accessor == kNullAddress) return kNullAddress;
1615 return redirect(accessor, ACCESSOR_GETTER);
1616 }
1617
redirected_callback() const1618 Address CallHandlerInfo::redirected_callback() const {
1619 Address address = v8::ToCData<Address>(callback());
1620 ApiFunction fun(address);
1621 ExternalReference::Type type = ExternalReference::DIRECT_API_CALL;
1622 return ExternalReference::Create(&fun, type).address();
1623 }
1624
IsCompatibleReceiverMap(Handle<AccessorInfo> info,Handle<Map> map)1625 bool AccessorInfo::IsCompatibleReceiverMap(Handle<AccessorInfo> info,
1626 Handle<Map> map) {
1627 if (!info->HasExpectedReceiverType()) return true;
1628 if (!map->IsJSObjectMap()) return false;
1629 return FunctionTemplateInfo::cast(info->expected_receiver_type())
1630 ->IsTemplateFor(*map);
1631 }
1632
SetPropertyWithAccessor(LookupIterator * it,Handle<Object> value,ShouldThrow should_throw)1633 Maybe<bool> Object::SetPropertyWithAccessor(LookupIterator* it,
1634 Handle<Object> value,
1635 ShouldThrow should_throw) {
1636 Isolate* isolate = it->isolate();
1637 Handle<Object> structure = it->GetAccessors();
1638 Handle<Object> receiver = it->GetReceiver();
1639 // In case of global IC, the receiver is the global object. Replace by the
1640 // global proxy.
1641 if (receiver->IsJSGlobalObject()) {
1642 receiver = handle(JSGlobalObject::cast(*receiver)->global_proxy(), isolate);
1643 }
1644
1645 // We should never get here to initialize a const with the hole value since a
1646 // const declaration would conflict with the setter.
1647 DCHECK(!structure->IsForeign());
1648
1649 // API style callbacks.
1650 Handle<JSObject> holder = it->GetHolder<JSObject>();
1651 if (structure->IsAccessorInfo()) {
1652 Handle<Name> name = it->GetName();
1653 Handle<AccessorInfo> info = Handle<AccessorInfo>::cast(structure);
1654 if (!info->IsCompatibleReceiver(*receiver)) {
1655 isolate->Throw(*isolate->factory()->NewTypeError(
1656 MessageTemplate::kIncompatibleMethodReceiver, name, receiver));
1657 return Nothing<bool>();
1658 }
1659
1660 if (!info->has_setter()) {
1661 // TODO(verwaest): We should not get here anymore once all AccessorInfos
1662 // are marked as special_data_property. They cannot both be writable and
1663 // not have a setter.
1664 return Just(true);
1665 }
1666
1667 if (info->is_sloppy() && !receiver->IsJSReceiver()) {
1668 ASSIGN_RETURN_ON_EXCEPTION_VALUE(
1669 isolate, receiver, Object::ConvertReceiver(isolate, receiver),
1670 Nothing<bool>());
1671 }
1672
1673 // The actual type of setter callback is either
1674 // v8::AccessorNameSetterCallback or
1675 // i::Accesors::AccessorNameBooleanSetterCallback, depending on whether the
1676 // AccessorInfo was created by the API or internally (see accessors.cc).
1677 // Here we handle both cases using GenericNamedPropertySetterCallback and
1678 // its Call method.
1679 PropertyCallbackArguments args(isolate, info->data(), *receiver, *holder,
1680 should_throw);
1681 Handle<Object> result = args.CallAccessorSetter(info, name, value);
1682 // In the case of AccessorNameSetterCallback, we know that the result value
1683 // cannot have been set, so the result of Call will be null. In the case of
1684 // AccessorNameBooleanSetterCallback, the result will either be null
1685 // (signalling an exception) or a boolean Oddball.
1686 RETURN_VALUE_IF_SCHEDULED_EXCEPTION(isolate, Nothing<bool>());
1687 if (result.is_null()) return Just(true);
1688 DCHECK(result->BooleanValue(isolate) || should_throw == kDontThrow);
1689 return Just(result->BooleanValue(isolate));
1690 }
1691
1692 // Regular accessor.
1693 Handle<Object> setter(AccessorPair::cast(*structure)->setter(), isolate);
1694 if (setter->IsFunctionTemplateInfo()) {
1695 SaveContext save(isolate);
1696 isolate->set_context(*holder->GetCreationContext());
1697 Handle<Object> argv[] = {value};
1698 RETURN_ON_EXCEPTION_VALUE(
1699 isolate, Builtins::InvokeApiFunction(
1700 isolate, false, Handle<FunctionTemplateInfo>::cast(setter),
1701 receiver, arraysize(argv), argv,
1702 isolate->factory()->undefined_value()),
1703 Nothing<bool>());
1704 return Just(true);
1705 } else if (setter->IsCallable()) {
1706 // TODO(rossberg): nicer would be to cast to some JSCallable here...
1707 return SetPropertyWithDefinedSetter(
1708 receiver, Handle<JSReceiver>::cast(setter), value, should_throw);
1709 }
1710
1711 RETURN_FAILURE(isolate, should_throw,
1712 NewTypeError(MessageTemplate::kNoSetterInCallback,
1713 it->GetName(), it->GetHolder<JSObject>()));
1714 }
1715
1716
GetPropertyWithDefinedGetter(Handle<Object> receiver,Handle<JSReceiver> getter)1717 MaybeHandle<Object> Object::GetPropertyWithDefinedGetter(
1718 Handle<Object> receiver,
1719 Handle<JSReceiver> getter) {
1720 Isolate* isolate = getter->GetIsolate();
1721
1722 // Platforms with simulators like arm/arm64 expose a funny issue. If the
1723 // simulator has a separate JS stack pointer from the C++ stack pointer, it
1724 // can miss C++ stack overflows in the stack guard at the start of JavaScript
1725 // functions. It would be very expensive to check the C++ stack pointer at
1726 // that location. The best solution seems to be to break the impasse by
1727 // adding checks at possible recursion points. What's more, we don't put
1728 // this stack check behind the USE_SIMULATOR define in order to keep
1729 // behavior the same between hardware and simulators.
1730 StackLimitCheck check(isolate);
1731 if (check.JsHasOverflowed()) {
1732 isolate->StackOverflow();
1733 return MaybeHandle<Object>();
1734 }
1735
1736 return Execution::Call(isolate, getter, receiver, 0, nullptr);
1737 }
1738
1739
SetPropertyWithDefinedSetter(Handle<Object> receiver,Handle<JSReceiver> setter,Handle<Object> value,ShouldThrow should_throw)1740 Maybe<bool> Object::SetPropertyWithDefinedSetter(Handle<Object> receiver,
1741 Handle<JSReceiver> setter,
1742 Handle<Object> value,
1743 ShouldThrow should_throw) {
1744 Isolate* isolate = setter->GetIsolate();
1745
1746 Handle<Object> argv[] = { value };
1747 RETURN_ON_EXCEPTION_VALUE(isolate, Execution::Call(isolate, setter, receiver,
1748 arraysize(argv), argv),
1749 Nothing<bool>());
1750 return Just(true);
1751 }
1752
1753
1754 // static
AllCanRead(LookupIterator * it)1755 bool JSObject::AllCanRead(LookupIterator* it) {
1756 // Skip current iteration, it's in state ACCESS_CHECK or INTERCEPTOR, both of
1757 // which have already been checked.
1758 DCHECK(it->state() == LookupIterator::ACCESS_CHECK ||
1759 it->state() == LookupIterator::INTERCEPTOR);
1760 for (it->Next(); it->IsFound(); it->Next()) {
1761 if (it->state() == LookupIterator::ACCESSOR) {
1762 auto accessors = it->GetAccessors();
1763 if (accessors->IsAccessorInfo()) {
1764 if (AccessorInfo::cast(*accessors)->all_can_read()) return true;
1765 }
1766 } else if (it->state() == LookupIterator::INTERCEPTOR) {
1767 if (it->GetInterceptor()->all_can_read()) return true;
1768 } else if (it->state() == LookupIterator::JSPROXY) {
1769 // Stop lookupiterating. And no, AllCanNotRead.
1770 return false;
1771 }
1772 }
1773 return false;
1774 }
1775
1776 namespace {
1777
GetPropertyWithInterceptorInternal(LookupIterator * it,Handle<InterceptorInfo> interceptor,bool * done)1778 MaybeHandle<Object> GetPropertyWithInterceptorInternal(
1779 LookupIterator* it, Handle<InterceptorInfo> interceptor, bool* done) {
1780 *done = false;
1781 Isolate* isolate = it->isolate();
1782 // Make sure that the top context does not change when doing callbacks or
1783 // interceptor calls.
1784 AssertNoContextChange ncc(isolate);
1785
1786 if (interceptor->getter()->IsUndefined(isolate)) {
1787 return isolate->factory()->undefined_value();
1788 }
1789
1790 Handle<JSObject> holder = it->GetHolder<JSObject>();
1791 Handle<Object> result;
1792 Handle<Object> receiver = it->GetReceiver();
1793 if (!receiver->IsJSReceiver()) {
1794 ASSIGN_RETURN_ON_EXCEPTION(
1795 isolate, receiver, Object::ConvertReceiver(isolate, receiver), Object);
1796 }
1797 PropertyCallbackArguments args(isolate, interceptor->data(), *receiver,
1798 *holder, kDontThrow);
1799
1800 if (it->IsElement()) {
1801 result = args.CallIndexedGetter(interceptor, it->index());
1802 } else {
1803 result = args.CallNamedGetter(interceptor, it->name());
1804 }
1805
1806 RETURN_EXCEPTION_IF_SCHEDULED_EXCEPTION(isolate, Object);
1807 if (result.is_null()) return isolate->factory()->undefined_value();
1808 *done = true;
1809 // Rebox handle before return
1810 return handle(*result, isolate);
1811 }
1812
GetPropertyAttributesWithInterceptorInternal(LookupIterator * it,Handle<InterceptorInfo> interceptor)1813 Maybe<PropertyAttributes> GetPropertyAttributesWithInterceptorInternal(
1814 LookupIterator* it, Handle<InterceptorInfo> interceptor) {
1815 Isolate* isolate = it->isolate();
1816 // Make sure that the top context does not change when doing
1817 // callbacks or interceptor calls.
1818 AssertNoContextChange ncc(isolate);
1819 HandleScope scope(isolate);
1820
1821 Handle<JSObject> holder = it->GetHolder<JSObject>();
1822 DCHECK_IMPLIES(!it->IsElement() && it->name()->IsSymbol(),
1823 interceptor->can_intercept_symbols());
1824 Handle<Object> receiver = it->GetReceiver();
1825 if (!receiver->IsJSReceiver()) {
1826 ASSIGN_RETURN_ON_EXCEPTION_VALUE(isolate, receiver,
1827 Object::ConvertReceiver(isolate, receiver),
1828 Nothing<PropertyAttributes>());
1829 }
1830 PropertyCallbackArguments args(isolate, interceptor->data(), *receiver,
1831 *holder, kDontThrow);
1832 if (!interceptor->query()->IsUndefined(isolate)) {
1833 Handle<Object> result;
1834 if (it->IsElement()) {
1835 result = args.CallIndexedQuery(interceptor, it->index());
1836 } else {
1837 result = args.CallNamedQuery(interceptor, it->name());
1838 }
1839 if (!result.is_null()) {
1840 int32_t value;
1841 CHECK(result->ToInt32(&value));
1842 return Just(static_cast<PropertyAttributes>(value));
1843 }
1844 } else if (!interceptor->getter()->IsUndefined(isolate)) {
1845 // TODO(verwaest): Use GetPropertyWithInterceptor?
1846 Handle<Object> result;
1847 if (it->IsElement()) {
1848 result = args.CallIndexedGetter(interceptor, it->index());
1849 } else {
1850 result = args.CallNamedGetter(interceptor, it->name());
1851 }
1852 if (!result.is_null()) return Just(DONT_ENUM);
1853 }
1854
1855 RETURN_VALUE_IF_SCHEDULED_EXCEPTION(isolate, Nothing<PropertyAttributes>());
1856 return Just(ABSENT);
1857 }
1858
SetPropertyWithInterceptorInternal(LookupIterator * it,Handle<InterceptorInfo> interceptor,ShouldThrow should_throw,Handle<Object> value)1859 Maybe<bool> SetPropertyWithInterceptorInternal(
1860 LookupIterator* it, Handle<InterceptorInfo> interceptor,
1861 ShouldThrow should_throw, Handle<Object> value) {
1862 Isolate* isolate = it->isolate();
1863 // Make sure that the top context does not change when doing callbacks or
1864 // interceptor calls.
1865 AssertNoContextChange ncc(isolate);
1866
1867 if (interceptor->setter()->IsUndefined(isolate)) return Just(false);
1868
1869 Handle<JSObject> holder = it->GetHolder<JSObject>();
1870 bool result;
1871 Handle<Object> receiver = it->GetReceiver();
1872 if (!receiver->IsJSReceiver()) {
1873 ASSIGN_RETURN_ON_EXCEPTION_VALUE(isolate, receiver,
1874 Object::ConvertReceiver(isolate, receiver),
1875 Nothing<bool>());
1876 }
1877 PropertyCallbackArguments args(isolate, interceptor->data(), *receiver,
1878 *holder, should_throw);
1879
1880 if (it->IsElement()) {
1881 // TODO(neis): In the future, we may want to actually return the
1882 // interceptor's result, which then should be a boolean.
1883 result = !args.CallIndexedSetter(interceptor, it->index(), value).is_null();
1884 } else {
1885 result = !args.CallNamedSetter(interceptor, it->name(), value).is_null();
1886 }
1887
1888 RETURN_VALUE_IF_SCHEDULED_EXCEPTION(it->isolate(), Nothing<bool>());
1889 return Just(result);
1890 }
1891
DefinePropertyWithInterceptorInternal(LookupIterator * it,Handle<InterceptorInfo> interceptor,ShouldThrow should_throw,PropertyDescriptor & desc)1892 Maybe<bool> DefinePropertyWithInterceptorInternal(
1893 LookupIterator* it, Handle<InterceptorInfo> interceptor,
1894 ShouldThrow should_throw, PropertyDescriptor& desc) {
1895 Isolate* isolate = it->isolate();
1896 // Make sure that the top context does not change when doing callbacks or
1897 // interceptor calls.
1898 AssertNoContextChange ncc(isolate);
1899
1900 if (interceptor->definer()->IsUndefined(isolate)) return Just(false);
1901
1902 Handle<JSObject> holder = it->GetHolder<JSObject>();
1903 bool result;
1904 Handle<Object> receiver = it->GetReceiver();
1905 if (!receiver->IsJSReceiver()) {
1906 ASSIGN_RETURN_ON_EXCEPTION_VALUE(isolate, receiver,
1907 Object::ConvertReceiver(isolate, receiver),
1908 Nothing<bool>());
1909 }
1910 PropertyCallbackArguments args(isolate, interceptor->data(), *receiver,
1911 *holder, should_throw);
1912
1913 std::unique_ptr<v8::PropertyDescriptor> descriptor(
1914 new v8::PropertyDescriptor());
1915 if (PropertyDescriptor::IsAccessorDescriptor(&desc)) {
1916 descriptor.reset(new v8::PropertyDescriptor(
1917 v8::Utils::ToLocal(desc.get()), v8::Utils::ToLocal(desc.set())));
1918 } else if (PropertyDescriptor::IsDataDescriptor(&desc)) {
1919 if (desc.has_writable()) {
1920 descriptor.reset(new v8::PropertyDescriptor(
1921 v8::Utils::ToLocal(desc.value()), desc.writable()));
1922 } else {
1923 descriptor.reset(
1924 new v8::PropertyDescriptor(v8::Utils::ToLocal(desc.value())));
1925 }
1926 }
1927 if (desc.has_enumerable()) {
1928 descriptor->set_enumerable(desc.enumerable());
1929 }
1930 if (desc.has_configurable()) {
1931 descriptor->set_configurable(desc.configurable());
1932 }
1933
1934 if (it->IsElement()) {
1935 result = !args.CallIndexedDefiner(interceptor, it->index(), *descriptor)
1936 .is_null();
1937 } else {
1938 result =
1939 !args.CallNamedDefiner(interceptor, it->name(), *descriptor).is_null();
1940 }
1941
1942 RETURN_VALUE_IF_SCHEDULED_EXCEPTION(it->isolate(), Nothing<bool>());
1943 return Just(result);
1944 }
1945
1946 } // namespace
1947
GetPropertyWithFailedAccessCheck(LookupIterator * it)1948 MaybeHandle<Object> JSObject::GetPropertyWithFailedAccessCheck(
1949 LookupIterator* it) {
1950 Isolate* isolate = it->isolate();
1951 Handle<JSObject> checked = it->GetHolder<JSObject>();
1952 Handle<InterceptorInfo> interceptor =
1953 it->GetInterceptorForFailedAccessCheck();
1954 if (interceptor.is_null()) {
1955 while (AllCanRead(it)) {
1956 if (it->state() == LookupIterator::ACCESSOR) {
1957 return GetPropertyWithAccessor(it);
1958 }
1959 DCHECK_EQ(LookupIterator::INTERCEPTOR, it->state());
1960 bool done;
1961 Handle<Object> result;
1962 ASSIGN_RETURN_ON_EXCEPTION(isolate, result,
1963 GetPropertyWithInterceptor(it, &done), Object);
1964 if (done) return result;
1965 }
1966
1967 } else {
1968 Handle<Object> result;
1969 bool done;
1970 ASSIGN_RETURN_ON_EXCEPTION(
1971 isolate, result,
1972 GetPropertyWithInterceptorInternal(it, interceptor, &done), Object);
1973 if (done) return result;
1974 }
1975
1976 // Cross-Origin [[Get]] of Well-Known Symbols does not throw, and returns
1977 // undefined.
1978 Handle<Name> name = it->GetName();
1979 if (name->IsSymbol() && Symbol::cast(*name)->is_well_known_symbol()) {
1980 return it->factory()->undefined_value();
1981 }
1982
1983 isolate->ReportFailedAccessCheck(checked);
1984 RETURN_EXCEPTION_IF_SCHEDULED_EXCEPTION(isolate, Object);
1985 return it->factory()->undefined_value();
1986 }
1987
1988
GetPropertyAttributesWithFailedAccessCheck(LookupIterator * it)1989 Maybe<PropertyAttributes> JSObject::GetPropertyAttributesWithFailedAccessCheck(
1990 LookupIterator* it) {
1991 Isolate* isolate = it->isolate();
1992 Handle<JSObject> checked = it->GetHolder<JSObject>();
1993 Handle<InterceptorInfo> interceptor =
1994 it->GetInterceptorForFailedAccessCheck();
1995 if (interceptor.is_null()) {
1996 while (AllCanRead(it)) {
1997 if (it->state() == LookupIterator::ACCESSOR) {
1998 return Just(it->property_attributes());
1999 }
2000 DCHECK_EQ(LookupIterator::INTERCEPTOR, it->state());
2001 auto result = GetPropertyAttributesWithInterceptor(it);
2002 if (isolate->has_scheduled_exception()) break;
2003 if (result.IsJust() && result.FromJust() != ABSENT) return result;
2004 }
2005 } else {
2006 Maybe<PropertyAttributes> result =
2007 GetPropertyAttributesWithInterceptorInternal(it, interceptor);
2008 if (isolate->has_pending_exception()) return Nothing<PropertyAttributes>();
2009 if (result.FromMaybe(ABSENT) != ABSENT) return result;
2010 }
2011 isolate->ReportFailedAccessCheck(checked);
2012 RETURN_VALUE_IF_SCHEDULED_EXCEPTION(isolate, Nothing<PropertyAttributes>());
2013 return Just(ABSENT);
2014 }
2015
2016
2017 // static
AllCanWrite(LookupIterator * it)2018 bool JSObject::AllCanWrite(LookupIterator* it) {
2019 for (; it->IsFound() && it->state() != LookupIterator::JSPROXY; it->Next()) {
2020 if (it->state() == LookupIterator::ACCESSOR) {
2021 Handle<Object> accessors = it->GetAccessors();
2022 if (accessors->IsAccessorInfo()) {
2023 if (AccessorInfo::cast(*accessors)->all_can_write()) return true;
2024 }
2025 }
2026 }
2027 return false;
2028 }
2029
2030
SetPropertyWithFailedAccessCheck(LookupIterator * it,Handle<Object> value,ShouldThrow should_throw)2031 Maybe<bool> JSObject::SetPropertyWithFailedAccessCheck(
2032 LookupIterator* it, Handle<Object> value, ShouldThrow should_throw) {
2033 Isolate* isolate = it->isolate();
2034 Handle<JSObject> checked = it->GetHolder<JSObject>();
2035 Handle<InterceptorInfo> interceptor =
2036 it->GetInterceptorForFailedAccessCheck();
2037 if (interceptor.is_null()) {
2038 if (AllCanWrite(it)) {
2039 return SetPropertyWithAccessor(it, value, should_throw);
2040 }
2041 } else {
2042 Maybe<bool> result = SetPropertyWithInterceptorInternal(
2043 it, interceptor, should_throw, value);
2044 if (isolate->has_pending_exception()) return Nothing<bool>();
2045 if (result.IsJust()) return result;
2046 }
2047 isolate->ReportFailedAccessCheck(checked);
2048 RETURN_VALUE_IF_SCHEDULED_EXCEPTION(isolate, Nothing<bool>());
2049 return Just(true);
2050 }
2051
2052
SetNormalizedProperty(Handle<JSObject> object,Handle<Name> name,Handle<Object> value,PropertyDetails details)2053 void JSObject::SetNormalizedProperty(Handle<JSObject> object,
2054 Handle<Name> name,
2055 Handle<Object> value,
2056 PropertyDetails details) {
2057 DCHECK(!object->HasFastProperties());
2058 DCHECK(name->IsUniqueName());
2059 Isolate* isolate = object->GetIsolate();
2060
2061 uint32_t hash = name->Hash();
2062
2063 if (object->IsJSGlobalObject()) {
2064 Handle<JSGlobalObject> global_obj = Handle<JSGlobalObject>::cast(object);
2065 Handle<GlobalDictionary> dictionary(global_obj->global_dictionary(),
2066 isolate);
2067 int entry = dictionary->FindEntry(ReadOnlyRoots(isolate), name, hash);
2068
2069 if (entry == GlobalDictionary::kNotFound) {
2070 DCHECK_IMPLIES(global_obj->map()->is_prototype_map(),
2071 Map::IsPrototypeChainInvalidated(global_obj->map()));
2072 auto cell = isolate->factory()->NewPropertyCell(name);
2073 cell->set_value(*value);
2074 auto cell_type = value->IsUndefined(isolate)
2075 ? PropertyCellType::kUndefined
2076 : PropertyCellType::kConstant;
2077 details = details.set_cell_type(cell_type);
2078 value = cell;
2079 dictionary =
2080 GlobalDictionary::Add(isolate, dictionary, name, value, details);
2081 global_obj->set_global_dictionary(*dictionary);
2082 } else {
2083 Handle<PropertyCell> cell = PropertyCell::PrepareForValue(
2084 isolate, dictionary, entry, value, details);
2085 cell->set_value(*value);
2086 }
2087 } else {
2088 Handle<NameDictionary> dictionary(object->property_dictionary(), isolate);
2089
2090 int entry = dictionary->FindEntry(isolate, name);
2091 if (entry == NameDictionary::kNotFound) {
2092 DCHECK_IMPLIES(object->map()->is_prototype_map(),
2093 Map::IsPrototypeChainInvalidated(object->map()));
2094 dictionary =
2095 NameDictionary::Add(isolate, dictionary, name, value, details);
2096 object->SetProperties(*dictionary);
2097 } else {
2098 PropertyDetails original_details = dictionary->DetailsAt(entry);
2099 int enumeration_index = original_details.dictionary_index();
2100 DCHECK_GT(enumeration_index, 0);
2101 details = details.set_index(enumeration_index);
2102 dictionary->SetEntry(isolate, entry, *name, *value, details);
2103 }
2104 }
2105 }
2106
2107 // static
HasInPrototypeChain(Isolate * isolate,Handle<JSReceiver> object,Handle<Object> proto)2108 Maybe<bool> JSReceiver::HasInPrototypeChain(Isolate* isolate,
2109 Handle<JSReceiver> object,
2110 Handle<Object> proto) {
2111 PrototypeIterator iter(isolate, object, kStartAtReceiver);
2112 while (true) {
2113 if (!iter.AdvanceFollowingProxies()) return Nothing<bool>();
2114 if (iter.IsAtEnd()) return Just(false);
2115 if (PrototypeIterator::GetCurrent(iter).is_identical_to(proto)) {
2116 return Just(true);
2117 }
2118 }
2119 }
2120
2121 namespace {
2122
HasExcludedProperty(const ScopedVector<Handle<Object>> * excluded_properties,Handle<Object> search_element)2123 bool HasExcludedProperty(
2124 const ScopedVector<Handle<Object>>* excluded_properties,
2125 Handle<Object> search_element) {
2126 // TODO(gsathya): Change this to be a hashtable.
2127 for (int i = 0; i < excluded_properties->length(); i++) {
2128 if (search_element->SameValue(*excluded_properties->at(i))) {
2129 return true;
2130 }
2131 }
2132
2133 return false;
2134 }
2135
FastAssign(Handle<JSReceiver> target,Handle<Object> source,const ScopedVector<Handle<Object>> * excluded_properties,bool use_set)2136 V8_WARN_UNUSED_RESULT Maybe<bool> FastAssign(
2137 Handle<JSReceiver> target, Handle<Object> source,
2138 const ScopedVector<Handle<Object>>* excluded_properties, bool use_set) {
2139 // Non-empty strings are the only non-JSReceivers that need to be handled
2140 // explicitly by Object.assign.
2141 if (!source->IsJSReceiver()) {
2142 return Just(!source->IsString() || String::cast(*source)->length() == 0);
2143 }
2144
2145 // If the target is deprecated, the object will be updated on first store. If
2146 // the source for that store equals the target, this will invalidate the
2147 // cached representation of the source. Preventively upgrade the target.
2148 // Do this on each iteration since any property load could cause deprecation.
2149 if (target->map()->is_deprecated()) {
2150 JSObject::MigrateInstance(Handle<JSObject>::cast(target));
2151 }
2152
2153 Isolate* isolate = target->GetIsolate();
2154 Handle<Map> map(JSReceiver::cast(*source)->map(), isolate);
2155
2156 if (!map->IsJSObjectMap()) return Just(false);
2157 if (!map->OnlyHasSimpleProperties()) return Just(false);
2158
2159 Handle<JSObject> from = Handle<JSObject>::cast(source);
2160 if (from->elements() != ReadOnlyRoots(isolate).empty_fixed_array()) {
2161 return Just(false);
2162 }
2163
2164 Handle<DescriptorArray> descriptors(map->instance_descriptors(), isolate);
2165 int length = map->NumberOfOwnDescriptors();
2166
2167 bool stable = true;
2168
2169 for (int i = 0; i < length; i++) {
2170 Handle<Name> next_key(descriptors->GetKey(i), isolate);
2171 Handle<Object> prop_value;
2172 // Directly decode from the descriptor array if |from| did not change shape.
2173 if (stable) {
2174 PropertyDetails details = descriptors->GetDetails(i);
2175 if (!details.IsEnumerable()) continue;
2176 if (details.kind() == kData) {
2177 if (details.location() == kDescriptor) {
2178 prop_value = handle(descriptors->GetStrongValue(i), isolate);
2179 } else {
2180 Representation representation = details.representation();
2181 FieldIndex index = FieldIndex::ForDescriptor(*map, i);
2182 prop_value = JSObject::FastPropertyAt(from, representation, index);
2183 }
2184 } else {
2185 ASSIGN_RETURN_ON_EXCEPTION_VALUE(
2186 isolate, prop_value,
2187 JSReceiver::GetProperty(isolate, from, next_key), Nothing<bool>());
2188 stable = from->map() == *map;
2189 }
2190 } else {
2191 // If the map did change, do a slower lookup. We are still guaranteed that
2192 // the object has a simple shape, and that the key is a name.
2193 LookupIterator it(from, next_key, from,
2194 LookupIterator::OWN_SKIP_INTERCEPTOR);
2195 if (!it.IsFound()) continue;
2196 DCHECK(it.state() == LookupIterator::DATA ||
2197 it.state() == LookupIterator::ACCESSOR);
2198 if (!it.IsEnumerable()) continue;
2199 ASSIGN_RETURN_ON_EXCEPTION_VALUE(
2200 isolate, prop_value, Object::GetProperty(&it), Nothing<bool>());
2201 }
2202
2203 if (use_set) {
2204 LookupIterator it(target, next_key, target);
2205 Maybe<bool> result =
2206 Object::SetProperty(&it, prop_value, LanguageMode::kStrict,
2207 Object::CERTAINLY_NOT_STORE_FROM_KEYED);
2208 if (result.IsNothing()) return result;
2209 if (stable) stable = from->map() == *map;
2210 } else {
2211 if (excluded_properties != nullptr &&
2212 HasExcludedProperty(excluded_properties, next_key)) {
2213 continue;
2214 }
2215
2216 // 4a ii 2. Perform ? CreateDataProperty(target, nextKey, propValue).
2217 bool success;
2218 LookupIterator it = LookupIterator::PropertyOrElement(
2219 isolate, target, next_key, &success, LookupIterator::OWN);
2220 CHECK(success);
2221 CHECK(JSObject::CreateDataProperty(&it, prop_value, kThrowOnError)
2222 .FromJust());
2223 }
2224 }
2225
2226 return Just(true);
2227 }
2228 } // namespace
2229
2230 // static
SetOrCopyDataProperties(Isolate * isolate,Handle<JSReceiver> target,Handle<Object> source,const ScopedVector<Handle<Object>> * excluded_properties,bool use_set)2231 Maybe<bool> JSReceiver::SetOrCopyDataProperties(
2232 Isolate* isolate, Handle<JSReceiver> target, Handle<Object> source,
2233 const ScopedVector<Handle<Object>>* excluded_properties, bool use_set) {
2234 Maybe<bool> fast_assign =
2235 FastAssign(target, source, excluded_properties, use_set);
2236 if (fast_assign.IsNothing()) return Nothing<bool>();
2237 if (fast_assign.FromJust()) return Just(true);
2238
2239 Handle<JSReceiver> from = Object::ToObject(isolate, source).ToHandleChecked();
2240 // 3b. Let keys be ? from.[[OwnPropertyKeys]]().
2241 Handle<FixedArray> keys;
2242 ASSIGN_RETURN_ON_EXCEPTION_VALUE(
2243 isolate, keys,
2244 KeyAccumulator::GetKeys(from, KeyCollectionMode::kOwnOnly, ALL_PROPERTIES,
2245 GetKeysConversion::kKeepNumbers),
2246 Nothing<bool>());
2247
2248 // 4. Repeat for each element nextKey of keys in List order,
2249 for (int j = 0; j < keys->length(); ++j) {
2250 Handle<Object> next_key(keys->get(j), isolate);
2251 // 4a i. Let desc be ? from.[[GetOwnProperty]](nextKey).
2252 PropertyDescriptor desc;
2253 Maybe<bool> found =
2254 JSReceiver::GetOwnPropertyDescriptor(isolate, from, next_key, &desc);
2255 if (found.IsNothing()) return Nothing<bool>();
2256 // 4a ii. If desc is not undefined and desc.[[Enumerable]] is true, then
2257 if (found.FromJust() && desc.enumerable()) {
2258 // 4a ii 1. Let propValue be ? Get(from, nextKey).
2259 Handle<Object> prop_value;
2260 ASSIGN_RETURN_ON_EXCEPTION_VALUE(
2261 isolate, prop_value,
2262 Runtime::GetObjectProperty(isolate, from, next_key), Nothing<bool>());
2263
2264 if (use_set) {
2265 // 4c ii 2. Let status be ? Set(to, nextKey, propValue, true).
2266 Handle<Object> status;
2267 ASSIGN_RETURN_ON_EXCEPTION_VALUE(
2268 isolate, status,
2269 Runtime::SetObjectProperty(isolate, target, next_key, prop_value,
2270 LanguageMode::kStrict),
2271 Nothing<bool>());
2272 } else {
2273 if (excluded_properties != nullptr &&
2274 HasExcludedProperty(excluded_properties, next_key)) {
2275 continue;
2276 }
2277
2278 // 4a ii 2. Perform ! CreateDataProperty(target, nextKey, propValue).
2279 bool success;
2280 LookupIterator it = LookupIterator::PropertyOrElement(
2281 isolate, target, next_key, &success, LookupIterator::OWN);
2282 CHECK(success);
2283 CHECK(JSObject::CreateDataProperty(&it, prop_value, kThrowOnError)
2284 .FromJust());
2285 }
2286 }
2287 }
2288
2289 return Just(true);
2290 }
2291
GetPrototypeChainRootMap(Isolate * isolate) const2292 Map* Object::GetPrototypeChainRootMap(Isolate* isolate) const {
2293 DisallowHeapAllocation no_alloc;
2294 if (IsSmi()) {
2295 Context* native_context = isolate->context()->native_context();
2296 return native_context->number_function()->initial_map();
2297 }
2298
2299 const HeapObject* heap_object = HeapObject::cast(this);
2300 return heap_object->map()->GetPrototypeChainRootMap(isolate);
2301 }
2302
GetPrototypeChainRootMap(Isolate * isolate) const2303 Map* Map::GetPrototypeChainRootMap(Isolate* isolate) const {
2304 DisallowHeapAllocation no_alloc;
2305 if (IsJSReceiverMap()) {
2306 return const_cast<Map*>(this);
2307 }
2308 int constructor_function_index = GetConstructorFunctionIndex();
2309 if (constructor_function_index != Map::kNoConstructorFunctionIndex) {
2310 Context* native_context = isolate->context()->native_context();
2311 JSFunction* constructor_function =
2312 JSFunction::cast(native_context->get(constructor_function_index));
2313 return constructor_function->initial_map();
2314 }
2315 return ReadOnlyRoots(isolate).null_value()->map();
2316 }
2317
2318 // static
GetOrCreateHash(Isolate * isolate,Object * key)2319 Smi* Object::GetOrCreateHash(Isolate* isolate, Object* key) {
2320 DisallowHeapAllocation no_gc;
2321 return key->GetOrCreateHash(isolate);
2322 }
2323
GetOrCreateHash(Isolate * isolate)2324 Smi* Object::GetOrCreateHash(Isolate* isolate) {
2325 DisallowHeapAllocation no_gc;
2326 Object* hash = Object::GetSimpleHash(this);
2327 if (hash->IsSmi()) return Smi::cast(hash);
2328
2329 DCHECK(IsJSReceiver());
2330 return JSReceiver::cast(this)->GetOrCreateIdentityHash(isolate);
2331 }
2332
2333
SameValue(Object * other)2334 bool Object::SameValue(Object* other) {
2335 if (other == this) return true;
2336
2337 if (IsNumber() && other->IsNumber()) {
2338 double this_value = Number();
2339 double other_value = other->Number();
2340 // SameValue(NaN, NaN) is true.
2341 if (this_value != other_value) {
2342 return std::isnan(this_value) && std::isnan(other_value);
2343 }
2344 // SameValue(0.0, -0.0) is false.
2345 return (std::signbit(this_value) == std::signbit(other_value));
2346 }
2347 if (IsString() && other->IsString()) {
2348 return String::cast(this)->Equals(String::cast(other));
2349 }
2350 if (IsBigInt() && other->IsBigInt()) {
2351 return BigInt::EqualToBigInt(BigInt::cast(this), BigInt::cast(other));
2352 }
2353 return false;
2354 }
2355
2356
SameValueZero(Object * other)2357 bool Object::SameValueZero(Object* other) {
2358 if (other == this) return true;
2359
2360 if (IsNumber() && other->IsNumber()) {
2361 double this_value = Number();
2362 double other_value = other->Number();
2363 // +0 == -0 is true
2364 return this_value == other_value ||
2365 (std::isnan(this_value) && std::isnan(other_value));
2366 }
2367 if (IsString() && other->IsString()) {
2368 return String::cast(this)->Equals(String::cast(other));
2369 }
2370 if (IsBigInt() && other->IsBigInt()) {
2371 return BigInt::EqualToBigInt(BigInt::cast(this), BigInt::cast(other));
2372 }
2373 return false;
2374 }
2375
2376
ArraySpeciesConstructor(Isolate * isolate,Handle<Object> original_array)2377 MaybeHandle<Object> Object::ArraySpeciesConstructor(
2378 Isolate* isolate, Handle<Object> original_array) {
2379 Handle<Object> default_species = isolate->array_function();
2380 if (original_array->IsJSArray() &&
2381 Handle<JSArray>::cast(original_array)->HasArrayPrototype(isolate) &&
2382 isolate->IsArraySpeciesLookupChainIntact()) {
2383 return default_species;
2384 }
2385 Handle<Object> constructor = isolate->factory()->undefined_value();
2386 Maybe<bool> is_array = Object::IsArray(original_array);
2387 MAYBE_RETURN_NULL(is_array);
2388 if (is_array.FromJust()) {
2389 ASSIGN_RETURN_ON_EXCEPTION(
2390 isolate, constructor,
2391 Object::GetProperty(isolate, original_array,
2392 isolate->factory()->constructor_string()),
2393 Object);
2394 if (constructor->IsConstructor()) {
2395 Handle<Context> constructor_context;
2396 ASSIGN_RETURN_ON_EXCEPTION(
2397 isolate, constructor_context,
2398 JSReceiver::GetFunctionRealm(Handle<JSReceiver>::cast(constructor)),
2399 Object);
2400 if (*constructor_context != *isolate->native_context() &&
2401 *constructor == constructor_context->array_function()) {
2402 constructor = isolate->factory()->undefined_value();
2403 }
2404 }
2405 if (constructor->IsJSReceiver()) {
2406 ASSIGN_RETURN_ON_EXCEPTION(
2407 isolate, constructor,
2408 JSReceiver::GetProperty(isolate,
2409 Handle<JSReceiver>::cast(constructor),
2410 isolate->factory()->species_symbol()),
2411 Object);
2412 if (constructor->IsNull(isolate)) {
2413 constructor = isolate->factory()->undefined_value();
2414 }
2415 }
2416 }
2417 if (constructor->IsUndefined(isolate)) {
2418 return default_species;
2419 } else {
2420 if (!constructor->IsConstructor()) {
2421 THROW_NEW_ERROR(isolate,
2422 NewTypeError(MessageTemplate::kSpeciesNotConstructor),
2423 Object);
2424 }
2425 return constructor;
2426 }
2427 }
2428
2429 // ES6 section 7.3.20 SpeciesConstructor ( O, defaultConstructor )
SpeciesConstructor(Isolate * isolate,Handle<JSReceiver> recv,Handle<JSFunction> default_ctor)2430 V8_WARN_UNUSED_RESULT MaybeHandle<Object> Object::SpeciesConstructor(
2431 Isolate* isolate, Handle<JSReceiver> recv,
2432 Handle<JSFunction> default_ctor) {
2433 Handle<Object> ctor_obj;
2434 ASSIGN_RETURN_ON_EXCEPTION(
2435 isolate, ctor_obj,
2436 JSObject::GetProperty(isolate, recv,
2437 isolate->factory()->constructor_string()),
2438 Object);
2439
2440 if (ctor_obj->IsUndefined(isolate)) return default_ctor;
2441
2442 if (!ctor_obj->IsJSReceiver()) {
2443 THROW_NEW_ERROR(isolate,
2444 NewTypeError(MessageTemplate::kConstructorNotReceiver),
2445 Object);
2446 }
2447
2448 Handle<JSReceiver> ctor = Handle<JSReceiver>::cast(ctor_obj);
2449
2450 Handle<Object> species;
2451 ASSIGN_RETURN_ON_EXCEPTION(
2452 isolate, species,
2453 JSObject::GetProperty(isolate, ctor,
2454 isolate->factory()->species_symbol()),
2455 Object);
2456
2457 if (species->IsNullOrUndefined(isolate)) {
2458 return default_ctor;
2459 }
2460
2461 if (species->IsConstructor()) return species;
2462
2463 THROW_NEW_ERROR(
2464 isolate, NewTypeError(MessageTemplate::kSpeciesNotConstructor), Object);
2465 }
2466
IterationHasObservableEffects()2467 bool Object::IterationHasObservableEffects() {
2468 // Check that this object is an array.
2469 if (!IsJSArray()) return true;
2470 JSArray* array = JSArray::cast(this);
2471 Isolate* isolate = array->GetIsolate();
2472
2473 #ifdef V8_ENABLE_FORCE_SLOW_PATH
2474 if (isolate->force_slow_path()) return true;
2475 #endif
2476
2477 // Check that we have the original ArrayPrototype.
2478 if (!array->map()->prototype()->IsJSObject()) return true;
2479 JSObject* array_proto = JSObject::cast(array->map()->prototype());
2480 if (!isolate->is_initial_array_prototype(array_proto)) return true;
2481
2482 // Check that the ArrayPrototype hasn't been modified in a way that would
2483 // affect iteration.
2484 if (!isolate->IsArrayIteratorLookupChainIntact()) return true;
2485
2486 // For FastPacked kinds, iteration will have the same effect as simply
2487 // accessing each property in order.
2488 ElementsKind array_kind = array->GetElementsKind();
2489 if (IsFastPackedElementsKind(array_kind)) return false;
2490
2491 // For FastHoley kinds, an element access on a hole would cause a lookup on
2492 // the prototype. This could have different results if the prototype has been
2493 // changed.
2494 if (IsHoleyElementsKind(array_kind) &&
2495 isolate->IsNoElementsProtectorIntact()) {
2496 return false;
2497 }
2498 return true;
2499 }
2500
ShortPrint(FILE * out)2501 void Object::ShortPrint(FILE* out) {
2502 OFStream os(out);
2503 os << Brief(this);
2504 }
2505
2506
ShortPrint(StringStream * accumulator)2507 void Object::ShortPrint(StringStream* accumulator) {
2508 std::ostringstream os;
2509 os << Brief(this);
2510 accumulator->Add(os.str().c_str());
2511 }
2512
2513
ShortPrint(std::ostream & os)2514 void Object::ShortPrint(std::ostream& os) { os << Brief(this); }
2515
ShortPrint(FILE * out)2516 void MaybeObject::ShortPrint(FILE* out) {
2517 OFStream os(out);
2518 os << Brief(this);
2519 }
2520
ShortPrint(StringStream * accumulator)2521 void MaybeObject::ShortPrint(StringStream* accumulator) {
2522 std::ostringstream os;
2523 os << Brief(this);
2524 accumulator->Add(os.str().c_str());
2525 }
2526
ShortPrint(std::ostream & os)2527 void MaybeObject::ShortPrint(std::ostream& os) { os << Brief(this); }
2528
Brief(const Object * v)2529 Brief::Brief(const Object* v)
2530 : value(MaybeObject::FromObject(const_cast<Object*>(v))) {}
2531
operator <<(std::ostream & os,const Brief & v)2532 std::ostream& operator<<(std::ostream& os, const Brief& v) {
2533 // TODO(marja): const-correct HeapObjectShortPrint.
2534 MaybeObject* maybe_object = const_cast<MaybeObject*>(v.value);
2535 Smi* smi;
2536 HeapObject* heap_object;
2537 if (maybe_object->ToSmi(&smi)) {
2538 smi->SmiPrint(os);
2539 } else if (maybe_object->IsClearedWeakHeapObject()) {
2540 os << "[cleared]";
2541 } else if (maybe_object->ToWeakHeapObject(&heap_object)) {
2542 os << "[weak] ";
2543 heap_object->HeapObjectShortPrint(os);
2544 } else if (maybe_object->ToStrongHeapObject(&heap_object)) {
2545 heap_object->HeapObjectShortPrint(os);
2546 } else {
2547 UNREACHABLE();
2548 }
2549 return os;
2550 }
2551
SmiPrint(std::ostream & os) const2552 void Smi::SmiPrint(std::ostream& os) const { // NOLINT
2553 os << value();
2554 }
2555
SlowFlatten(Isolate * isolate,Handle<ConsString> cons,PretenureFlag pretenure)2556 Handle<String> String::SlowFlatten(Isolate* isolate, Handle<ConsString> cons,
2557 PretenureFlag pretenure) {
2558 DCHECK_NE(cons->second()->length(), 0);
2559
2560 // TurboFan can create cons strings with empty first parts.
2561 while (cons->first()->length() == 0) {
2562 // We do not want to call this function recursively. Therefore we call
2563 // String::Flatten only in those cases where String::SlowFlatten is not
2564 // called again.
2565 if (cons->second()->IsConsString() && !cons->second()->IsFlat()) {
2566 cons = handle(ConsString::cast(cons->second()), isolate);
2567 } else {
2568 return String::Flatten(isolate, handle(cons->second(), isolate));
2569 }
2570 }
2571
2572 DCHECK(AllowHeapAllocation::IsAllowed());
2573 int length = cons->length();
2574 PretenureFlag tenure = Heap::InNewSpace(*cons) ? pretenure : TENURED;
2575 Handle<SeqString> result;
2576 if (cons->IsOneByteRepresentation()) {
2577 Handle<SeqOneByteString> flat = isolate->factory()->NewRawOneByteString(
2578 length, tenure).ToHandleChecked();
2579 DisallowHeapAllocation no_gc;
2580 WriteToFlat(*cons, flat->GetChars(), 0, length);
2581 result = flat;
2582 } else {
2583 Handle<SeqTwoByteString> flat = isolate->factory()->NewRawTwoByteString(
2584 length, tenure).ToHandleChecked();
2585 DisallowHeapAllocation no_gc;
2586 WriteToFlat(*cons, flat->GetChars(), 0, length);
2587 result = flat;
2588 }
2589 cons->set_first(isolate, *result);
2590 cons->set_second(isolate, ReadOnlyRoots(isolate).empty_string());
2591 DCHECK(result->IsFlat());
2592 return result;
2593 }
2594
2595
2596
MakeExternal(v8::String::ExternalStringResource * resource)2597 bool String::MakeExternal(v8::String::ExternalStringResource* resource) {
2598 DisallowHeapAllocation no_allocation;
2599 // Externalizing twice leaks the external resource, so it's
2600 // prohibited by the API.
2601 DCHECK(this->SupportsExternalization());
2602 DCHECK(!resource->IsCompressible());
2603 #ifdef ENABLE_SLOW_DCHECKS
2604 if (FLAG_enable_slow_asserts) {
2605 // Assert that the resource and the string are equivalent.
2606 DCHECK(static_cast<size_t>(this->length()) == resource->length());
2607 ScopedVector<uc16> smart_chars(this->length());
2608 String::WriteToFlat(this, smart_chars.start(), 0, this->length());
2609 DCHECK_EQ(0, memcmp(smart_chars.start(), resource->data(),
2610 resource->length() * sizeof(smart_chars[0])));
2611 }
2612 #endif // DEBUG
2613 int size = this->Size(); // Byte size of the original string.
2614 // Abort if size does not allow in-place conversion.
2615 if (size < ExternalString::kShortSize) return false;
2616 Isolate* isolate;
2617 // Read-only strings cannot be made external, since that would mutate the
2618 // string.
2619 if (!Isolate::FromWritableHeapObject(this, &isolate)) return false;
2620 Heap* heap = isolate->heap();
2621 bool is_one_byte = this->IsOneByteRepresentation();
2622 bool is_internalized = this->IsInternalizedString();
2623 bool has_pointers = StringShape(this).IsIndirect();
2624 if (has_pointers) {
2625 heap->NotifyObjectLayoutChange(this, size, no_allocation);
2626 }
2627 // Morph the string to an external string by replacing the map and
2628 // reinitializing the fields. This won't work if the space the existing
2629 // string occupies is too small for a regular external string.
2630 // Instead, we resort to a short external string instead, omitting
2631 // the field caching the address of the backing store. When we encounter
2632 // short external strings in generated code, we need to bailout to runtime.
2633 Map* new_map;
2634 ReadOnlyRoots roots(heap);
2635 if (size < ExternalString::kSize) {
2636 if (is_internalized) {
2637 new_map =
2638 is_one_byte
2639 ? roots
2640 .short_external_internalized_string_with_one_byte_data_map()
2641 : roots.short_external_internalized_string_map();
2642 } else {
2643 new_map = is_one_byte
2644 ? roots.short_external_string_with_one_byte_data_map()
2645 : roots.short_external_string_map();
2646 }
2647 } else {
2648 new_map =
2649 is_internalized
2650 ? (is_one_byte
2651 ? roots.external_internalized_string_with_one_byte_data_map()
2652 : roots.external_internalized_string_map())
2653 : (is_one_byte ? roots.external_string_with_one_byte_data_map()
2654 : roots.external_string_map());
2655 }
2656
2657 // Byte size of the external String object.
2658 int new_size = this->SizeFromMap(new_map);
2659 heap->CreateFillerObjectAt(this->address() + new_size, size - new_size,
2660 ClearRecordedSlots::kNo);
2661 if (has_pointers) {
2662 heap->ClearRecordedSlotRange(this->address(), this->address() + new_size);
2663 }
2664
2665 // We are storing the new map using release store after creating a filler for
2666 // the left-over space to avoid races with the sweeper thread.
2667 this->synchronized_set_map(new_map);
2668
2669 ExternalTwoByteString* self = ExternalTwoByteString::cast(this);
2670 self->SetResource(isolate, resource);
2671 heap->RegisterExternalString(this);
2672 if (is_internalized) self->Hash(); // Force regeneration of the hash value.
2673 return true;
2674 }
2675
2676
MakeExternal(v8::String::ExternalOneByteStringResource * resource)2677 bool String::MakeExternal(v8::String::ExternalOneByteStringResource* resource) {
2678 DisallowHeapAllocation no_allocation;
2679 // Externalizing twice leaks the external resource, so it's
2680 // prohibited by the API.
2681 DCHECK(this->SupportsExternalization());
2682 DCHECK(!resource->IsCompressible());
2683 #ifdef ENABLE_SLOW_DCHECKS
2684 if (FLAG_enable_slow_asserts) {
2685 // Assert that the resource and the string are equivalent.
2686 DCHECK(static_cast<size_t>(this->length()) == resource->length());
2687 if (this->IsTwoByteRepresentation()) {
2688 ScopedVector<uint16_t> smart_chars(this->length());
2689 String::WriteToFlat(this, smart_chars.start(), 0, this->length());
2690 DCHECK(String::IsOneByte(smart_chars.start(), this->length()));
2691 }
2692 ScopedVector<char> smart_chars(this->length());
2693 String::WriteToFlat(this, smart_chars.start(), 0, this->length());
2694 DCHECK_EQ(0, memcmp(smart_chars.start(), resource->data(),
2695 resource->length() * sizeof(smart_chars[0])));
2696 }
2697 #endif // DEBUG
2698 int size = this->Size(); // Byte size of the original string.
2699 // Abort if size does not allow in-place conversion.
2700 if (size < ExternalString::kShortSize) return false;
2701 Isolate* isolate;
2702 // Read-only strings cannot be made external, since that would mutate the
2703 // string.
2704 if (!Isolate::FromWritableHeapObject(this, &isolate)) return false;
2705 Heap* heap = isolate->heap();
2706 bool is_internalized = this->IsInternalizedString();
2707 bool has_pointers = StringShape(this).IsIndirect();
2708
2709 if (has_pointers) {
2710 heap->NotifyObjectLayoutChange(this, size, no_allocation);
2711 }
2712
2713 // Morph the string to an external string by replacing the map and
2714 // reinitializing the fields. This won't work if the space the existing
2715 // string occupies is too small for a regular external string.
2716 // Instead, we resort to a short external string instead, omitting
2717 // the field caching the address of the backing store. When we encounter
2718 // short external strings in generated code, we need to bailout to runtime.
2719 Map* new_map;
2720 ReadOnlyRoots roots(heap);
2721 if (size < ExternalString::kSize) {
2722 new_map = is_internalized
2723 ? roots.short_external_one_byte_internalized_string_map()
2724 : roots.short_external_one_byte_string_map();
2725 } else {
2726 new_map = is_internalized
2727 ? roots.external_one_byte_internalized_string_map()
2728 : roots.external_one_byte_string_map();
2729 }
2730
2731 // Byte size of the external String object.
2732 int new_size = this->SizeFromMap(new_map);
2733 heap->CreateFillerObjectAt(this->address() + new_size, size - new_size,
2734 ClearRecordedSlots::kNo);
2735 if (has_pointers) {
2736 heap->ClearRecordedSlotRange(this->address(), this->address() + new_size);
2737 }
2738
2739 // We are storing the new map using release store after creating a filler for
2740 // the left-over space to avoid races with the sweeper thread.
2741 this->synchronized_set_map(new_map);
2742
2743 ExternalOneByteString* self = ExternalOneByteString::cast(this);
2744 self->SetResource(isolate, resource);
2745 heap->RegisterExternalString(this);
2746 if (is_internalized) self->Hash(); // Force regeneration of the hash value.
2747 return true;
2748 }
2749
SupportsExternalization()2750 bool String::SupportsExternalization() {
2751 if (this->IsThinString()) {
2752 return i::ThinString::cast(this)->actual()->SupportsExternalization();
2753 }
2754
2755 Isolate* isolate;
2756 // RO_SPACE strings cannot be externalized.
2757 if (!Isolate::FromWritableHeapObject(this, &isolate)) {
2758 return false;
2759 }
2760
2761 // Already an external string.
2762 if (StringShape(this).IsExternal()) {
2763 return false;
2764 }
2765
2766 return !isolate->heap()->IsInGCPostProcessing();
2767 }
2768
StringShortPrint(StringStream * accumulator,bool show_details)2769 void String::StringShortPrint(StringStream* accumulator, bool show_details) {
2770 int len = length();
2771 if (len > kMaxShortPrintLength) {
2772 accumulator->Add("<Very long string[%u]>", len);
2773 return;
2774 }
2775
2776 if (!LooksValid()) {
2777 accumulator->Add("<Invalid String>");
2778 return;
2779 }
2780
2781 StringCharacterStream stream(this);
2782
2783 bool truncated = false;
2784 if (len > kMaxShortPrintLength) {
2785 len = kMaxShortPrintLength;
2786 truncated = true;
2787 }
2788 bool one_byte = true;
2789 for (int i = 0; i < len; i++) {
2790 uint16_t c = stream.GetNext();
2791
2792 if (c < 32 || c >= 127) {
2793 one_byte = false;
2794 }
2795 }
2796 stream.Reset(this);
2797 if (one_byte) {
2798 if (show_details) accumulator->Add("<String[%u]: ", length());
2799 for (int i = 0; i < len; i++) {
2800 accumulator->Put(static_cast<char>(stream.GetNext()));
2801 }
2802 if (show_details) accumulator->Put('>');
2803 } else {
2804 // Backslash indicates that the string contains control
2805 // characters and that backslashes are therefore escaped.
2806 if (show_details) accumulator->Add("<String[%u]\\: ", length());
2807 for (int i = 0; i < len; i++) {
2808 uint16_t c = stream.GetNext();
2809 if (c == '\n') {
2810 accumulator->Add("\\n");
2811 } else if (c == '\r') {
2812 accumulator->Add("\\r");
2813 } else if (c == '\\') {
2814 accumulator->Add("\\\\");
2815 } else if (c < 32 || c > 126) {
2816 accumulator->Add("\\x%02x", c);
2817 } else {
2818 accumulator->Put(static_cast<char>(c));
2819 }
2820 }
2821 if (truncated) {
2822 accumulator->Put('.');
2823 accumulator->Put('.');
2824 accumulator->Put('.');
2825 }
2826 if (show_details) accumulator->Put('>');
2827 }
2828 return;
2829 }
2830
2831
PrintUC16(std::ostream & os,int start,int end)2832 void String::PrintUC16(std::ostream& os, int start, int end) { // NOLINT
2833 if (end < 0) end = length();
2834 StringCharacterStream stream(this, start);
2835 for (int i = start; i < end && stream.HasMore(); i++) {
2836 os << AsUC16(stream.GetNext());
2837 }
2838 }
2839
2840
JSObjectShortPrint(StringStream * accumulator)2841 void JSObject::JSObjectShortPrint(StringStream* accumulator) {
2842 switch (map()->instance_type()) {
2843 case JS_ARRAY_TYPE: {
2844 double length = JSArray::cast(this)->length()->IsUndefined()
2845 ? 0
2846 : JSArray::cast(this)->length()->Number();
2847 accumulator->Add("<JSArray[%u]>", static_cast<uint32_t>(length));
2848 break;
2849 }
2850 case JS_BOUND_FUNCTION_TYPE: {
2851 JSBoundFunction* bound_function = JSBoundFunction::cast(this);
2852 accumulator->Add("<JSBoundFunction");
2853 accumulator->Add(
2854 " (BoundTargetFunction %p)>",
2855 reinterpret_cast<void*>(bound_function->bound_target_function()));
2856 break;
2857 }
2858 case JS_WEAK_MAP_TYPE: {
2859 accumulator->Add("<JSWeakMap>");
2860 break;
2861 }
2862 case JS_WEAK_SET_TYPE: {
2863 accumulator->Add("<JSWeakSet>");
2864 break;
2865 }
2866 case JS_REGEXP_TYPE: {
2867 accumulator->Add("<JSRegExp");
2868 JSRegExp* regexp = JSRegExp::cast(this);
2869 if (regexp->source()->IsString()) {
2870 accumulator->Add(" ");
2871 String::cast(regexp->source())->StringShortPrint(accumulator);
2872 }
2873 accumulator->Add(">");
2874
2875 break;
2876 }
2877 case JS_FUNCTION_TYPE: {
2878 JSFunction* function = JSFunction::cast(this);
2879 Object* fun_name = function->shared()->DebugName();
2880 bool printed = false;
2881 if (fun_name->IsString()) {
2882 String* str = String::cast(fun_name);
2883 if (str->length() > 0) {
2884 accumulator->Add("<JSFunction ");
2885 accumulator->Put(str);
2886 printed = true;
2887 }
2888 }
2889 if (!printed) {
2890 accumulator->Add("<JSFunction");
2891 }
2892 if (FLAG_trace_file_names) {
2893 Object* source_name =
2894 Script::cast(function->shared()->script())->name();
2895 if (source_name->IsString()) {
2896 String* str = String::cast(source_name);
2897 if (str->length() > 0) {
2898 accumulator->Add(" <");
2899 accumulator->Put(str);
2900 accumulator->Add(">");
2901 }
2902 }
2903 }
2904 accumulator->Add(" (sfi = %p)",
2905 reinterpret_cast<void*>(function->shared()));
2906 accumulator->Put('>');
2907 break;
2908 }
2909 case JS_GENERATOR_OBJECT_TYPE: {
2910 accumulator->Add("<JSGenerator>");
2911 break;
2912 }
2913 case JS_ASYNC_GENERATOR_OBJECT_TYPE: {
2914 accumulator->Add("<JS AsyncGenerator>");
2915 break;
2916 }
2917
2918 // All other JSObjects are rather similar to each other (JSObject,
2919 // JSGlobalProxy, JSGlobalObject, JSUndetectable, JSValue).
2920 default: {
2921 Map* map_of_this = map();
2922 Heap* heap = GetHeap();
2923 Object* constructor = map_of_this->GetConstructor();
2924 bool printed = false;
2925 if (constructor->IsHeapObject() &&
2926 !heap->Contains(HeapObject::cast(constructor))) {
2927 accumulator->Add("!!!INVALID CONSTRUCTOR!!!");
2928 } else {
2929 bool global_object = IsJSGlobalProxy();
2930 if (constructor->IsJSFunction()) {
2931 if (!heap->Contains(JSFunction::cast(constructor)->shared())) {
2932 accumulator->Add("!!!INVALID SHARED ON CONSTRUCTOR!!!");
2933 } else {
2934 String* constructor_name =
2935 JSFunction::cast(constructor)->shared()->Name();
2936 if (constructor_name->length() > 0) {
2937 accumulator->Add(global_object ? "<GlobalObject " : "<");
2938 accumulator->Put(constructor_name);
2939 accumulator->Add(
2940 " %smap = %p",
2941 map_of_this->is_deprecated() ? "deprecated-" : "",
2942 map_of_this);
2943 printed = true;
2944 }
2945 }
2946 } else if (constructor->IsFunctionTemplateInfo()) {
2947 accumulator->Add(global_object ? "<RemoteObject>" : "<RemoteObject>");
2948 printed = true;
2949 }
2950 if (!printed) {
2951 accumulator->Add("<JS%sObject", global_object ? "Global " : "");
2952 }
2953 }
2954 if (IsJSValue()) {
2955 accumulator->Add(" value = ");
2956 JSValue::cast(this)->value()->ShortPrint(accumulator);
2957 }
2958 accumulator->Put('>');
2959 break;
2960 }
2961 }
2962 }
2963
2964
PrintElementsTransition(FILE * file,Handle<JSObject> object,ElementsKind from_kind,Handle<FixedArrayBase> from_elements,ElementsKind to_kind,Handle<FixedArrayBase> to_elements)2965 void JSObject::PrintElementsTransition(
2966 FILE* file, Handle<JSObject> object,
2967 ElementsKind from_kind, Handle<FixedArrayBase> from_elements,
2968 ElementsKind to_kind, Handle<FixedArrayBase> to_elements) {
2969 if (from_kind != to_kind) {
2970 OFStream os(file);
2971 os << "elements transition [" << ElementsKindToString(from_kind) << " -> "
2972 << ElementsKindToString(to_kind) << "] in ";
2973 JavaScriptFrame::PrintTop(object->GetIsolate(), file, false, true);
2974 PrintF(file, " for ");
2975 object->ShortPrint(file);
2976 PrintF(file, " from ");
2977 from_elements->ShortPrint(file);
2978 PrintF(file, " to ");
2979 to_elements->ShortPrint(file);
2980 PrintF(file, "\n");
2981 }
2982 }
2983
2984
2985 // static
GetConstructorFunction(Handle<Map> map,Handle<Context> native_context)2986 MaybeHandle<JSFunction> Map::GetConstructorFunction(
2987 Handle<Map> map, Handle<Context> native_context) {
2988 if (map->IsPrimitiveMap()) {
2989 int const constructor_function_index = map->GetConstructorFunctionIndex();
2990 if (constructor_function_index != kNoConstructorFunctionIndex) {
2991 return handle(
2992 JSFunction::cast(native_context->get(constructor_function_index)),
2993 native_context->GetIsolate());
2994 }
2995 }
2996 return MaybeHandle<JSFunction>();
2997 }
2998
PrintReconfiguration(Isolate * isolate,FILE * file,int modify_index,PropertyKind kind,PropertyAttributes attributes)2999 void Map::PrintReconfiguration(Isolate* isolate, FILE* file, int modify_index,
3000 PropertyKind kind,
3001 PropertyAttributes attributes) {
3002 OFStream os(file);
3003 os << "[reconfiguring]";
3004 Name* name = instance_descriptors()->GetKey(modify_index);
3005 if (name->IsString()) {
3006 String::cast(name)->PrintOn(file);
3007 } else {
3008 os << "{symbol " << static_cast<void*>(name) << "}";
3009 }
3010 os << ": " << (kind == kData ? "kData" : "ACCESSORS") << ", attrs: ";
3011 os << attributes << " [";
3012 JavaScriptFrame::PrintTop(isolate, file, false, true);
3013 os << "]\n";
3014 }
3015
GetVisitorId(Map * map)3016 VisitorId Map::GetVisitorId(Map* map) {
3017 STATIC_ASSERT(kVisitorIdCount <= 256);
3018
3019 const int instance_type = map->instance_type();
3020 const bool has_unboxed_fields =
3021 FLAG_unbox_double_fields && !map->HasFastPointerLayout();
3022 if (instance_type < FIRST_NONSTRING_TYPE) {
3023 switch (instance_type & kStringRepresentationMask) {
3024 case kSeqStringTag:
3025 if ((instance_type & kStringEncodingMask) == kOneByteStringTag) {
3026 return kVisitSeqOneByteString;
3027 } else {
3028 return kVisitSeqTwoByteString;
3029 }
3030
3031 case kConsStringTag:
3032 if (IsShortcutCandidate(instance_type)) {
3033 return kVisitShortcutCandidate;
3034 } else {
3035 return kVisitConsString;
3036 }
3037
3038 case kSlicedStringTag:
3039 return kVisitSlicedString;
3040
3041 case kExternalStringTag:
3042 return kVisitDataObject;
3043
3044 case kThinStringTag:
3045 return kVisitThinString;
3046 }
3047 UNREACHABLE();
3048 }
3049
3050 switch (instance_type) {
3051 case BYTE_ARRAY_TYPE:
3052 return kVisitByteArray;
3053
3054 case BYTECODE_ARRAY_TYPE:
3055 return kVisitBytecodeArray;
3056
3057 case FREE_SPACE_TYPE:
3058 return kVisitFreeSpace;
3059
3060 case FIXED_ARRAY_TYPE:
3061 case OBJECT_BOILERPLATE_DESCRIPTION_TYPE:
3062 case HASH_TABLE_TYPE:
3063 case ORDERED_HASH_MAP_TYPE:
3064 case ORDERED_HASH_SET_TYPE:
3065 case NAME_DICTIONARY_TYPE:
3066 case GLOBAL_DICTIONARY_TYPE:
3067 case NUMBER_DICTIONARY_TYPE:
3068 case SIMPLE_NUMBER_DICTIONARY_TYPE:
3069 case STRING_TABLE_TYPE:
3070 case SCOPE_INFO_TYPE:
3071 case SCRIPT_CONTEXT_TABLE_TYPE:
3072 case BLOCK_CONTEXT_TYPE:
3073 case CATCH_CONTEXT_TYPE:
3074 case DEBUG_EVALUATE_CONTEXT_TYPE:
3075 case EVAL_CONTEXT_TYPE:
3076 case FUNCTION_CONTEXT_TYPE:
3077 case MODULE_CONTEXT_TYPE:
3078 case NATIVE_CONTEXT_TYPE:
3079 case SCRIPT_CONTEXT_TYPE:
3080 case WITH_CONTEXT_TYPE:
3081 return kVisitFixedArray;
3082
3083 case EPHEMERON_HASH_TABLE_TYPE:
3084 return kVisitEphemeronHashTable;
3085
3086 case WEAK_FIXED_ARRAY_TYPE:
3087 case WEAK_ARRAY_LIST_TYPE:
3088 case DESCRIPTOR_ARRAY_TYPE:
3089 return kVisitWeakArray;
3090
3091 case FIXED_DOUBLE_ARRAY_TYPE:
3092 return kVisitFixedDoubleArray;
3093
3094 case PROPERTY_ARRAY_TYPE:
3095 return kVisitPropertyArray;
3096
3097 case FEEDBACK_CELL_TYPE:
3098 return kVisitFeedbackCell;
3099
3100 case FEEDBACK_VECTOR_TYPE:
3101 return kVisitFeedbackVector;
3102
3103 case ODDBALL_TYPE:
3104 return kVisitOddball;
3105
3106 case MAP_TYPE:
3107 return kVisitMap;
3108
3109 case CODE_TYPE:
3110 return kVisitCode;
3111
3112 case CELL_TYPE:
3113 return kVisitCell;
3114
3115 case PROPERTY_CELL_TYPE:
3116 return kVisitPropertyCell;
3117
3118 case TRANSITION_ARRAY_TYPE:
3119 return kVisitTransitionArray;
3120
3121 case JS_WEAK_MAP_TYPE:
3122 case JS_WEAK_SET_TYPE:
3123 return kVisitJSWeakCollection;
3124
3125 case CALL_HANDLER_INFO_TYPE:
3126 return kVisitStruct;
3127
3128 case SHARED_FUNCTION_INFO_TYPE:
3129 return kVisitSharedFunctionInfo;
3130
3131 case JS_PROXY_TYPE:
3132 return kVisitStruct;
3133
3134 case SYMBOL_TYPE:
3135 return kVisitSymbol;
3136
3137 case JS_ARRAY_BUFFER_TYPE:
3138 return kVisitJSArrayBuffer;
3139
3140 case SMALL_ORDERED_HASH_MAP_TYPE:
3141 return kVisitSmallOrderedHashMap;
3142
3143 case SMALL_ORDERED_HASH_SET_TYPE:
3144 return kVisitSmallOrderedHashSet;
3145
3146 case CODE_DATA_CONTAINER_TYPE:
3147 return kVisitCodeDataContainer;
3148
3149 case WASM_INSTANCE_TYPE:
3150 return kVisitWasmInstanceObject;
3151
3152 case PRE_PARSED_SCOPE_DATA_TYPE:
3153 return kVisitPreParsedScopeData;
3154
3155 case UNCOMPILED_DATA_WITHOUT_PRE_PARSED_SCOPE_TYPE:
3156 return kVisitUncompiledDataWithoutPreParsedScope;
3157
3158 case UNCOMPILED_DATA_WITH_PRE_PARSED_SCOPE_TYPE:
3159 return kVisitUncompiledDataWithPreParsedScope;
3160
3161 case JS_OBJECT_TYPE:
3162 case JS_ERROR_TYPE:
3163 case JS_ARGUMENTS_TYPE:
3164 case JS_ASYNC_FROM_SYNC_ITERATOR_TYPE:
3165 case JS_CONTEXT_EXTENSION_OBJECT_TYPE:
3166 case JS_GENERATOR_OBJECT_TYPE:
3167 case JS_ASYNC_GENERATOR_OBJECT_TYPE:
3168 case JS_MODULE_NAMESPACE_TYPE:
3169 case JS_VALUE_TYPE:
3170 case JS_DATE_TYPE:
3171 case JS_ARRAY_ITERATOR_TYPE:
3172 case JS_ARRAY_TYPE:
3173 case JS_GLOBAL_PROXY_TYPE:
3174 case JS_GLOBAL_OBJECT_TYPE:
3175 case JS_MESSAGE_OBJECT_TYPE:
3176 case JS_TYPED_ARRAY_TYPE:
3177 case JS_DATA_VIEW_TYPE:
3178 case JS_SET_TYPE:
3179 case JS_MAP_TYPE:
3180 case JS_SET_KEY_VALUE_ITERATOR_TYPE:
3181 case JS_SET_VALUE_ITERATOR_TYPE:
3182 case JS_MAP_KEY_ITERATOR_TYPE:
3183 case JS_MAP_KEY_VALUE_ITERATOR_TYPE:
3184 case JS_MAP_VALUE_ITERATOR_TYPE:
3185 case JS_STRING_ITERATOR_TYPE:
3186 case JS_PROMISE_TYPE:
3187 case JS_REGEXP_TYPE:
3188 case JS_REGEXP_STRING_ITERATOR_TYPE:
3189 #ifdef V8_INTL_SUPPORT
3190 case JS_INTL_COLLATOR_TYPE:
3191 case JS_INTL_LIST_FORMAT_TYPE:
3192 case JS_INTL_LOCALE_TYPE:
3193 case JS_INTL_PLURAL_RULES_TYPE:
3194 case JS_INTL_RELATIVE_TIME_FORMAT_TYPE:
3195 #endif // V8_INTL_SUPPORT
3196 case WASM_GLOBAL_TYPE:
3197 case WASM_MEMORY_TYPE:
3198 case WASM_MODULE_TYPE:
3199 case WASM_TABLE_TYPE:
3200 case JS_BOUND_FUNCTION_TYPE:
3201 return has_unboxed_fields ? kVisitJSObject : kVisitJSObjectFast;
3202 case JS_API_OBJECT_TYPE:
3203 case JS_SPECIAL_API_OBJECT_TYPE:
3204 return kVisitJSApiObject;
3205
3206 case JS_FUNCTION_TYPE:
3207 return kVisitJSFunction;
3208
3209 case FILLER_TYPE:
3210 case FOREIGN_TYPE:
3211 case HEAP_NUMBER_TYPE:
3212 case MUTABLE_HEAP_NUMBER_TYPE:
3213 case FEEDBACK_METADATA_TYPE:
3214 return kVisitDataObject;
3215
3216 case BIGINT_TYPE:
3217 return kVisitBigInt;
3218
3219 case FIXED_UINT8_ARRAY_TYPE:
3220 case FIXED_INT8_ARRAY_TYPE:
3221 case FIXED_UINT16_ARRAY_TYPE:
3222 case FIXED_INT16_ARRAY_TYPE:
3223 case FIXED_UINT32_ARRAY_TYPE:
3224 case FIXED_INT32_ARRAY_TYPE:
3225 case FIXED_FLOAT32_ARRAY_TYPE:
3226 case FIXED_UINT8_CLAMPED_ARRAY_TYPE:
3227 case FIXED_BIGUINT64_ARRAY_TYPE:
3228 case FIXED_BIGINT64_ARRAY_TYPE:
3229 return kVisitFixedTypedArrayBase;
3230
3231 case FIXED_FLOAT64_ARRAY_TYPE:
3232 return kVisitFixedFloat64Array;
3233
3234 case ALLOCATION_SITE_TYPE:
3235 return kVisitAllocationSite;
3236
3237 #define MAKE_STRUCT_CASE(NAME, Name, name) case NAME##_TYPE:
3238 STRUCT_LIST(MAKE_STRUCT_CASE)
3239 #undef MAKE_STRUCT_CASE
3240 if (instance_type == PROTOTYPE_INFO_TYPE) {
3241 return kVisitPrototypeInfo;
3242 }
3243 return kVisitStruct;
3244
3245 case LOAD_HANDLER_TYPE:
3246 case STORE_HANDLER_TYPE:
3247 return kVisitDataHandler;
3248
3249 default:
3250 UNREACHABLE();
3251 }
3252 }
3253
PrintGeneralization(Isolate * isolate,FILE * file,const char * reason,int modify_index,int split,int descriptors,bool descriptor_to_field,Representation old_representation,Representation new_representation,MaybeHandle<FieldType> old_field_type,MaybeHandle<Object> old_value,MaybeHandle<FieldType> new_field_type,MaybeHandle<Object> new_value)3254 void Map::PrintGeneralization(
3255 Isolate* isolate, FILE* file, const char* reason, int modify_index,
3256 int split, int descriptors, bool descriptor_to_field,
3257 Representation old_representation, Representation new_representation,
3258 MaybeHandle<FieldType> old_field_type, MaybeHandle<Object> old_value,
3259 MaybeHandle<FieldType> new_field_type, MaybeHandle<Object> new_value) {
3260 OFStream os(file);
3261 os << "[generalizing]";
3262 Name* name = instance_descriptors()->GetKey(modify_index);
3263 if (name->IsString()) {
3264 String::cast(name)->PrintOn(file);
3265 } else {
3266 os << "{symbol " << static_cast<void*>(name) << "}";
3267 }
3268 os << ":";
3269 if (descriptor_to_field) {
3270 os << "c";
3271 } else {
3272 os << old_representation.Mnemonic() << "{";
3273 if (old_field_type.is_null()) {
3274 os << Brief(*(old_value.ToHandleChecked()));
3275 } else {
3276 old_field_type.ToHandleChecked()->PrintTo(os);
3277 }
3278 os << "}";
3279 }
3280 os << "->" << new_representation.Mnemonic() << "{";
3281 if (new_field_type.is_null()) {
3282 os << Brief(*(new_value.ToHandleChecked()));
3283 } else {
3284 new_field_type.ToHandleChecked()->PrintTo(os);
3285 }
3286 os << "} (";
3287 if (strlen(reason) > 0) {
3288 os << reason;
3289 } else {
3290 os << "+" << (descriptors - split) << " maps";
3291 }
3292 os << ") [";
3293 JavaScriptFrame::PrintTop(isolate, file, false, true);
3294 os << "]\n";
3295 }
3296
3297
PrintInstanceMigration(FILE * file,Map * original_map,Map * new_map)3298 void JSObject::PrintInstanceMigration(FILE* file,
3299 Map* original_map,
3300 Map* new_map) {
3301 if (new_map->is_dictionary_map()) {
3302 PrintF(file, "[migrating to slow]\n");
3303 return;
3304 }
3305 PrintF(file, "[migrating]");
3306 DescriptorArray* o = original_map->instance_descriptors();
3307 DescriptorArray* n = new_map->instance_descriptors();
3308 for (int i = 0; i < original_map->NumberOfOwnDescriptors(); i++) {
3309 Representation o_r = o->GetDetails(i).representation();
3310 Representation n_r = n->GetDetails(i).representation();
3311 if (!o_r.Equals(n_r)) {
3312 String::cast(o->GetKey(i))->PrintOn(file);
3313 PrintF(file, ":%s->%s ", o_r.Mnemonic(), n_r.Mnemonic());
3314 } else if (o->GetDetails(i).location() == kDescriptor &&
3315 n->GetDetails(i).location() == kField) {
3316 Name* name = o->GetKey(i);
3317 if (name->IsString()) {
3318 String::cast(name)->PrintOn(file);
3319 } else {
3320 PrintF(file, "{symbol %p}", static_cast<void*>(name));
3321 }
3322 PrintF(file, " ");
3323 }
3324 }
3325 if (original_map->elements_kind() != new_map->elements_kind()) {
3326 PrintF(file, "elements_kind[%i->%i]", original_map->elements_kind(),
3327 new_map->elements_kind());
3328 }
3329 PrintF(file, "\n");
3330 }
3331
IsUnmodifiedApiObject(Object ** o)3332 bool JSObject::IsUnmodifiedApiObject(Object** o) {
3333 Object* object = *o;
3334 if (object->IsSmi()) return false;
3335 HeapObject* heap_object = HeapObject::cast(object);
3336 if (!object->IsJSObject()) return false;
3337 JSObject* js_object = JSObject::cast(object);
3338 if (!js_object->IsApiWrapper()) return false;
3339 Object* maybe_constructor = js_object->map()->GetConstructor();
3340 if (!maybe_constructor->IsJSFunction()) return false;
3341 JSFunction* constructor = JSFunction::cast(maybe_constructor);
3342 if (js_object->elements()->length() != 0) return false;
3343
3344 return constructor->initial_map() == heap_object->map();
3345 }
3346
HeapObjectShortPrint(std::ostream & os)3347 void HeapObject::HeapObjectShortPrint(std::ostream& os) { // NOLINT
3348 os << AsHex(reinterpret_cast<Address>(this), kPointerHexDigits, true) << " ";
3349
3350 if (IsString()) {
3351 HeapStringAllocator allocator;
3352 StringStream accumulator(&allocator);
3353 String::cast(this)->StringShortPrint(&accumulator);
3354 os << accumulator.ToCString().get();
3355 return;
3356 }
3357 if (IsJSObject()) {
3358 HeapStringAllocator allocator;
3359 StringStream accumulator(&allocator);
3360 JSObject::cast(this)->JSObjectShortPrint(&accumulator);
3361 os << accumulator.ToCString().get();
3362 return;
3363 }
3364 switch (map()->instance_type()) {
3365 case MAP_TYPE: {
3366 os << "<Map";
3367 Map* mapInstance = Map::cast(this);
3368 if (mapInstance->IsJSObjectMap()) {
3369 os << "(" << ElementsKindToString(mapInstance->elements_kind()) << ")";
3370 } else if (mapInstance->instance_size() != kVariableSizeSentinel) {
3371 os << "[" << mapInstance->instance_size() << "]";
3372 }
3373 os << ">";
3374 } break;
3375 case BLOCK_CONTEXT_TYPE:
3376 os << "<BlockContext[" << FixedArray::cast(this)->length() << "]>";
3377 break;
3378 case CATCH_CONTEXT_TYPE:
3379 os << "<CatchContext[" << FixedArray::cast(this)->length() << "]>";
3380 break;
3381 case DEBUG_EVALUATE_CONTEXT_TYPE:
3382 os << "<DebugEvaluateContext[" << FixedArray::cast(this)->length()
3383 << "]>";
3384 break;
3385 case EVAL_CONTEXT_TYPE:
3386 os << "<EvalContext[" << FixedArray::cast(this)->length() << "]>";
3387 break;
3388 case FUNCTION_CONTEXT_TYPE:
3389 os << "<FunctionContext[" << FixedArray::cast(this)->length() << "]>";
3390 break;
3391 case MODULE_CONTEXT_TYPE:
3392 os << "<ModuleContext[" << FixedArray::cast(this)->length() << "]>";
3393 break;
3394 case NATIVE_CONTEXT_TYPE:
3395 os << "<NativeContext[" << FixedArray::cast(this)->length() << "]>";
3396 break;
3397 case SCRIPT_CONTEXT_TYPE:
3398 os << "<ScriptContext[" << FixedArray::cast(this)->length() << "]>";
3399 break;
3400 case WITH_CONTEXT_TYPE:
3401 os << "<WithContext[" << FixedArray::cast(this)->length() << "]>";
3402 break;
3403 case SCRIPT_CONTEXT_TABLE_TYPE:
3404 os << "<ScriptContextTable[" << FixedArray::cast(this)->length() << "]>";
3405 break;
3406 case HASH_TABLE_TYPE:
3407 os << "<HashTable[" << FixedArray::cast(this)->length() << "]>";
3408 break;
3409 case ORDERED_HASH_MAP_TYPE:
3410 os << "<OrderedHashMap[" << FixedArray::cast(this)->length() << "]>";
3411 break;
3412 case ORDERED_HASH_SET_TYPE:
3413 os << "<OrderedHashSet[" << FixedArray::cast(this)->length() << "]>";
3414 break;
3415 case NAME_DICTIONARY_TYPE:
3416 os << "<NameDictionary[" << FixedArray::cast(this)->length() << "]>";
3417 break;
3418 case GLOBAL_DICTIONARY_TYPE:
3419 os << "<GlobalDictionary[" << FixedArray::cast(this)->length() << "]>";
3420 break;
3421 case NUMBER_DICTIONARY_TYPE:
3422 os << "<NumberDictionary[" << FixedArray::cast(this)->length() << "]>";
3423 break;
3424 case SIMPLE_NUMBER_DICTIONARY_TYPE:
3425 os << "<SimpleNumberDictionary[" << FixedArray::cast(this)->length()
3426 << "]>";
3427 break;
3428 case STRING_TABLE_TYPE:
3429 os << "<StringTable[" << FixedArray::cast(this)->length() << "]>";
3430 break;
3431 case FIXED_ARRAY_TYPE:
3432 os << "<FixedArray[" << FixedArray::cast(this)->length() << "]>";
3433 break;
3434 case OBJECT_BOILERPLATE_DESCRIPTION_TYPE:
3435 os << "<ObjectBoilerplateDescription[" << FixedArray::cast(this)->length()
3436 << "]>";
3437 break;
3438 case FIXED_DOUBLE_ARRAY_TYPE:
3439 os << "<FixedDoubleArray[" << FixedDoubleArray::cast(this)->length()
3440 << "]>";
3441 break;
3442 case BYTE_ARRAY_TYPE:
3443 os << "<ByteArray[" << ByteArray::cast(this)->length() << "]>";
3444 break;
3445 case BYTECODE_ARRAY_TYPE:
3446 os << "<BytecodeArray[" << BytecodeArray::cast(this)->length() << "]>";
3447 break;
3448 case DESCRIPTOR_ARRAY_TYPE:
3449 os << "<DescriptorArray[" << DescriptorArray::cast(this)->length()
3450 << "]>";
3451 break;
3452 case TRANSITION_ARRAY_TYPE:
3453 os << "<TransitionArray[" << TransitionArray::cast(this)->length()
3454 << "]>";
3455 break;
3456 case PROPERTY_ARRAY_TYPE:
3457 os << "<PropertyArray[" << PropertyArray::cast(this)->length() << "]>";
3458 break;
3459 case FEEDBACK_CELL_TYPE: {
3460 {
3461 ReadOnlyRoots roots = GetReadOnlyRoots();
3462 os << "<FeedbackCell[";
3463 if (map() == roots.no_closures_cell_map()) {
3464 os << "no closures";
3465 } else if (map() == roots.one_closure_cell_map()) {
3466 os << "one closure";
3467 } else if (map() == roots.many_closures_cell_map()) {
3468 os << "many closures";
3469 } else {
3470 os << "!!!INVALID MAP!!!";
3471 }
3472 os << "]>";
3473 }
3474 break;
3475 }
3476 case FEEDBACK_VECTOR_TYPE:
3477 os << "<FeedbackVector[" << FeedbackVector::cast(this)->length() << "]>";
3478 break;
3479 case FREE_SPACE_TYPE:
3480 os << "<FreeSpace[" << FreeSpace::cast(this)->size() << "]>";
3481 break;
3482 #define TYPED_ARRAY_SHORT_PRINT(Type, type, TYPE, ctype) \
3483 case FIXED_##TYPE##_ARRAY_TYPE: \
3484 os << "<Fixed" #Type "Array[" << Fixed##Type##Array::cast(this)->length() \
3485 << "]>"; \
3486 break;
3487
3488 TYPED_ARRAYS(TYPED_ARRAY_SHORT_PRINT)
3489 #undef TYPED_ARRAY_SHORT_PRINT
3490
3491 case PRE_PARSED_SCOPE_DATA_TYPE: {
3492 PreParsedScopeData* data = PreParsedScopeData::cast(this);
3493 os << "<PreParsedScopeData[" << data->length() << "]>";
3494 break;
3495 }
3496
3497 case UNCOMPILED_DATA_WITHOUT_PRE_PARSED_SCOPE_TYPE: {
3498 UncompiledDataWithoutPreParsedScope* data =
3499 UncompiledDataWithoutPreParsedScope::cast(this);
3500 os << "<UncompiledDataWithoutPreParsedScope (" << data->start_position()
3501 << ", " << data->end_position() << ")]>";
3502 break;
3503 }
3504
3505 case UNCOMPILED_DATA_WITH_PRE_PARSED_SCOPE_TYPE: {
3506 UncompiledDataWithPreParsedScope* data =
3507 UncompiledDataWithPreParsedScope::cast(this);
3508 os << "<UncompiledDataWithPreParsedScope (" << data->start_position()
3509 << ", " << data->end_position()
3510 << ") preparsed=" << Brief(data->pre_parsed_scope_data()) << ">";
3511 break;
3512 }
3513
3514 case SHARED_FUNCTION_INFO_TYPE: {
3515 SharedFunctionInfo* shared = SharedFunctionInfo::cast(this);
3516 std::unique_ptr<char[]> debug_name = shared->DebugName()->ToCString();
3517 if (debug_name[0] != 0) {
3518 os << "<SharedFunctionInfo " << debug_name.get() << ">";
3519 } else {
3520 os << "<SharedFunctionInfo>";
3521 }
3522 break;
3523 }
3524 case JS_MESSAGE_OBJECT_TYPE:
3525 os << "<JSMessageObject>";
3526 break;
3527 #define MAKE_STRUCT_CASE(NAME, Name, name) \
3528 case NAME##_TYPE: \
3529 os << "<" #Name; \
3530 Name::cast(this)->BriefPrintDetails(os); \
3531 os << ">"; \
3532 break;
3533 STRUCT_LIST(MAKE_STRUCT_CASE)
3534 #undef MAKE_STRUCT_CASE
3535 case ALLOCATION_SITE_TYPE: {
3536 os << "<AllocationSite";
3537 AllocationSite::cast(this)->BriefPrintDetails(os);
3538 os << ">";
3539 break;
3540 }
3541 case SCOPE_INFO_TYPE: {
3542 ScopeInfo* scope = ScopeInfo::cast(this);
3543 os << "<ScopeInfo";
3544 if (scope->length()) os << " " << scope->scope_type() << " ";
3545 os << "[" << scope->length() << "]>";
3546 break;
3547 }
3548 case CODE_TYPE: {
3549 Code* code = Code::cast(this);
3550 os << "<Code " << Code::Kind2String(code->kind());
3551 if (code->is_stub()) {
3552 os << " " << CodeStub::MajorName(CodeStub::GetMajorKey(code));
3553 } else if (code->is_builtin()) {
3554 os << " " << Builtins::name(code->builtin_index());
3555 }
3556 os << ">";
3557 break;
3558 }
3559 case ODDBALL_TYPE: {
3560 if (IsUndefined()) {
3561 os << "<undefined>";
3562 } else if (IsTheHole()) {
3563 os << "<the_hole>";
3564 } else if (IsNull()) {
3565 os << "<null>";
3566 } else if (IsTrue()) {
3567 os << "<true>";
3568 } else if (IsFalse()) {
3569 os << "<false>";
3570 } else {
3571 os << "<Odd Oddball: ";
3572 os << Oddball::cast(this)->to_string()->ToCString().get();
3573 os << ">";
3574 }
3575 break;
3576 }
3577 case SYMBOL_TYPE: {
3578 Symbol* symbol = Symbol::cast(this);
3579 symbol->SymbolShortPrint(os);
3580 break;
3581 }
3582 case HEAP_NUMBER_TYPE: {
3583 os << "<HeapNumber ";
3584 HeapNumber::cast(this)->HeapNumberPrint(os);
3585 os << ">";
3586 break;
3587 }
3588 case MUTABLE_HEAP_NUMBER_TYPE: {
3589 os << "<MutableHeapNumber ";
3590 MutableHeapNumber::cast(this)->MutableHeapNumberPrint(os);
3591 os << '>';
3592 break;
3593 }
3594 case BIGINT_TYPE: {
3595 os << "<BigInt ";
3596 BigInt::cast(this)->BigIntShortPrint(os);
3597 os << ">";
3598 break;
3599 }
3600 case JS_PROXY_TYPE:
3601 os << "<JSProxy>";
3602 break;
3603 case FOREIGN_TYPE:
3604 os << "<Foreign>";
3605 break;
3606 case CELL_TYPE: {
3607 os << "<Cell value= ";
3608 HeapStringAllocator allocator;
3609 StringStream accumulator(&allocator);
3610 Cell::cast(this)->value()->ShortPrint(&accumulator);
3611 os << accumulator.ToCString().get();
3612 os << '>';
3613 break;
3614 }
3615 case PROPERTY_CELL_TYPE: {
3616 PropertyCell* cell = PropertyCell::cast(this);
3617 os << "<PropertyCell name=";
3618 cell->name()->ShortPrint(os);
3619 os << " value=";
3620 HeapStringAllocator allocator;
3621 StringStream accumulator(&allocator);
3622 cell->value()->ShortPrint(&accumulator);
3623 os << accumulator.ToCString().get();
3624 os << '>';
3625 break;
3626 }
3627 case CALL_HANDLER_INFO_TYPE: {
3628 CallHandlerInfo* info = CallHandlerInfo::cast(this);
3629 os << "<CallHandlerInfo ";
3630 os << "callback= " << Brief(info->callback());
3631 os << ", js_callback= " << Brief(info->js_callback());
3632 os << ", data= " << Brief(info->data());
3633 if (info->IsSideEffectFreeCallHandlerInfo()) {
3634 os << ", side_effect_free= true>";
3635 } else {
3636 os << ", side_effect_free= false>";
3637 }
3638 break;
3639 }
3640 default:
3641 os << "<Other heap object (" << map()->instance_type() << ")>";
3642 break;
3643 }
3644 }
3645
BriefPrintDetails(std::ostream & os)3646 void Struct::BriefPrintDetails(std::ostream& os) {}
3647
BriefPrintDetails(std::ostream & os)3648 void Tuple2::BriefPrintDetails(std::ostream& os) {
3649 os << " " << Brief(value1()) << ", " << Brief(value2());
3650 }
3651
BriefPrintDetails(std::ostream & os)3652 void Tuple3::BriefPrintDetails(std::ostream& os) {
3653 os << " " << Brief(value1()) << ", " << Brief(value2()) << ", "
3654 << Brief(value3());
3655 }
3656
BriefPrintDetails(std::ostream & os)3657 void ArrayBoilerplateDescription::BriefPrintDetails(std::ostream& os) {
3658 os << " " << elements_kind() << ", " << Brief(constant_elements());
3659 }
3660
BriefPrintDetails(std::ostream & os)3661 void CallableTask::BriefPrintDetails(std::ostream& os) {
3662 os << " callable=" << Brief(callable());
3663 }
3664
Iterate(ObjectVisitor * v)3665 void HeapObject::Iterate(ObjectVisitor* v) { IterateFast<ObjectVisitor>(v); }
3666
3667
IterateBody(ObjectVisitor * v)3668 void HeapObject::IterateBody(ObjectVisitor* v) {
3669 Map* m = map();
3670 IterateBodyFast<ObjectVisitor>(m, SizeFromMap(m), v);
3671 }
3672
IterateBody(Map * map,int object_size,ObjectVisitor * v)3673 void HeapObject::IterateBody(Map* map, int object_size, ObjectVisitor* v) {
3674 IterateBodyFast<ObjectVisitor>(map, object_size, v);
3675 }
3676
3677
3678 struct CallIsValidSlot {
3679 template <typename BodyDescriptor>
applyv8::internal::CallIsValidSlot3680 static bool apply(Map* map, HeapObject* obj, int offset, int) {
3681 return BodyDescriptor::IsValidSlot(map, obj, offset);
3682 }
3683 };
3684
IsValidSlot(Map * map,int offset)3685 bool HeapObject::IsValidSlot(Map* map, int offset) {
3686 DCHECK_NE(0, offset);
3687 return BodyDescriptorApply<CallIsValidSlot, bool>(map->instance_type(), map,
3688 this, offset, 0);
3689 }
3690
class_name()3691 String* JSReceiver::class_name() {
3692 ReadOnlyRoots roots = GetReadOnlyRoots();
3693 if (IsFunction()) return roots.Function_string();
3694 if (IsJSArgumentsObject()) return roots.Arguments_string();
3695 if (IsJSArray()) return roots.Array_string();
3696 if (IsJSArrayBuffer()) {
3697 if (JSArrayBuffer::cast(this)->is_shared()) {
3698 return roots.SharedArrayBuffer_string();
3699 }
3700 return roots.ArrayBuffer_string();
3701 }
3702 if (IsJSArrayIterator()) return roots.ArrayIterator_string();
3703 if (IsJSDate()) return roots.Date_string();
3704 if (IsJSError()) return roots.Error_string();
3705 if (IsJSGeneratorObject()) return roots.Generator_string();
3706 if (IsJSMap()) return roots.Map_string();
3707 if (IsJSMapIterator()) return roots.MapIterator_string();
3708 if (IsJSProxy()) {
3709 return map()->is_callable() ? roots.Function_string()
3710 : roots.Object_string();
3711 }
3712 if (IsJSRegExp()) return roots.RegExp_string();
3713 if (IsJSSet()) return roots.Set_string();
3714 if (IsJSSetIterator()) return roots.SetIterator_string();
3715 if (IsJSTypedArray()) {
3716 #define SWITCH_KIND(Type, type, TYPE, ctype) \
3717 if (map()->elements_kind() == TYPE##_ELEMENTS) { \
3718 return roots.Type##Array_string(); \
3719 }
3720 TYPED_ARRAYS(SWITCH_KIND)
3721 #undef SWITCH_KIND
3722 }
3723 if (IsJSValue()) {
3724 Object* value = JSValue::cast(this)->value();
3725 if (value->IsBoolean()) return roots.Boolean_string();
3726 if (value->IsString()) return roots.String_string();
3727 if (value->IsNumber()) return roots.Number_string();
3728 if (value->IsBigInt()) return roots.BigInt_string();
3729 if (value->IsSymbol()) return roots.Symbol_string();
3730 if (value->IsScript()) return roots.Script_string();
3731 UNREACHABLE();
3732 }
3733 if (IsJSWeakMap()) return roots.WeakMap_string();
3734 if (IsJSWeakSet()) return roots.WeakSet_string();
3735 if (IsJSGlobalProxy()) return roots.global_string();
3736
3737 Object* maybe_constructor = map()->GetConstructor();
3738 if (maybe_constructor->IsJSFunction()) {
3739 JSFunction* constructor = JSFunction::cast(maybe_constructor);
3740 if (constructor->shared()->IsApiFunction()) {
3741 maybe_constructor = constructor->shared()->get_api_func_data();
3742 }
3743 }
3744
3745 if (maybe_constructor->IsFunctionTemplateInfo()) {
3746 FunctionTemplateInfo* info = FunctionTemplateInfo::cast(maybe_constructor);
3747 if (info->class_name()->IsString()) return String::cast(info->class_name());
3748 }
3749
3750 return roots.Object_string();
3751 }
3752
CanBeRehashed() const3753 bool HeapObject::CanBeRehashed() const {
3754 DCHECK(NeedsRehashing());
3755 switch (map()->instance_type()) {
3756 case ORDERED_HASH_MAP_TYPE:
3757 case ORDERED_HASH_SET_TYPE:
3758 // TODO(yangguo): actually support rehashing OrderedHash{Map,Set}.
3759 return false;
3760 case NAME_DICTIONARY_TYPE:
3761 case GLOBAL_DICTIONARY_TYPE:
3762 case NUMBER_DICTIONARY_TYPE:
3763 case SIMPLE_NUMBER_DICTIONARY_TYPE:
3764 case STRING_TABLE_TYPE:
3765 return true;
3766 case DESCRIPTOR_ARRAY_TYPE:
3767 return true;
3768 case TRANSITION_ARRAY_TYPE:
3769 return true;
3770 case SMALL_ORDERED_HASH_MAP_TYPE:
3771 return SmallOrderedHashMap::cast(this)->NumberOfElements() == 0;
3772 case SMALL_ORDERED_HASH_SET_TYPE:
3773 return SmallOrderedHashMap::cast(this)->NumberOfElements() == 0;
3774 default:
3775 return false;
3776 }
3777 return false;
3778 }
3779
RehashBasedOnMap(Isolate * isolate)3780 void HeapObject::RehashBasedOnMap(Isolate* isolate) {
3781 switch (map()->instance_type()) {
3782 case HASH_TABLE_TYPE:
3783 UNREACHABLE();
3784 break;
3785 case NAME_DICTIONARY_TYPE:
3786 NameDictionary::cast(this)->Rehash(isolate);
3787 break;
3788 case GLOBAL_DICTIONARY_TYPE:
3789 GlobalDictionary::cast(this)->Rehash(isolate);
3790 break;
3791 case NUMBER_DICTIONARY_TYPE:
3792 NumberDictionary::cast(this)->Rehash(isolate);
3793 break;
3794 case SIMPLE_NUMBER_DICTIONARY_TYPE:
3795 SimpleNumberDictionary::cast(this)->Rehash(isolate);
3796 break;
3797 case STRING_TABLE_TYPE:
3798 StringTable::cast(this)->Rehash(isolate);
3799 break;
3800 case DESCRIPTOR_ARRAY_TYPE:
3801 DCHECK_LE(1, DescriptorArray::cast(this)->number_of_descriptors());
3802 DescriptorArray::cast(this)->Sort();
3803 break;
3804 case TRANSITION_ARRAY_TYPE:
3805 TransitionArray::cast(this)->Sort();
3806 break;
3807 case SMALL_ORDERED_HASH_MAP_TYPE:
3808 DCHECK_EQ(0, SmallOrderedHashMap::cast(this)->NumberOfElements());
3809 break;
3810 case SMALL_ORDERED_HASH_SET_TYPE:
3811 DCHECK_EQ(0, SmallOrderedHashSet::cast(this)->NumberOfElements());
3812 break;
3813 default:
3814 break;
3815 }
3816 }
3817
3818 namespace {
GetConstructorHelper(Handle<JSReceiver> receiver)3819 std::pair<MaybeHandle<JSFunction>, Handle<String>> GetConstructorHelper(
3820 Handle<JSReceiver> receiver) {
3821 Isolate* isolate = receiver->GetIsolate();
3822
3823 // If the object was instantiated simply with base == new.target, the
3824 // constructor on the map provides the most accurate name.
3825 // Don't provide the info for prototypes, since their constructors are
3826 // reclaimed and replaced by Object in OptimizeAsPrototype.
3827 if (!receiver->IsJSProxy() && receiver->map()->new_target_is_base() &&
3828 !receiver->map()->is_prototype_map()) {
3829 Object* maybe_constructor = receiver->map()->GetConstructor();
3830 if (maybe_constructor->IsJSFunction()) {
3831 JSFunction* constructor = JSFunction::cast(maybe_constructor);
3832 String* name = constructor->shared()->DebugName();
3833 if (name->length() != 0 &&
3834 !name->Equals(ReadOnlyRoots(isolate).Object_string())) {
3835 return std::make_pair(handle(constructor, isolate),
3836 handle(name, isolate));
3837 }
3838 } else if (maybe_constructor->IsFunctionTemplateInfo()) {
3839 FunctionTemplateInfo* info =
3840 FunctionTemplateInfo::cast(maybe_constructor);
3841 if (info->class_name()->IsString()) {
3842 return std::make_pair(
3843 MaybeHandle<JSFunction>(),
3844 handle(String::cast(info->class_name()), isolate));
3845 }
3846 }
3847 }
3848
3849 Handle<Object> maybe_tag = JSReceiver::GetDataProperty(
3850 receiver, isolate->factory()->to_string_tag_symbol());
3851 if (maybe_tag->IsString())
3852 return std::make_pair(MaybeHandle<JSFunction>(),
3853 Handle<String>::cast(maybe_tag));
3854
3855 PrototypeIterator iter(isolate, receiver);
3856 if (iter.IsAtEnd()) {
3857 return std::make_pair(MaybeHandle<JSFunction>(),
3858 handle(receiver->class_name(), isolate));
3859 }
3860
3861 Handle<JSReceiver> start = PrototypeIterator::GetCurrent<JSReceiver>(iter);
3862 LookupIterator it(receiver, isolate->factory()->constructor_string(), start,
3863 LookupIterator::PROTOTYPE_CHAIN_SKIP_INTERCEPTOR);
3864 Handle<Object> maybe_constructor = JSReceiver::GetDataProperty(&it);
3865 if (maybe_constructor->IsJSFunction()) {
3866 JSFunction* constructor = JSFunction::cast(*maybe_constructor);
3867 String* name = constructor->shared()->DebugName();
3868
3869 if (name->length() != 0 &&
3870 !name->Equals(ReadOnlyRoots(isolate).Object_string())) {
3871 return std::make_pair(handle(constructor, isolate),
3872 handle(name, isolate));
3873 }
3874 }
3875
3876 return std::make_pair(MaybeHandle<JSFunction>(),
3877 handle(receiver->class_name(), isolate));
3878 }
3879 } // anonymous namespace
3880
3881 // static
GetConstructor(Handle<JSReceiver> receiver)3882 MaybeHandle<JSFunction> JSReceiver::GetConstructor(
3883 Handle<JSReceiver> receiver) {
3884 return GetConstructorHelper(receiver).first;
3885 }
3886
3887 // static
GetConstructorName(Handle<JSReceiver> receiver)3888 Handle<String> JSReceiver::GetConstructorName(Handle<JSReceiver> receiver) {
3889 return GetConstructorHelper(receiver).second;
3890 }
3891
GetCreationContext()3892 Handle<Context> JSReceiver::GetCreationContext() {
3893 JSReceiver* receiver = this;
3894 // Externals are JSObjects with null as a constructor.
3895 DCHECK(!receiver->IsExternal(GetIsolate()));
3896 Object* constructor = receiver->map()->GetConstructor();
3897 JSFunction* function;
3898 if (constructor->IsJSFunction()) {
3899 function = JSFunction::cast(constructor);
3900 } else if (constructor->IsFunctionTemplateInfo()) {
3901 // Remote objects don't have a creation context.
3902 return Handle<Context>::null();
3903 } else {
3904 // Functions have null as a constructor,
3905 // but any JSFunction knows its context immediately.
3906 CHECK(receiver->IsJSFunction());
3907 function = JSFunction::cast(receiver);
3908 }
3909
3910 return function->has_context()
3911 ? Handle<Context>(function->context()->native_context(),
3912 receiver->GetIsolate())
3913 : Handle<Context>::null();
3914 }
3915
3916 // static
WrapFieldType(Isolate * isolate,Handle<FieldType> type)3917 MaybeObjectHandle Map::WrapFieldType(Isolate* isolate, Handle<FieldType> type) {
3918 if (type->IsClass()) {
3919 return MaybeObjectHandle::Weak(type->AsClass(), isolate);
3920 }
3921 return MaybeObjectHandle(type);
3922 }
3923
3924 // static
UnwrapFieldType(MaybeObject * wrapped_type)3925 FieldType* Map::UnwrapFieldType(MaybeObject* wrapped_type) {
3926 if (wrapped_type->IsClearedWeakHeapObject()) {
3927 return FieldType::None();
3928 }
3929 HeapObject* heap_object;
3930 if (wrapped_type->ToWeakHeapObject(&heap_object)) {
3931 return FieldType::cast(heap_object);
3932 }
3933 return FieldType::cast(wrapped_type->ToObject());
3934 }
3935
CopyWithField(Isolate * isolate,Handle<Map> map,Handle<Name> name,Handle<FieldType> type,PropertyAttributes attributes,PropertyConstness constness,Representation representation,TransitionFlag flag)3936 MaybeHandle<Map> Map::CopyWithField(Isolate* isolate, Handle<Map> map,
3937 Handle<Name> name, Handle<FieldType> type,
3938 PropertyAttributes attributes,
3939 PropertyConstness constness,
3940 Representation representation,
3941 TransitionFlag flag) {
3942 DCHECK(DescriptorArray::kNotFound ==
3943 map->instance_descriptors()->Search(
3944 *name, map->NumberOfOwnDescriptors()));
3945
3946 // Ensure the descriptor array does not get too big.
3947 if (map->NumberOfOwnDescriptors() >= kMaxNumberOfDescriptors) {
3948 return MaybeHandle<Map>();
3949 }
3950
3951 // Compute the new index for new field.
3952 int index = map->NextFreePropertyIndex();
3953
3954 if (map->instance_type() == JS_CONTEXT_EXTENSION_OBJECT_TYPE) {
3955 constness = PropertyConstness::kMutable;
3956 representation = Representation::Tagged();
3957 type = FieldType::Any(isolate);
3958 } else {
3959 Map::GeneralizeIfCanHaveTransitionableFastElementsKind(
3960 isolate, map->instance_type(), &constness, &representation, &type);
3961 }
3962
3963 MaybeObjectHandle wrapped_type = WrapFieldType(isolate, type);
3964
3965 DCHECK_IMPLIES(!FLAG_track_constant_fields,
3966 constness == PropertyConstness::kMutable);
3967 Descriptor d = Descriptor::DataField(name, index, attributes, constness,
3968 representation, wrapped_type);
3969 Handle<Map> new_map = Map::CopyAddDescriptor(isolate, map, &d, flag);
3970 new_map->AccountAddedPropertyField();
3971 return new_map;
3972 }
3973
CopyWithConstant(Isolate * isolate,Handle<Map> map,Handle<Name> name,Handle<Object> constant,PropertyAttributes attributes,TransitionFlag flag)3974 MaybeHandle<Map> Map::CopyWithConstant(Isolate* isolate, Handle<Map> map,
3975 Handle<Name> name,
3976 Handle<Object> constant,
3977 PropertyAttributes attributes,
3978 TransitionFlag flag) {
3979 // Ensure the descriptor array does not get too big.
3980 if (map->NumberOfOwnDescriptors() >= kMaxNumberOfDescriptors) {
3981 return MaybeHandle<Map>();
3982 }
3983
3984 if (FLAG_track_constant_fields) {
3985 Representation representation = constant->OptimalRepresentation();
3986 Handle<FieldType> type = constant->OptimalType(isolate, representation);
3987 return CopyWithField(isolate, map, name, type, attributes,
3988 PropertyConstness::kConst, representation, flag);
3989 } else {
3990 // Allocate new instance descriptors with (name, constant) added.
3991 Descriptor d =
3992 Descriptor::DataConstant(isolate, name, 0, constant, attributes);
3993 Handle<Map> new_map = Map::CopyAddDescriptor(isolate, map, &d, flag);
3994 return new_map;
3995 }
3996 }
3997
Mnemonic() const3998 const char* Representation::Mnemonic() const {
3999 switch (kind_) {
4000 case kNone: return "v";
4001 case kTagged: return "t";
4002 case kSmi: return "s";
4003 case kDouble: return "d";
4004 case kInteger32: return "i";
4005 case kHeapObject: return "h";
4006 case kExternal: return "x";
4007 default:
4008 UNREACHABLE();
4009 }
4010 }
4011
TransitionRemovesTaggedField(Map * target) const4012 bool Map::TransitionRemovesTaggedField(Map* target) const {
4013 int inobject = NumberOfFields();
4014 int target_inobject = target->NumberOfFields();
4015 for (int i = target_inobject; i < inobject; i++) {
4016 FieldIndex index = FieldIndex::ForPropertyIndex(this, i);
4017 if (!IsUnboxedDoubleField(index)) return true;
4018 }
4019 return false;
4020 }
4021
TransitionChangesTaggedFieldToUntaggedField(Map * target) const4022 bool Map::TransitionChangesTaggedFieldToUntaggedField(Map* target) const {
4023 int inobject = NumberOfFields();
4024 int target_inobject = target->NumberOfFields();
4025 int limit = Min(inobject, target_inobject);
4026 for (int i = 0; i < limit; i++) {
4027 FieldIndex index = FieldIndex::ForPropertyIndex(target, i);
4028 if (!IsUnboxedDoubleField(index) && target->IsUnboxedDoubleField(index)) {
4029 return true;
4030 }
4031 }
4032 return false;
4033 }
4034
TransitionRequiresSynchronizationWithGC(Map * target) const4035 bool Map::TransitionRequiresSynchronizationWithGC(Map* target) const {
4036 return TransitionRemovesTaggedField(target) ||
4037 TransitionChangesTaggedFieldToUntaggedField(target);
4038 }
4039
InstancesNeedRewriting(Map * target) const4040 bool Map::InstancesNeedRewriting(Map* target) const {
4041 int target_number_of_fields = target->NumberOfFields();
4042 int target_inobject = target->GetInObjectProperties();
4043 int target_unused = target->UnusedPropertyFields();
4044 int old_number_of_fields;
4045
4046 return InstancesNeedRewriting(target, target_number_of_fields,
4047 target_inobject, target_unused,
4048 &old_number_of_fields);
4049 }
4050
InstancesNeedRewriting(Map * target,int target_number_of_fields,int target_inobject,int target_unused,int * old_number_of_fields) const4051 bool Map::InstancesNeedRewriting(Map* target, int target_number_of_fields,
4052 int target_inobject, int target_unused,
4053 int* old_number_of_fields) const {
4054 // If fields were added (or removed), rewrite the instance.
4055 *old_number_of_fields = NumberOfFields();
4056 DCHECK(target_number_of_fields >= *old_number_of_fields);
4057 if (target_number_of_fields != *old_number_of_fields) return true;
4058
4059 // If smi descriptors were replaced by double descriptors, rewrite.
4060 DescriptorArray* old_desc = instance_descriptors();
4061 DescriptorArray* new_desc = target->instance_descriptors();
4062 int limit = NumberOfOwnDescriptors();
4063 for (int i = 0; i < limit; i++) {
4064 if (new_desc->GetDetails(i).representation().IsDouble() !=
4065 old_desc->GetDetails(i).representation().IsDouble()) {
4066 return true;
4067 }
4068 }
4069
4070 // If no fields were added, and no inobject properties were removed, setting
4071 // the map is sufficient.
4072 if (target_inobject == GetInObjectProperties()) return false;
4073 // In-object slack tracking may have reduced the object size of the new map.
4074 // In that case, succeed if all existing fields were inobject, and they still
4075 // fit within the new inobject size.
4076 DCHECK(target_inobject < GetInObjectProperties());
4077 if (target_number_of_fields <= target_inobject) {
4078 DCHECK(target_number_of_fields + target_unused == target_inobject);
4079 return false;
4080 }
4081 // Otherwise, properties will need to be moved to the backing store.
4082 return true;
4083 }
4084
4085
4086 // static
UpdatePrototypeUserRegistration(Handle<Map> old_map,Handle<Map> new_map,Isolate * isolate)4087 void JSObject::UpdatePrototypeUserRegistration(Handle<Map> old_map,
4088 Handle<Map> new_map,
4089 Isolate* isolate) {
4090 DCHECK(old_map->is_prototype_map());
4091 DCHECK(new_map->is_prototype_map());
4092 bool was_registered = JSObject::UnregisterPrototypeUser(old_map, isolate);
4093 new_map->set_prototype_info(old_map->prototype_info());
4094 old_map->set_prototype_info(Smi::kZero);
4095 if (FLAG_trace_prototype_users) {
4096 PrintF("Moving prototype_info %p from map %p to map %p.\n",
4097 reinterpret_cast<void*>(new_map->prototype_info()),
4098 reinterpret_cast<void*>(*old_map),
4099 reinterpret_cast<void*>(*new_map));
4100 }
4101 if (was_registered) {
4102 if (new_map->prototype_info()->IsPrototypeInfo()) {
4103 // The new map isn't registered with its prototype yet; reflect this fact
4104 // in the PrototypeInfo it just inherited from the old map.
4105 PrototypeInfo::cast(new_map->prototype_info())
4106 ->set_registry_slot(PrototypeInfo::UNREGISTERED);
4107 }
4108 JSObject::LazyRegisterPrototypeUser(new_map, isolate);
4109 }
4110 }
4111
4112 namespace {
4113 // To migrate a fast instance to a fast map:
4114 // - First check whether the instance needs to be rewritten. If not, simply
4115 // change the map.
4116 // - Otherwise, allocate a fixed array large enough to hold all fields, in
4117 // addition to unused space.
4118 // - Copy all existing properties in, in the following order: backing store
4119 // properties, unused fields, inobject properties.
4120 // - If all allocation succeeded, commit the state atomically:
4121 // * Copy inobject properties from the backing store back into the object.
4122 // * Trim the difference in instance size of the object. This also cleanly
4123 // frees inobject properties that moved to the backing store.
4124 // * If there are properties left in the backing store, trim of the space used
4125 // to temporarily store the inobject properties.
4126 // * If there are properties left in the backing store, install the backing
4127 // store.
MigrateFastToFast(Handle<JSObject> object,Handle<Map> new_map)4128 void MigrateFastToFast(Handle<JSObject> object, Handle<Map> new_map) {
4129 Isolate* isolate = object->GetIsolate();
4130 Handle<Map> old_map(object->map(), isolate);
4131 // In case of a regular transition.
4132 if (new_map->GetBackPointer() == *old_map) {
4133 // If the map does not add named properties, simply set the map.
4134 if (old_map->NumberOfOwnDescriptors() ==
4135 new_map->NumberOfOwnDescriptors()) {
4136 object->synchronized_set_map(*new_map);
4137 return;
4138 }
4139
4140 PropertyDetails details = new_map->GetLastDescriptorDetails();
4141 int target_index = details.field_index() - new_map->GetInObjectProperties();
4142 int property_array_length = object->property_array()->length();
4143 bool have_space = old_map->UnusedPropertyFields() > 0 ||
4144 (details.location() == kField && target_index >= 0 &&
4145 property_array_length > target_index);
4146 // Either new_map adds an kDescriptor property, or a kField property for
4147 // which there is still space, and which does not require a mutable double
4148 // box (an out-of-object double).
4149 if (details.location() == kDescriptor ||
4150 (have_space && ((FLAG_unbox_double_fields && target_index < 0) ||
4151 !details.representation().IsDouble()))) {
4152 object->synchronized_set_map(*new_map);
4153 return;
4154 }
4155
4156 // If there is still space in the object, we need to allocate a mutable
4157 // double box.
4158 if (have_space) {
4159 FieldIndex index =
4160 FieldIndex::ForDescriptor(*new_map, new_map->LastAdded());
4161 DCHECK(details.representation().IsDouble());
4162 DCHECK(!new_map->IsUnboxedDoubleField(index));
4163 auto value = isolate->factory()->NewMutableHeapNumberWithHoleNaN();
4164 object->RawFastPropertyAtPut(index, *value);
4165 object->synchronized_set_map(*new_map);
4166 return;
4167 }
4168
4169 // This migration is a transition from a map that has run out of property
4170 // space. Extend the backing store.
4171 int grow_by = new_map->UnusedPropertyFields() + 1;
4172 Handle<PropertyArray> old_storage(object->property_array(), isolate);
4173 Handle<PropertyArray> new_storage =
4174 isolate->factory()->CopyPropertyArrayAndGrow(old_storage, grow_by);
4175
4176 // Properly initialize newly added property.
4177 Handle<Object> value;
4178 if (details.representation().IsDouble()) {
4179 value = isolate->factory()->NewMutableHeapNumberWithHoleNaN();
4180 } else {
4181 value = isolate->factory()->uninitialized_value();
4182 }
4183 DCHECK_EQ(kField, details.location());
4184 DCHECK_EQ(kData, details.kind());
4185 DCHECK_GE(target_index, 0); // Must be a backing store index.
4186 new_storage->set(target_index, *value);
4187
4188 // From here on we cannot fail and we shouldn't GC anymore.
4189 DisallowHeapAllocation no_allocation;
4190
4191 // Set the new property value and do the map transition.
4192 object->SetProperties(*new_storage);
4193 object->synchronized_set_map(*new_map);
4194 return;
4195 }
4196
4197 int old_number_of_fields;
4198 int number_of_fields = new_map->NumberOfFields();
4199 int inobject = new_map->GetInObjectProperties();
4200 int unused = new_map->UnusedPropertyFields();
4201
4202 // Nothing to do if no functions were converted to fields and no smis were
4203 // converted to doubles.
4204 if (!old_map->InstancesNeedRewriting(*new_map, number_of_fields, inobject,
4205 unused, &old_number_of_fields)) {
4206 object->synchronized_set_map(*new_map);
4207 return;
4208 }
4209
4210 int total_size = number_of_fields + unused;
4211 int external = total_size - inobject;
4212 Handle<PropertyArray> array = isolate->factory()->NewPropertyArray(external);
4213
4214 // We use this array to temporarily store the inobject properties.
4215 Handle<FixedArray> inobject_props =
4216 isolate->factory()->NewFixedArray(inobject);
4217
4218 Handle<DescriptorArray> old_descriptors(old_map->instance_descriptors(),
4219 isolate);
4220 Handle<DescriptorArray> new_descriptors(new_map->instance_descriptors(),
4221 isolate);
4222 int old_nof = old_map->NumberOfOwnDescriptors();
4223 int new_nof = new_map->NumberOfOwnDescriptors();
4224
4225 // This method only supports generalizing instances to at least the same
4226 // number of properties.
4227 DCHECK(old_nof <= new_nof);
4228
4229 for (int i = 0; i < old_nof; i++) {
4230 PropertyDetails details = new_descriptors->GetDetails(i);
4231 if (details.location() != kField) continue;
4232 DCHECK_EQ(kData, details.kind());
4233 PropertyDetails old_details = old_descriptors->GetDetails(i);
4234 Representation old_representation = old_details.representation();
4235 Representation representation = details.representation();
4236 Handle<Object> value;
4237 if (old_details.location() == kDescriptor) {
4238 if (old_details.kind() == kAccessor) {
4239 // In case of kAccessor -> kData property reconfiguration, the property
4240 // must already be prepared for data of certain type.
4241 DCHECK(!details.representation().IsNone());
4242 if (details.representation().IsDouble()) {
4243 value = isolate->factory()->NewMutableHeapNumberWithHoleNaN();
4244 } else {
4245 value = isolate->factory()->uninitialized_value();
4246 }
4247 } else {
4248 DCHECK_EQ(kData, old_details.kind());
4249 value = handle(old_descriptors->GetStrongValue(i), isolate);
4250 DCHECK(!old_representation.IsDouble() && !representation.IsDouble());
4251 }
4252 } else {
4253 DCHECK_EQ(kField, old_details.location());
4254 FieldIndex index = FieldIndex::ForDescriptor(*old_map, i);
4255 if (object->IsUnboxedDoubleField(index)) {
4256 uint64_t old_bits = object->RawFastDoublePropertyAsBitsAt(index);
4257 if (representation.IsDouble()) {
4258 value = isolate->factory()->NewMutableHeapNumberFromBits(old_bits);
4259 } else {
4260 value = isolate->factory()->NewHeapNumberFromBits(old_bits);
4261 }
4262 } else {
4263 value = handle(object->RawFastPropertyAt(index), isolate);
4264 if (!old_representation.IsDouble() && representation.IsDouble()) {
4265 DCHECK_IMPLIES(old_representation.IsNone(),
4266 value->IsUninitialized(isolate));
4267 value = Object::NewStorageFor(isolate, value, representation);
4268 } else if (old_representation.IsDouble() &&
4269 !representation.IsDouble()) {
4270 value = Object::WrapForRead(isolate, value, old_representation);
4271 }
4272 }
4273 }
4274 DCHECK(!(representation.IsDouble() && value->IsSmi()));
4275 int target_index = new_descriptors->GetFieldIndex(i);
4276 if (target_index < inobject) {
4277 inobject_props->set(target_index, *value);
4278 } else {
4279 array->set(target_index - inobject, *value);
4280 }
4281 }
4282
4283 for (int i = old_nof; i < new_nof; i++) {
4284 PropertyDetails details = new_descriptors->GetDetails(i);
4285 if (details.location() != kField) continue;
4286 DCHECK_EQ(kData, details.kind());
4287 Handle<Object> value;
4288 if (details.representation().IsDouble()) {
4289 value = isolate->factory()->NewMutableHeapNumberWithHoleNaN();
4290 } else {
4291 value = isolate->factory()->uninitialized_value();
4292 }
4293 int target_index = new_descriptors->GetFieldIndex(i);
4294 if (target_index < inobject) {
4295 inobject_props->set(target_index, *value);
4296 } else {
4297 array->set(target_index - inobject, *value);
4298 }
4299 }
4300
4301 // From here on we cannot fail and we shouldn't GC anymore.
4302 DisallowHeapAllocation no_allocation;
4303
4304 Heap* heap = isolate->heap();
4305
4306 int old_instance_size = old_map->instance_size();
4307
4308 heap->NotifyObjectLayoutChange(*object, old_instance_size, no_allocation);
4309
4310 // Copy (real) inobject properties. If necessary, stop at number_of_fields to
4311 // avoid overwriting |one_pointer_filler_map|.
4312 int limit = Min(inobject, number_of_fields);
4313 for (int i = 0; i < limit; i++) {
4314 FieldIndex index = FieldIndex::ForPropertyIndex(*new_map, i);
4315 Object* value = inobject_props->get(i);
4316 // Can't use JSObject::FastPropertyAtPut() because proper map was not set
4317 // yet.
4318 if (new_map->IsUnboxedDoubleField(index)) {
4319 DCHECK(value->IsMutableHeapNumber());
4320 // Ensure that all bits of the double value are preserved.
4321 object->RawFastDoublePropertyAsBitsAtPut(
4322 index, MutableHeapNumber::cast(value)->value_as_bits());
4323 if (i < old_number_of_fields && !old_map->IsUnboxedDoubleField(index)) {
4324 // Transition from tagged to untagged slot.
4325 heap->ClearRecordedSlot(*object,
4326 HeapObject::RawField(*object, index.offset()));
4327 } else {
4328 DCHECK(!heap->HasRecordedSlot(
4329 *object, HeapObject::RawField(*object, index.offset())));
4330 }
4331 } else {
4332 object->RawFastPropertyAtPut(index, value);
4333 }
4334 }
4335
4336 object->SetProperties(*array);
4337
4338 // Create filler object past the new instance size.
4339 int new_instance_size = new_map->instance_size();
4340 int instance_size_delta = old_instance_size - new_instance_size;
4341 DCHECK_GE(instance_size_delta, 0);
4342
4343 if (instance_size_delta > 0) {
4344 Address address = object->address();
4345 heap->CreateFillerObjectAt(address + new_instance_size, instance_size_delta,
4346 ClearRecordedSlots::kYes);
4347 }
4348
4349 // We are storing the new map using release store after creating a filler for
4350 // the left-over space to avoid races with the sweeper thread.
4351 object->synchronized_set_map(*new_map);
4352 }
4353
MigrateFastToSlow(Handle<JSObject> object,Handle<Map> new_map,int expected_additional_properties)4354 void MigrateFastToSlow(Handle<JSObject> object, Handle<Map> new_map,
4355 int expected_additional_properties) {
4356 // The global object is always normalized.
4357 DCHECK(!object->IsJSGlobalObject());
4358 // JSGlobalProxy must never be normalized
4359 DCHECK(!object->IsJSGlobalProxy());
4360
4361 DCHECK_IMPLIES(new_map->is_prototype_map(),
4362 Map::IsPrototypeChainInvalidated(*new_map));
4363
4364 Isolate* isolate = object->GetIsolate();
4365 HandleScope scope(isolate);
4366 Handle<Map> map(object->map(), isolate);
4367
4368 // Allocate new content.
4369 int real_size = map->NumberOfOwnDescriptors();
4370 int property_count = real_size;
4371 if (expected_additional_properties > 0) {
4372 property_count += expected_additional_properties;
4373 } else {
4374 // Make space for two more properties.
4375 property_count += NameDictionary::kInitialCapacity;
4376 }
4377 Handle<NameDictionary> dictionary =
4378 NameDictionary::New(isolate, property_count);
4379
4380 Handle<DescriptorArray> descs(map->instance_descriptors(), isolate);
4381 for (int i = 0; i < real_size; i++) {
4382 PropertyDetails details = descs->GetDetails(i);
4383 Handle<Name> key(descs->GetKey(i), isolate);
4384 Handle<Object> value;
4385 if (details.location() == kField) {
4386 FieldIndex index = FieldIndex::ForDescriptor(*map, i);
4387 if (details.kind() == kData) {
4388 if (object->IsUnboxedDoubleField(index)) {
4389 double old_value = object->RawFastDoublePropertyAt(index);
4390 value = isolate->factory()->NewHeapNumber(old_value);
4391 } else {
4392 value = handle(object->RawFastPropertyAt(index), isolate);
4393 if (details.representation().IsDouble()) {
4394 DCHECK(value->IsMutableHeapNumber());
4395 double old_value = Handle<MutableHeapNumber>::cast(value)->value();
4396 value = isolate->factory()->NewHeapNumber(old_value);
4397 }
4398 }
4399 } else {
4400 DCHECK_EQ(kAccessor, details.kind());
4401 value = handle(object->RawFastPropertyAt(index), isolate);
4402 }
4403
4404 } else {
4405 DCHECK_EQ(kDescriptor, details.location());
4406 value = handle(descs->GetStrongValue(i), isolate);
4407 }
4408 DCHECK(!value.is_null());
4409 PropertyDetails d(details.kind(), details.attributes(),
4410 PropertyCellType::kNoCell);
4411 dictionary = NameDictionary::Add(isolate, dictionary, key, value, d);
4412 }
4413
4414 // Copy the next enumeration index from instance descriptor.
4415 dictionary->SetNextEnumerationIndex(real_size + 1);
4416
4417 // From here on we cannot fail and we shouldn't GC anymore.
4418 DisallowHeapAllocation no_allocation;
4419
4420 Heap* heap = isolate->heap();
4421 int old_instance_size = map->instance_size();
4422 heap->NotifyObjectLayoutChange(*object, old_instance_size, no_allocation);
4423
4424 // Resize the object in the heap if necessary.
4425 int new_instance_size = new_map->instance_size();
4426 int instance_size_delta = old_instance_size - new_instance_size;
4427 DCHECK_GE(instance_size_delta, 0);
4428
4429 if (instance_size_delta > 0) {
4430 heap->CreateFillerObjectAt(object->address() + new_instance_size,
4431 instance_size_delta, ClearRecordedSlots::kYes);
4432 }
4433
4434 // We are storing the new map using release store after creating a filler for
4435 // the left-over space to avoid races with the sweeper thread.
4436 object->synchronized_set_map(*new_map);
4437
4438 object->SetProperties(*dictionary);
4439
4440 // Ensure that in-object space of slow-mode object does not contain random
4441 // garbage.
4442 int inobject_properties = new_map->GetInObjectProperties();
4443 if (inobject_properties) {
4444 Heap* heap = isolate->heap();
4445 heap->ClearRecordedSlotRange(
4446 object->address() + map->GetInObjectPropertyOffset(0),
4447 object->address() + new_instance_size);
4448
4449 for (int i = 0; i < inobject_properties; i++) {
4450 FieldIndex index = FieldIndex::ForPropertyIndex(*new_map, i);
4451 object->RawFastPropertyAtPut(index, Smi::kZero);
4452 }
4453 }
4454
4455 isolate->counters()->props_to_dictionary()->Increment();
4456
4457 #ifdef DEBUG
4458 if (FLAG_trace_normalization) {
4459 StdoutStream os;
4460 os << "Object properties have been normalized:\n";
4461 object->Print(os);
4462 }
4463 #endif
4464 }
4465
4466 } // namespace
4467
4468 // static
NotifyMapChange(Handle<Map> old_map,Handle<Map> new_map,Isolate * isolate)4469 void JSObject::NotifyMapChange(Handle<Map> old_map, Handle<Map> new_map,
4470 Isolate* isolate) {
4471 if (!old_map->is_prototype_map()) return;
4472
4473 InvalidatePrototypeChains(*old_map);
4474
4475 // If the map was registered with its prototype before, ensure that it
4476 // registers with its new prototype now. This preserves the invariant that
4477 // when a map on a prototype chain is registered with its prototype, then
4478 // all prototypes further up the chain are also registered with their
4479 // respective prototypes.
4480 UpdatePrototypeUserRegistration(old_map, new_map, isolate);
4481 }
4482
MigrateToMap(Handle<JSObject> object,Handle<Map> new_map,int expected_additional_properties)4483 void JSObject::MigrateToMap(Handle<JSObject> object, Handle<Map> new_map,
4484 int expected_additional_properties) {
4485 if (object->map() == *new_map) return;
4486 Handle<Map> old_map(object->map(), object->GetIsolate());
4487 NotifyMapChange(old_map, new_map, object->GetIsolate());
4488
4489 if (old_map->is_dictionary_map()) {
4490 // For slow-to-fast migrations JSObject::MigrateSlowToFast()
4491 // must be used instead.
4492 CHECK(new_map->is_dictionary_map());
4493
4494 // Slow-to-slow migration is trivial.
4495 object->synchronized_set_map(*new_map);
4496 } else if (!new_map->is_dictionary_map()) {
4497 MigrateFastToFast(object, new_map);
4498 if (old_map->is_prototype_map()) {
4499 DCHECK(!old_map->is_stable());
4500 DCHECK(new_map->is_stable());
4501 DCHECK(new_map->owns_descriptors());
4502 DCHECK(old_map->owns_descriptors());
4503 // Transfer ownership to the new map. Keep the descriptor pointer of the
4504 // old map intact because the concurrent marker might be iterating the
4505 // object with the old map.
4506 old_map->set_owns_descriptors(false);
4507 DCHECK(old_map->is_abandoned_prototype_map());
4508 // Ensure that no transition was inserted for prototype migrations.
4509 DCHECK_EQ(0, TransitionsAccessor(object->GetIsolate(), old_map)
4510 .NumberOfTransitions());
4511 DCHECK(new_map->GetBackPointer()->IsUndefined());
4512 DCHECK(object->map() != *old_map);
4513 }
4514 } else {
4515 MigrateFastToSlow(object, new_map, expected_additional_properties);
4516 }
4517
4518 // Careful: Don't allocate here!
4519 // For some callers of this method, |object| might be in an inconsistent
4520 // state now: the new map might have a new elements_kind, but the object's
4521 // elements pointer hasn't been updated yet. Callers will fix this, but in
4522 // the meantime, (indirectly) calling JSObjectVerify() must be avoided.
4523 // When adding code here, add a DisallowHeapAllocation too.
4524 }
4525
ForceSetPrototype(Handle<JSObject> object,Handle<Object> proto)4526 void JSObject::ForceSetPrototype(Handle<JSObject> object,
4527 Handle<Object> proto) {
4528 // object.__proto__ = proto;
4529 Handle<Map> old_map = Handle<Map>(object->map(), object->GetIsolate());
4530 Handle<Map> new_map =
4531 Map::Copy(object->GetIsolate(), old_map, "ForceSetPrototype");
4532 Map::SetPrototype(object->GetIsolate(), new_map, proto);
4533 JSObject::MigrateToMap(object, new_map);
4534 }
4535
NumberOfFields() const4536 int Map::NumberOfFields() const {
4537 DescriptorArray* descriptors = instance_descriptors();
4538 int result = 0;
4539 for (int i = 0; i < NumberOfOwnDescriptors(); i++) {
4540 if (descriptors->GetDetails(i).location() == kField) result++;
4541 }
4542 return result;
4543 }
4544
HasOutOfObjectProperties() const4545 bool Map::HasOutOfObjectProperties() const {
4546 return GetInObjectProperties() < NumberOfFields();
4547 }
4548
GeneralizeAllFields()4549 void DescriptorArray::GeneralizeAllFields() {
4550 int length = number_of_descriptors();
4551 for (int i = 0; i < length; i++) {
4552 PropertyDetails details = GetDetails(i);
4553 details = details.CopyWithRepresentation(Representation::Tagged());
4554 if (details.location() == kField) {
4555 DCHECK_EQ(kData, details.kind());
4556 details = details.CopyWithConstness(PropertyConstness::kMutable);
4557 SetValue(i, FieldType::Any());
4558 }
4559 set(ToDetailsIndex(i), MaybeObject::FromObject(details.AsSmi()));
4560 }
4561 }
4562
CopyGeneralizeAllFields(Isolate * isolate,Handle<Map> map,ElementsKind elements_kind,int modify_index,PropertyKind kind,PropertyAttributes attributes,const char * reason)4563 Handle<Map> Map::CopyGeneralizeAllFields(Isolate* isolate, Handle<Map> map,
4564 ElementsKind elements_kind,
4565 int modify_index, PropertyKind kind,
4566 PropertyAttributes attributes,
4567 const char* reason) {
4568 Handle<DescriptorArray> old_descriptors(map->instance_descriptors(), isolate);
4569 int number_of_own_descriptors = map->NumberOfOwnDescriptors();
4570 Handle<DescriptorArray> descriptors = DescriptorArray::CopyUpTo(
4571 isolate, old_descriptors, number_of_own_descriptors);
4572 descriptors->GeneralizeAllFields();
4573
4574 Handle<LayoutDescriptor> new_layout_descriptor(
4575 LayoutDescriptor::FastPointerLayout(), isolate);
4576 Handle<Map> new_map = CopyReplaceDescriptors(
4577 isolate, map, descriptors, new_layout_descriptor, OMIT_TRANSITION,
4578 MaybeHandle<Name>(), reason, SPECIAL_TRANSITION);
4579
4580 // Unless the instance is being migrated, ensure that modify_index is a field.
4581 if (modify_index >= 0) {
4582 PropertyDetails details = descriptors->GetDetails(modify_index);
4583 if (details.constness() != PropertyConstness::kMutable ||
4584 details.location() != kField || details.attributes() != attributes) {
4585 int field_index = details.location() == kField
4586 ? details.field_index()
4587 : new_map->NumberOfFields();
4588 Descriptor d = Descriptor::DataField(
4589 isolate, handle(descriptors->GetKey(modify_index), isolate),
4590 field_index, attributes, Representation::Tagged());
4591 descriptors->Replace(modify_index, &d);
4592 if (details.location() != kField) {
4593 new_map->AccountAddedPropertyField();
4594 }
4595 } else {
4596 DCHECK(details.attributes() == attributes);
4597 }
4598
4599 if (FLAG_trace_generalization) {
4600 MaybeHandle<FieldType> field_type = FieldType::None(isolate);
4601 if (details.location() == kField) {
4602 field_type = handle(
4603 map->instance_descriptors()->GetFieldType(modify_index), isolate);
4604 }
4605 map->PrintGeneralization(
4606 isolate, stdout, reason, modify_index,
4607 new_map->NumberOfOwnDescriptors(), new_map->NumberOfOwnDescriptors(),
4608 details.location() == kDescriptor, details.representation(),
4609 Representation::Tagged(), field_type, MaybeHandle<Object>(),
4610 FieldType::Any(isolate), MaybeHandle<Object>());
4611 }
4612 }
4613 new_map->set_elements_kind(elements_kind);
4614 return new_map;
4615 }
4616
DeprecateTransitionTree(Isolate * isolate)4617 void Map::DeprecateTransitionTree(Isolate* isolate) {
4618 if (is_deprecated()) return;
4619 DisallowHeapAllocation no_gc;
4620 TransitionsAccessor transitions(isolate, this, &no_gc);
4621 int num_transitions = transitions.NumberOfTransitions();
4622 for (int i = 0; i < num_transitions; ++i) {
4623 transitions.GetTarget(i)->DeprecateTransitionTree(isolate);
4624 }
4625 DCHECK(!constructor_or_backpointer()->IsFunctionTemplateInfo());
4626 set_is_deprecated(true);
4627 if (FLAG_trace_maps) {
4628 LOG(isolate, MapEvent("Deprecate", this, nullptr));
4629 }
4630 dependent_code()->DeoptimizeDependentCodeGroup(
4631 isolate, DependentCode::kTransitionGroup);
4632 NotifyLeafMapLayoutChange(isolate);
4633 }
4634
4635
4636 // Installs |new_descriptors| over the current instance_descriptors to ensure
4637 // proper sharing of descriptor arrays.
ReplaceDescriptors(Isolate * isolate,DescriptorArray * new_descriptors,LayoutDescriptor * new_layout_descriptor)4638 void Map::ReplaceDescriptors(Isolate* isolate, DescriptorArray* new_descriptors,
4639 LayoutDescriptor* new_layout_descriptor) {
4640 // Don't overwrite the empty descriptor array or initial map's descriptors.
4641 if (NumberOfOwnDescriptors() == 0 || GetBackPointer()->IsUndefined(isolate)) {
4642 return;
4643 }
4644
4645 DescriptorArray* to_replace = instance_descriptors();
4646 // Replace descriptors by new_descriptors in all maps that share it. The old
4647 // descriptors will not be trimmed in the mark-compactor, we need to mark
4648 // all its elements.
4649 MarkingBarrierForElements(isolate->heap(), to_replace);
4650 Map* current = this;
4651 while (current->instance_descriptors() == to_replace) {
4652 Object* next = current->GetBackPointer();
4653 if (next->IsUndefined(isolate)) break; // Stop overwriting at initial map.
4654 current->SetEnumLength(kInvalidEnumCacheSentinel);
4655 current->UpdateDescriptors(new_descriptors, new_layout_descriptor);
4656 current = Map::cast(next);
4657 }
4658 set_owns_descriptors(false);
4659 }
4660
FindRootMap(Isolate * isolate) const4661 Map* Map::FindRootMap(Isolate* isolate) const {
4662 const Map* result = this;
4663 while (true) {
4664 Object* back = result->GetBackPointer();
4665 if (back->IsUndefined(isolate)) {
4666 // Initial map always owns descriptors and doesn't have unused entries
4667 // in the descriptor array.
4668 DCHECK(result->owns_descriptors());
4669 DCHECK_EQ(result->NumberOfOwnDescriptors(),
4670 result->instance_descriptors()->number_of_descriptors());
4671 return const_cast<Map*>(result);
4672 }
4673 result = Map::cast(back);
4674 }
4675 }
4676
FindFieldOwner(Isolate * isolate,int descriptor) const4677 Map* Map::FindFieldOwner(Isolate* isolate, int descriptor) const {
4678 DisallowHeapAllocation no_allocation;
4679 DCHECK_EQ(kField, instance_descriptors()->GetDetails(descriptor).location());
4680 const Map* result = this;
4681 while (true) {
4682 Object* back = result->GetBackPointer();
4683 if (back->IsUndefined(isolate)) break;
4684 const Map* parent = Map::cast(back);
4685 if (parent->NumberOfOwnDescriptors() <= descriptor) break;
4686 result = parent;
4687 }
4688 return const_cast<Map*>(result);
4689 }
4690
UpdateFieldType(Isolate * isolate,int descriptor,Handle<Name> name,PropertyConstness new_constness,Representation new_representation,MaybeObjectHandle new_wrapped_type)4691 void Map::UpdateFieldType(Isolate* isolate, int descriptor, Handle<Name> name,
4692 PropertyConstness new_constness,
4693 Representation new_representation,
4694 MaybeObjectHandle new_wrapped_type) {
4695 DCHECK(new_wrapped_type->IsSmi() || new_wrapped_type->IsWeakHeapObject());
4696 // We store raw pointers in the queue, so no allocations are allowed.
4697 DisallowHeapAllocation no_allocation;
4698 PropertyDetails details = instance_descriptors()->GetDetails(descriptor);
4699 if (details.location() != kField) return;
4700 DCHECK_EQ(kData, details.kind());
4701
4702 Zone zone(isolate->allocator(), ZONE_NAME);
4703 ZoneQueue<Map*> backlog(&zone);
4704 backlog.push(this);
4705
4706 while (!backlog.empty()) {
4707 Map* current = backlog.front();
4708 backlog.pop();
4709
4710 TransitionsAccessor transitions(isolate, current, &no_allocation);
4711 int num_transitions = transitions.NumberOfTransitions();
4712 for (int i = 0; i < num_transitions; ++i) {
4713 Map* target = transitions.GetTarget(i);
4714 backlog.push(target);
4715 }
4716 DescriptorArray* descriptors = current->instance_descriptors();
4717 PropertyDetails details = descriptors->GetDetails(descriptor);
4718
4719 // Currently constness change implies map change.
4720 DCHECK_IMPLIES(new_constness != details.constness(),
4721 FLAG_modify_map_inplace);
4722
4723 // It is allowed to change representation here only from None to something.
4724 DCHECK(details.representation().Equals(new_representation) ||
4725 details.representation().IsNone());
4726
4727 // Skip if already updated the shared descriptor.
4728 if ((FLAG_modify_map_inplace && new_constness != details.constness()) ||
4729 descriptors->GetFieldType(descriptor) != *new_wrapped_type.object()) {
4730 DCHECK_IMPLIES(!FLAG_track_constant_fields,
4731 new_constness == PropertyConstness::kMutable);
4732 Descriptor d = Descriptor::DataField(
4733 name, descriptors->GetFieldIndex(descriptor), details.attributes(),
4734 new_constness, new_representation, new_wrapped_type);
4735 descriptors->Replace(descriptor, &d);
4736 }
4737 }
4738 }
4739
FieldTypeIsCleared(Representation rep,FieldType * type)4740 bool FieldTypeIsCleared(Representation rep, FieldType* type) {
4741 return type->IsNone() && rep.IsHeapObject();
4742 }
4743
4744
4745 // static
GeneralizeFieldType(Representation rep1,Handle<FieldType> type1,Representation rep2,Handle<FieldType> type2,Isolate * isolate)4746 Handle<FieldType> Map::GeneralizeFieldType(Representation rep1,
4747 Handle<FieldType> type1,
4748 Representation rep2,
4749 Handle<FieldType> type2,
4750 Isolate* isolate) {
4751 // Cleared field types need special treatment. They represent lost knowledge,
4752 // so we must be conservative, so their generalization with any other type
4753 // is "Any".
4754 if (FieldTypeIsCleared(rep1, *type1) || FieldTypeIsCleared(rep2, *type2)) {
4755 return FieldType::Any(isolate);
4756 }
4757 if (type1->NowIs(type2)) return type2;
4758 if (type2->NowIs(type1)) return type1;
4759 return FieldType::Any(isolate);
4760 }
4761
4762 // static
GeneralizeField(Isolate * isolate,Handle<Map> map,int modify_index,PropertyConstness new_constness,Representation new_representation,Handle<FieldType> new_field_type)4763 void Map::GeneralizeField(Isolate* isolate, Handle<Map> map, int modify_index,
4764 PropertyConstness new_constness,
4765 Representation new_representation,
4766 Handle<FieldType> new_field_type) {
4767 // Check if we actually need to generalize the field type at all.
4768 Handle<DescriptorArray> old_descriptors(map->instance_descriptors(), isolate);
4769 PropertyDetails old_details = old_descriptors->GetDetails(modify_index);
4770 PropertyConstness old_constness = old_details.constness();
4771 Representation old_representation = old_details.representation();
4772 Handle<FieldType> old_field_type(old_descriptors->GetFieldType(modify_index),
4773 isolate);
4774
4775 // Return if the current map is general enough to hold requested constness and
4776 // representation/field type.
4777 if (((FLAG_modify_map_inplace &&
4778 IsGeneralizableTo(new_constness, old_constness)) ||
4779 (!FLAG_modify_map_inplace && (old_constness == new_constness))) &&
4780 old_representation.Equals(new_representation) &&
4781 !FieldTypeIsCleared(new_representation, *new_field_type) &&
4782 // Checking old_field_type for being cleared is not necessary because
4783 // the NowIs check below would fail anyway in that case.
4784 new_field_type->NowIs(old_field_type)) {
4785 DCHECK(GeneralizeFieldType(old_representation, old_field_type,
4786 new_representation, new_field_type, isolate)
4787 ->NowIs(old_field_type));
4788 return;
4789 }
4790
4791 // Determine the field owner.
4792 Handle<Map> field_owner(map->FindFieldOwner(isolate, modify_index), isolate);
4793 Handle<DescriptorArray> descriptors(field_owner->instance_descriptors(),
4794 isolate);
4795 DCHECK_EQ(*old_field_type, descriptors->GetFieldType(modify_index));
4796
4797 new_field_type =
4798 Map::GeneralizeFieldType(old_representation, old_field_type,
4799 new_representation, new_field_type, isolate);
4800 if (FLAG_modify_map_inplace) {
4801 new_constness = GeneralizeConstness(old_constness, new_constness);
4802 }
4803
4804 PropertyDetails details = descriptors->GetDetails(modify_index);
4805 Handle<Name> name(descriptors->GetKey(modify_index), isolate);
4806
4807 MaybeObjectHandle wrapped_type(WrapFieldType(isolate, new_field_type));
4808 field_owner->UpdateFieldType(isolate, modify_index, name, new_constness,
4809 new_representation, wrapped_type);
4810 field_owner->dependent_code()->DeoptimizeDependentCodeGroup(
4811 isolate, DependentCode::kFieldOwnerGroup);
4812
4813 if (FLAG_trace_generalization) {
4814 map->PrintGeneralization(
4815 isolate, stdout, "field type generalization", modify_index,
4816 map->NumberOfOwnDescriptors(), map->NumberOfOwnDescriptors(), false,
4817 details.representation(), details.representation(), old_field_type,
4818 MaybeHandle<Object>(), new_field_type, MaybeHandle<Object>());
4819 }
4820 }
4821
4822 // TODO(ishell): remove.
4823 // static
ReconfigureProperty(Isolate * isolate,Handle<Map> map,int modify_index,PropertyKind new_kind,PropertyAttributes new_attributes,Representation new_representation,Handle<FieldType> new_field_type)4824 Handle<Map> Map::ReconfigureProperty(Isolate* isolate, Handle<Map> map,
4825 int modify_index, PropertyKind new_kind,
4826 PropertyAttributes new_attributes,
4827 Representation new_representation,
4828 Handle<FieldType> new_field_type) {
4829 DCHECK_EQ(kData, new_kind); // Only kData case is supported.
4830 MapUpdater mu(isolate, map);
4831 return mu.ReconfigureToDataField(modify_index, new_attributes,
4832 PropertyConstness::kConst,
4833 new_representation, new_field_type);
4834 }
4835
4836 // TODO(ishell): remove.
4837 // static
ReconfigureElementsKind(Isolate * isolate,Handle<Map> map,ElementsKind new_elements_kind)4838 Handle<Map> Map::ReconfigureElementsKind(Isolate* isolate, Handle<Map> map,
4839 ElementsKind new_elements_kind) {
4840 MapUpdater mu(isolate, map);
4841 return mu.ReconfigureElementsKind(new_elements_kind);
4842 }
4843
4844 // Generalize all fields and update the transition tree.
GeneralizeAllFields(Isolate * isolate,Handle<Map> map)4845 Handle<Map> Map::GeneralizeAllFields(Isolate* isolate, Handle<Map> map) {
4846 Handle<FieldType> any_type = FieldType::Any(isolate);
4847
4848 Handle<DescriptorArray> descriptors(map->instance_descriptors(), isolate);
4849 for (int i = 0; i < map->NumberOfOwnDescriptors(); ++i) {
4850 PropertyDetails details = descriptors->GetDetails(i);
4851 if (details.location() == kField) {
4852 DCHECK_EQ(kData, details.kind());
4853 MapUpdater mu(isolate, map);
4854 map = mu.ReconfigureToDataField(i, details.attributes(),
4855 PropertyConstness::kMutable,
4856 Representation::Tagged(), any_type);
4857 }
4858 }
4859 return map;
4860 }
4861
4862
4863 // static
TryUpdate(Isolate * isolate,Handle<Map> old_map)4864 MaybeHandle<Map> Map::TryUpdate(Isolate* isolate, Handle<Map> old_map) {
4865 DisallowHeapAllocation no_allocation;
4866 DisallowDeoptimization no_deoptimization(isolate);
4867
4868 if (!old_map->is_deprecated()) return old_map;
4869
4870 // Check the state of the root map.
4871 Map* root_map = old_map->FindRootMap(isolate);
4872 if (root_map->is_deprecated()) {
4873 JSFunction* constructor = JSFunction::cast(root_map->GetConstructor());
4874 DCHECK(constructor->has_initial_map());
4875 DCHECK(constructor->initial_map()->is_dictionary_map());
4876 if (constructor->initial_map()->elements_kind() !=
4877 old_map->elements_kind()) {
4878 return MaybeHandle<Map>();
4879 }
4880 return handle(constructor->initial_map(), constructor->GetIsolate());
4881 }
4882 if (!old_map->EquivalentToForTransition(root_map)) return MaybeHandle<Map>();
4883
4884 ElementsKind from_kind = root_map->elements_kind();
4885 ElementsKind to_kind = old_map->elements_kind();
4886 if (from_kind != to_kind) {
4887 // Try to follow existing elements kind transitions.
4888 root_map = root_map->LookupElementsTransitionMap(isolate, to_kind);
4889 if (root_map == nullptr) return MaybeHandle<Map>();
4890 // From here on, use the map with correct elements kind as root map.
4891 }
4892 Map* new_map = root_map->TryReplayPropertyTransitions(isolate, *old_map);
4893 if (new_map == nullptr) return MaybeHandle<Map>();
4894 return handle(new_map, isolate);
4895 }
4896
TryReplayPropertyTransitions(Isolate * isolate,Map * old_map)4897 Map* Map::TryReplayPropertyTransitions(Isolate* isolate, Map* old_map) {
4898 DisallowHeapAllocation no_allocation;
4899 DisallowDeoptimization no_deoptimization(isolate);
4900
4901 int root_nof = NumberOfOwnDescriptors();
4902
4903 int old_nof = old_map->NumberOfOwnDescriptors();
4904 DescriptorArray* old_descriptors = old_map->instance_descriptors();
4905
4906 Map* new_map = this;
4907 for (int i = root_nof; i < old_nof; ++i) {
4908 PropertyDetails old_details = old_descriptors->GetDetails(i);
4909 Map* transition =
4910 TransitionsAccessor(isolate, new_map, &no_allocation)
4911 .SearchTransition(old_descriptors->GetKey(i), old_details.kind(),
4912 old_details.attributes());
4913 if (transition == nullptr) return nullptr;
4914 new_map = transition;
4915 DescriptorArray* new_descriptors = new_map->instance_descriptors();
4916
4917 PropertyDetails new_details = new_descriptors->GetDetails(i);
4918 DCHECK_EQ(old_details.kind(), new_details.kind());
4919 DCHECK_EQ(old_details.attributes(), new_details.attributes());
4920 if (!IsGeneralizableTo(old_details.constness(), new_details.constness())) {
4921 return nullptr;
4922 }
4923 DCHECK(IsGeneralizableTo(old_details.location(), new_details.location()));
4924 if (!old_details.representation().fits_into(new_details.representation())) {
4925 return nullptr;
4926 }
4927 if (new_details.location() == kField) {
4928 if (new_details.kind() == kData) {
4929 FieldType* new_type = new_descriptors->GetFieldType(i);
4930 // Cleared field types need special treatment. They represent lost
4931 // knowledge, so we must first generalize the new_type to "Any".
4932 if (FieldTypeIsCleared(new_details.representation(), new_type)) {
4933 return nullptr;
4934 }
4935 DCHECK_EQ(kData, old_details.kind());
4936 if (old_details.location() == kField) {
4937 FieldType* old_type = old_descriptors->GetFieldType(i);
4938 if (FieldTypeIsCleared(old_details.representation(), old_type) ||
4939 !old_type->NowIs(new_type)) {
4940 return nullptr;
4941 }
4942 } else {
4943 DCHECK_EQ(kDescriptor, old_details.location());
4944 DCHECK(!FLAG_track_constant_fields);
4945 Object* old_value = old_descriptors->GetStrongValue(i);
4946 if (!new_type->NowContains(old_value)) {
4947 return nullptr;
4948 }
4949 }
4950
4951 } else {
4952 DCHECK_EQ(kAccessor, new_details.kind());
4953 #ifdef DEBUG
4954 FieldType* new_type = new_descriptors->GetFieldType(i);
4955 DCHECK(new_type->IsAny());
4956 #endif
4957 UNREACHABLE();
4958 }
4959 } else {
4960 DCHECK_EQ(kDescriptor, new_details.location());
4961 if (old_details.location() == kField ||
4962 old_descriptors->GetStrongValue(i) !=
4963 new_descriptors->GetStrongValue(i)) {
4964 return nullptr;
4965 }
4966 }
4967 }
4968 if (new_map->NumberOfOwnDescriptors() != old_nof) return nullptr;
4969 return new_map;
4970 }
4971
4972
4973 // static
Update(Isolate * isolate,Handle<Map> map)4974 Handle<Map> Map::Update(Isolate* isolate, Handle<Map> map) {
4975 if (!map->is_deprecated()) return map;
4976 MapUpdater mu(isolate, map);
4977 return mu.Update();
4978 }
4979
SetPropertyWithInterceptor(LookupIterator * it,ShouldThrow should_throw,Handle<Object> value)4980 Maybe<bool> JSObject::SetPropertyWithInterceptor(LookupIterator* it,
4981 ShouldThrow should_throw,
4982 Handle<Object> value) {
4983 DCHECK_EQ(LookupIterator::INTERCEPTOR, it->state());
4984 return SetPropertyWithInterceptorInternal(it, it->GetInterceptor(),
4985 should_throw, value);
4986 }
4987
SetProperty(Isolate * isolate,Handle<Object> object,Handle<Name> name,Handle<Object> value,LanguageMode language_mode,StoreFromKeyed store_mode)4988 MaybeHandle<Object> Object::SetProperty(Isolate* isolate, Handle<Object> object,
4989 Handle<Name> name, Handle<Object> value,
4990 LanguageMode language_mode,
4991 StoreFromKeyed store_mode) {
4992 LookupIterator it(isolate, object, name);
4993 MAYBE_RETURN_NULL(SetProperty(&it, value, language_mode, store_mode));
4994 return value;
4995 }
4996
4997
SetPropertyInternal(LookupIterator * it,Handle<Object> value,LanguageMode language_mode,StoreFromKeyed store_mode,bool * found)4998 Maybe<bool> Object::SetPropertyInternal(LookupIterator* it,
4999 Handle<Object> value,
5000 LanguageMode language_mode,
5001 StoreFromKeyed store_mode,
5002 bool* found) {
5003 it->UpdateProtector();
5004 DCHECK(it->IsFound());
5005 ShouldThrow should_throw =
5006 is_sloppy(language_mode) ? kDontThrow : kThrowOnError;
5007
5008 // Make sure that the top context does not change when doing callbacks or
5009 // interceptor calls.
5010 AssertNoContextChange ncc(it->isolate());
5011
5012 do {
5013 switch (it->state()) {
5014 case LookupIterator::NOT_FOUND:
5015 UNREACHABLE();
5016
5017 case LookupIterator::ACCESS_CHECK:
5018 if (it->HasAccess()) break;
5019 // Check whether it makes sense to reuse the lookup iterator. Here it
5020 // might still call into setters up the prototype chain.
5021 return JSObject::SetPropertyWithFailedAccessCheck(it, value,
5022 should_throw);
5023
5024 case LookupIterator::JSPROXY:
5025 return JSProxy::SetProperty(it->GetHolder<JSProxy>(), it->GetName(),
5026 value, it->GetReceiver(), language_mode);
5027
5028 case LookupIterator::INTERCEPTOR: {
5029 if (it->HolderIsReceiverOrHiddenPrototype()) {
5030 Maybe<bool> result =
5031 JSObject::SetPropertyWithInterceptor(it, should_throw, value);
5032 if (result.IsNothing() || result.FromJust()) return result;
5033 } else {
5034 Maybe<PropertyAttributes> maybe_attributes =
5035 JSObject::GetPropertyAttributesWithInterceptor(it);
5036 if (maybe_attributes.IsNothing()) return Nothing<bool>();
5037 if ((maybe_attributes.FromJust() & READ_ONLY) != 0) {
5038 return WriteToReadOnlyProperty(it, value, should_throw);
5039 }
5040 if (maybe_attributes.FromJust() == ABSENT) break;
5041 *found = false;
5042 return Nothing<bool>();
5043 }
5044 break;
5045 }
5046
5047 case LookupIterator::ACCESSOR: {
5048 if (it->IsReadOnly()) {
5049 return WriteToReadOnlyProperty(it, value, should_throw);
5050 }
5051 Handle<Object> accessors = it->GetAccessors();
5052 if (accessors->IsAccessorInfo() &&
5053 !it->HolderIsReceiverOrHiddenPrototype() &&
5054 AccessorInfo::cast(*accessors)->is_special_data_property()) {
5055 *found = false;
5056 return Nothing<bool>();
5057 }
5058 return SetPropertyWithAccessor(it, value, should_throw);
5059 }
5060 case LookupIterator::INTEGER_INDEXED_EXOTIC: {
5061 // IntegerIndexedElementSet converts value to a Number/BigInt prior to
5062 // the bounds check. The bounds check has already happened here, but
5063 // perform the possibly effectful ToNumber (or ToBigInt) operation
5064 // anyways.
5065 auto holder = it->GetHolder<JSTypedArray>();
5066 Handle<Object> throwaway_value;
5067 if (holder->type() == kExternalBigInt64Array ||
5068 holder->type() == kExternalBigUint64Array) {
5069 ASSIGN_RETURN_ON_EXCEPTION_VALUE(
5070 it->isolate(), throwaway_value,
5071 BigInt::FromObject(it->isolate(), value), Nothing<bool>());
5072 } else {
5073 ASSIGN_RETURN_ON_EXCEPTION_VALUE(
5074 it->isolate(), throwaway_value,
5075 Object::ToNumber(it->isolate(), value), Nothing<bool>());
5076 }
5077
5078 // FIXME: Throw a TypeError if the holder is neutered here
5079 // (IntegerIndexedElementSpec step 5).
5080
5081 // TODO(verwaest): Per spec, we should return false here (steps 6-9
5082 // in IntegerIndexedElementSpec), resulting in an exception being thrown
5083 // on OOB accesses in strict code. Historically, v8 has not done made
5084 // this change due to uncertainty about web compat. (v8:4901)
5085 return Just(true);
5086 }
5087
5088 case LookupIterator::DATA:
5089 if (it->IsReadOnly()) {
5090 return WriteToReadOnlyProperty(it, value, should_throw);
5091 }
5092 if (it->HolderIsReceiverOrHiddenPrototype()) {
5093 return SetDataProperty(it, value);
5094 }
5095 V8_FALLTHROUGH;
5096 case LookupIterator::TRANSITION:
5097 *found = false;
5098 return Nothing<bool>();
5099 }
5100 it->Next();
5101 } while (it->IsFound());
5102
5103 *found = false;
5104 return Nothing<bool>();
5105 }
5106
5107
SetProperty(LookupIterator * it,Handle<Object> value,LanguageMode language_mode,StoreFromKeyed store_mode)5108 Maybe<bool> Object::SetProperty(LookupIterator* it, Handle<Object> value,
5109 LanguageMode language_mode,
5110 StoreFromKeyed store_mode) {
5111 if (it->IsFound()) {
5112 bool found = true;
5113 Maybe<bool> result =
5114 SetPropertyInternal(it, value, language_mode, store_mode, &found);
5115 if (found) return result;
5116 }
5117
5118 // If the receiver is the JSGlobalObject, the store was contextual. In case
5119 // the property did not exist yet on the global object itself, we have to
5120 // throw a reference error in strict mode. In sloppy mode, we continue.
5121 if (is_strict(language_mode) && it->GetReceiver()->IsJSGlobalObject()) {
5122 it->isolate()->Throw(*it->isolate()->factory()->NewReferenceError(
5123 MessageTemplate::kNotDefined, it->name()));
5124 return Nothing<bool>();
5125 }
5126
5127 ShouldThrow should_throw =
5128 is_sloppy(language_mode) ? kDontThrow : kThrowOnError;
5129 return AddDataProperty(it, value, NONE, should_throw, store_mode);
5130 }
5131
5132
SetSuperProperty(LookupIterator * it,Handle<Object> value,LanguageMode language_mode,StoreFromKeyed store_mode)5133 Maybe<bool> Object::SetSuperProperty(LookupIterator* it, Handle<Object> value,
5134 LanguageMode language_mode,
5135 StoreFromKeyed store_mode) {
5136 Isolate* isolate = it->isolate();
5137
5138 if (it->IsFound()) {
5139 bool found = true;
5140 Maybe<bool> result =
5141 SetPropertyInternal(it, value, language_mode, store_mode, &found);
5142 if (found) return result;
5143 }
5144
5145 it->UpdateProtector();
5146
5147 // The property either doesn't exist on the holder or exists there as a data
5148 // property.
5149
5150 ShouldThrow should_throw =
5151 is_sloppy(language_mode) ? kDontThrow : kThrowOnError;
5152
5153 if (!it->GetReceiver()->IsJSReceiver()) {
5154 return WriteToReadOnlyProperty(it, value, should_throw);
5155 }
5156 Handle<JSReceiver> receiver = Handle<JSReceiver>::cast(it->GetReceiver());
5157
5158 LookupIterator::Configuration c = LookupIterator::OWN;
5159 LookupIterator own_lookup =
5160 it->IsElement() ? LookupIterator(isolate, receiver, it->index(), c)
5161 : LookupIterator(isolate, receiver, it->name(), c);
5162
5163 for (; own_lookup.IsFound(); own_lookup.Next()) {
5164 switch (own_lookup.state()) {
5165 case LookupIterator::ACCESS_CHECK:
5166 if (!own_lookup.HasAccess()) {
5167 return JSObject::SetPropertyWithFailedAccessCheck(&own_lookup, value,
5168 should_throw);
5169 }
5170 break;
5171
5172 case LookupIterator::ACCESSOR:
5173 if (own_lookup.GetAccessors()->IsAccessorInfo()) {
5174 if (own_lookup.IsReadOnly()) {
5175 return WriteToReadOnlyProperty(&own_lookup, value, should_throw);
5176 }
5177 return JSObject::SetPropertyWithAccessor(&own_lookup, value,
5178 should_throw);
5179 }
5180 V8_FALLTHROUGH;
5181 case LookupIterator::INTEGER_INDEXED_EXOTIC:
5182 return RedefineIncompatibleProperty(isolate, it->GetName(), value,
5183 should_throw);
5184
5185 case LookupIterator::DATA: {
5186 if (own_lookup.IsReadOnly()) {
5187 return WriteToReadOnlyProperty(&own_lookup, value, should_throw);
5188 }
5189 return SetDataProperty(&own_lookup, value);
5190 }
5191
5192 case LookupIterator::INTERCEPTOR:
5193 case LookupIterator::JSPROXY: {
5194 PropertyDescriptor desc;
5195 Maybe<bool> owned =
5196 JSReceiver::GetOwnPropertyDescriptor(&own_lookup, &desc);
5197 MAYBE_RETURN(owned, Nothing<bool>());
5198 if (!owned.FromJust()) {
5199 return JSReceiver::CreateDataProperty(&own_lookup, value,
5200 should_throw);
5201 }
5202 if (PropertyDescriptor::IsAccessorDescriptor(&desc) ||
5203 !desc.writable()) {
5204 return RedefineIncompatibleProperty(isolate, it->GetName(), value,
5205 should_throw);
5206 }
5207
5208 PropertyDescriptor value_desc;
5209 value_desc.set_value(value);
5210 return JSReceiver::DefineOwnProperty(isolate, receiver, it->GetName(),
5211 &value_desc, should_throw);
5212 }
5213
5214 case LookupIterator::NOT_FOUND:
5215 case LookupIterator::TRANSITION:
5216 UNREACHABLE();
5217 }
5218 }
5219
5220 return AddDataProperty(&own_lookup, value, NONE, should_throw, store_mode);
5221 }
5222
CannotCreateProperty(Isolate * isolate,Handle<Object> receiver,Handle<Object> name,Handle<Object> value,ShouldThrow should_throw)5223 Maybe<bool> Object::CannotCreateProperty(Isolate* isolate,
5224 Handle<Object> receiver,
5225 Handle<Object> name,
5226 Handle<Object> value,
5227 ShouldThrow should_throw) {
5228 RETURN_FAILURE(
5229 isolate, should_throw,
5230 NewTypeError(MessageTemplate::kStrictCannotCreateProperty, name,
5231 Object::TypeOf(isolate, receiver), receiver));
5232 }
5233
5234
WriteToReadOnlyProperty(LookupIterator * it,Handle<Object> value,ShouldThrow should_throw)5235 Maybe<bool> Object::WriteToReadOnlyProperty(LookupIterator* it,
5236 Handle<Object> value,
5237 ShouldThrow should_throw) {
5238 return WriteToReadOnlyProperty(it->isolate(), it->GetReceiver(),
5239 it->GetName(), value, should_throw);
5240 }
5241
5242
WriteToReadOnlyProperty(Isolate * isolate,Handle<Object> receiver,Handle<Object> name,Handle<Object> value,ShouldThrow should_throw)5243 Maybe<bool> Object::WriteToReadOnlyProperty(Isolate* isolate,
5244 Handle<Object> receiver,
5245 Handle<Object> name,
5246 Handle<Object> value,
5247 ShouldThrow should_throw) {
5248 RETURN_FAILURE(isolate, should_throw,
5249 NewTypeError(MessageTemplate::kStrictReadOnlyProperty, name,
5250 Object::TypeOf(isolate, receiver), receiver));
5251 }
5252
5253
RedefineIncompatibleProperty(Isolate * isolate,Handle<Object> name,Handle<Object> value,ShouldThrow should_throw)5254 Maybe<bool> Object::RedefineIncompatibleProperty(Isolate* isolate,
5255 Handle<Object> name,
5256 Handle<Object> value,
5257 ShouldThrow should_throw) {
5258 RETURN_FAILURE(isolate, should_throw,
5259 NewTypeError(MessageTemplate::kRedefineDisallowed, name));
5260 }
5261
5262
SetDataProperty(LookupIterator * it,Handle<Object> value)5263 Maybe<bool> Object::SetDataProperty(LookupIterator* it, Handle<Object> value) {
5264 DCHECK_IMPLIES(it->GetReceiver()->IsJSProxy(),
5265 it->GetName()->IsPrivateField());
5266 DCHECK_IMPLIES(!it->IsElement() && it->GetName()->IsPrivateField(),
5267 it->state() == LookupIterator::DATA);
5268 Handle<JSReceiver> receiver = Handle<JSReceiver>::cast(it->GetReceiver());
5269
5270 // Store on the holder which may be hidden behind the receiver.
5271 DCHECK(it->HolderIsReceiverOrHiddenPrototype());
5272
5273 Handle<Object> to_assign = value;
5274 // Convert the incoming value to a number for storing into typed arrays.
5275 if (it->IsElement() && receiver->IsJSObject() &&
5276 JSObject::cast(*receiver)->HasFixedTypedArrayElements()) {
5277 ElementsKind elements_kind = JSObject::cast(*receiver)->GetElementsKind();
5278 if (elements_kind == BIGINT64_ELEMENTS ||
5279 elements_kind == BIGUINT64_ELEMENTS) {
5280 ASSIGN_RETURN_ON_EXCEPTION_VALUE(it->isolate(), to_assign,
5281 BigInt::FromObject(it->isolate(), value),
5282 Nothing<bool>());
5283 // We have to recheck the length. However, it can only change if the
5284 // underlying buffer was neutered, so just check that.
5285 if (Handle<JSArrayBufferView>::cast(receiver)->WasNeutered()) {
5286 return Just(true);
5287 // TODO(neis): According to the spec, this should throw a TypeError.
5288 }
5289 } else if (!value->IsNumber() && !value->IsUndefined(it->isolate())) {
5290 ASSIGN_RETURN_ON_EXCEPTION_VALUE(it->isolate(), to_assign,
5291 Object::ToNumber(it->isolate(), value),
5292 Nothing<bool>());
5293 // We have to recheck the length. However, it can only change if the
5294 // underlying buffer was neutered, so just check that.
5295 if (Handle<JSArrayBufferView>::cast(receiver)->WasNeutered()) {
5296 return Just(true);
5297 // TODO(neis): According to the spec, this should throw a TypeError.
5298 }
5299 }
5300 }
5301
5302 // Possibly migrate to the most up-to-date map that will be able to store
5303 // |value| under it->name().
5304 it->PrepareForDataProperty(to_assign);
5305
5306 // Write the property value.
5307 it->WriteDataValue(to_assign, false);
5308
5309 #if VERIFY_HEAP
5310 if (FLAG_verify_heap) {
5311 receiver->HeapObjectVerify(it->isolate());
5312 }
5313 #endif
5314 return Just(true);
5315 }
5316
5317
AddDataProperty(LookupIterator * it,Handle<Object> value,PropertyAttributes attributes,ShouldThrow should_throw,StoreFromKeyed store_mode)5318 Maybe<bool> Object::AddDataProperty(LookupIterator* it, Handle<Object> value,
5319 PropertyAttributes attributes,
5320 ShouldThrow should_throw,
5321 StoreFromKeyed store_mode) {
5322 if (!it->GetReceiver()->IsJSReceiver()) {
5323 return CannotCreateProperty(it->isolate(), it->GetReceiver(), it->GetName(),
5324 value, should_throw);
5325 }
5326
5327 // Private symbols should be installed on JSProxy using
5328 // JSProxy::SetPrivateSymbol.
5329 if (it->GetReceiver()->IsJSProxy() && it->GetName()->IsPrivate() &&
5330 !it->GetName()->IsPrivateField()) {
5331 RETURN_FAILURE(it->isolate(), should_throw,
5332 NewTypeError(MessageTemplate::kProxyPrivate));
5333 }
5334
5335 DCHECK_NE(LookupIterator::INTEGER_INDEXED_EXOTIC, it->state());
5336
5337 Handle<JSReceiver> receiver = it->GetStoreTarget<JSReceiver>();
5338 DCHECK_IMPLIES(receiver->IsJSProxy(), it->GetName()->IsPrivateField());
5339 DCHECK_IMPLIES(receiver->IsJSProxy(),
5340 it->state() == LookupIterator::NOT_FOUND);
5341
5342 // If the receiver is a JSGlobalProxy, store on the prototype (JSGlobalObject)
5343 // instead. If the prototype is Null, the proxy is detached.
5344 if (receiver->IsJSGlobalProxy()) return Just(true);
5345
5346 Isolate* isolate = it->isolate();
5347
5348 if (it->ExtendingNonExtensible(receiver)) {
5349 RETURN_FAILURE(
5350 isolate, should_throw,
5351 NewTypeError(MessageTemplate::kObjectNotExtensible, it->GetName()));
5352 }
5353
5354 if (it->IsElement()) {
5355 if (receiver->IsJSArray()) {
5356 Handle<JSArray> array = Handle<JSArray>::cast(receiver);
5357 if (JSArray::WouldChangeReadOnlyLength(array, it->index())) {
5358 RETURN_FAILURE(isolate, should_throw,
5359 NewTypeError(MessageTemplate::kStrictReadOnlyProperty,
5360 isolate->factory()->length_string(),
5361 Object::TypeOf(isolate, array), array));
5362 }
5363
5364 if (FLAG_trace_external_array_abuse &&
5365 array->HasFixedTypedArrayElements()) {
5366 CheckArrayAbuse(array, "typed elements write", it->index(), true);
5367 }
5368
5369 if (FLAG_trace_js_array_abuse && !array->HasFixedTypedArrayElements()) {
5370 CheckArrayAbuse(array, "elements write", it->index(), false);
5371 }
5372 }
5373
5374 Handle<JSObject> receiver_obj = Handle<JSObject>::cast(receiver);
5375 JSObject::AddDataElement(receiver_obj, it->index(), value, attributes);
5376 JSObject::ValidateElements(*receiver_obj);
5377 return Just(true);
5378 } else {
5379 it->UpdateProtector();
5380 // Migrate to the most up-to-date map that will be able to store |value|
5381 // under it->name() with |attributes|.
5382 it->PrepareTransitionToDataProperty(receiver, value, attributes,
5383 store_mode);
5384 DCHECK_EQ(LookupIterator::TRANSITION, it->state());
5385 it->ApplyTransitionToDataProperty(receiver);
5386
5387 // Write the property value.
5388 it->WriteDataValue(value, true);
5389
5390 #if VERIFY_HEAP
5391 if (FLAG_verify_heap) {
5392 receiver->HeapObjectVerify(isolate);
5393 }
5394 #endif
5395 }
5396
5397 return Just(true);
5398 }
5399
EnsureDescriptorSlack(Isolate * isolate,Handle<Map> map,int slack)5400 void Map::EnsureDescriptorSlack(Isolate* isolate, Handle<Map> map, int slack) {
5401 // Only supports adding slack to owned descriptors.
5402 DCHECK(map->owns_descriptors());
5403
5404 Handle<DescriptorArray> descriptors(map->instance_descriptors(), isolate);
5405 int old_size = map->NumberOfOwnDescriptors();
5406 if (slack <= descriptors->NumberOfSlackDescriptors()) return;
5407
5408 Handle<DescriptorArray> new_descriptors =
5409 DescriptorArray::CopyUpTo(isolate, descriptors, old_size, slack);
5410
5411 DisallowHeapAllocation no_allocation;
5412 // The descriptors are still the same, so keep the layout descriptor.
5413 LayoutDescriptor* layout_descriptor = map->GetLayoutDescriptor();
5414
5415 if (old_size == 0) {
5416 map->UpdateDescriptors(*new_descriptors, layout_descriptor);
5417 return;
5418 }
5419
5420 // If the source descriptors had an enum cache we copy it. This ensures
5421 // that the maps to which we push the new descriptor array back can rely
5422 // on a cache always being available once it is set. If the map has more
5423 // enumerated descriptors than available in the original cache, the cache
5424 // will be lazily replaced by the extended cache when needed.
5425 new_descriptors->CopyEnumCacheFrom(*descriptors);
5426
5427 // Replace descriptors by new_descriptors in all maps that share it. The old
5428 // descriptors will not be trimmed in the mark-compactor, we need to mark
5429 // all its elements.
5430 MarkingBarrierForElements(isolate->heap(), *descriptors);
5431
5432 Map* current = *map;
5433 while (current->instance_descriptors() == *descriptors) {
5434 Object* next = current->GetBackPointer();
5435 if (next->IsUndefined(isolate)) break; // Stop overwriting at initial map.
5436 current->UpdateDescriptors(*new_descriptors, layout_descriptor);
5437 current = Map::cast(next);
5438 }
5439 map->UpdateDescriptors(*new_descriptors, layout_descriptor);
5440 }
5441
5442 // static
GetObjectCreateMap(Isolate * isolate,Handle<HeapObject> prototype)5443 Handle<Map> Map::GetObjectCreateMap(Isolate* isolate,
5444 Handle<HeapObject> prototype) {
5445 Handle<Map> map(isolate->native_context()->object_function()->initial_map(),
5446 isolate);
5447 if (map->prototype() == *prototype) return map;
5448 if (prototype->IsNull(isolate)) {
5449 return isolate->slow_object_with_null_prototype_map();
5450 }
5451 if (prototype->IsJSObject()) {
5452 Handle<JSObject> js_prototype = Handle<JSObject>::cast(prototype);
5453 if (!js_prototype->map()->is_prototype_map()) {
5454 JSObject::OptimizeAsPrototype(js_prototype);
5455 }
5456 Handle<PrototypeInfo> info =
5457 Map::GetOrCreatePrototypeInfo(js_prototype, isolate);
5458 // TODO(verwaest): Use inobject slack tracking for this map.
5459 if (info->HasObjectCreateMap()) {
5460 map = handle(info->ObjectCreateMap(), isolate);
5461 } else {
5462 map = Map::CopyInitialMap(isolate, map);
5463 Map::SetPrototype(isolate, map, prototype);
5464 PrototypeInfo::SetObjectCreateMap(info, map);
5465 }
5466 return map;
5467 }
5468
5469 return Map::TransitionToPrototype(isolate, map, prototype);
5470 }
5471
5472 // static
TryGetObjectCreateMap(Isolate * isolate,Handle<HeapObject> prototype)5473 MaybeHandle<Map> Map::TryGetObjectCreateMap(Isolate* isolate,
5474 Handle<HeapObject> prototype) {
5475 Handle<Map> map(isolate->native_context()->object_function()->initial_map(),
5476 isolate);
5477 if (map->prototype() == *prototype) return map;
5478 if (prototype->IsNull(isolate)) {
5479 return isolate->slow_object_with_null_prototype_map();
5480 }
5481 if (!prototype->IsJSObject()) return MaybeHandle<Map>();
5482 Handle<JSObject> js_prototype = Handle<JSObject>::cast(prototype);
5483 if (!js_prototype->map()->is_prototype_map()) return MaybeHandle<Map>();
5484 Handle<PrototypeInfo> info =
5485 Map::GetOrCreatePrototypeInfo(js_prototype, isolate);
5486 if (!info->HasObjectCreateMap()) return MaybeHandle<Map>();
5487 return handle(info->ObjectCreateMap(), isolate);
5488 }
5489
5490 template <class T>
AppendUniqueCallbacks(Isolate * isolate,Handle<TemplateList> callbacks,Handle<typename T::Array> array,int valid_descriptors)5491 static int AppendUniqueCallbacks(Isolate* isolate,
5492 Handle<TemplateList> callbacks,
5493 Handle<typename T::Array> array,
5494 int valid_descriptors) {
5495 int nof_callbacks = callbacks->length();
5496
5497 // Fill in new callback descriptors. Process the callbacks from
5498 // back to front so that the last callback with a given name takes
5499 // precedence over previously added callbacks with that name.
5500 for (int i = nof_callbacks - 1; i >= 0; i--) {
5501 Handle<AccessorInfo> entry(AccessorInfo::cast(callbacks->get(i)), isolate);
5502 Handle<Name> key(Name::cast(entry->name()), isolate);
5503 DCHECK(key->IsUniqueName());
5504 // Check if a descriptor with this name already exists before writing.
5505 if (!T::Contains(key, entry, valid_descriptors, array)) {
5506 T::Insert(key, entry, valid_descriptors, array);
5507 valid_descriptors++;
5508 }
5509 }
5510
5511 return valid_descriptors;
5512 }
5513
5514 struct FixedArrayAppender {
5515 typedef FixedArray Array;
Containsv8::internal::FixedArrayAppender5516 static bool Contains(Handle<Name> key,
5517 Handle<AccessorInfo> entry,
5518 int valid_descriptors,
5519 Handle<FixedArray> array) {
5520 for (int i = 0; i < valid_descriptors; i++) {
5521 if (*key == AccessorInfo::cast(array->get(i))->name()) return true;
5522 }
5523 return false;
5524 }
Insertv8::internal::FixedArrayAppender5525 static void Insert(Handle<Name> key,
5526 Handle<AccessorInfo> entry,
5527 int valid_descriptors,
5528 Handle<FixedArray> array) {
5529 DisallowHeapAllocation no_gc;
5530 array->set(valid_descriptors, *entry);
5531 }
5532 };
5533
AppendUnique(Isolate * isolate,Handle<Object> descriptors,Handle<FixedArray> array,int valid_descriptors)5534 int AccessorInfo::AppendUnique(Isolate* isolate, Handle<Object> descriptors,
5535 Handle<FixedArray> array,
5536 int valid_descriptors) {
5537 Handle<TemplateList> callbacks = Handle<TemplateList>::cast(descriptors);
5538 DCHECK_GE(array->length(), callbacks->length() + valid_descriptors);
5539 return AppendUniqueCallbacks<FixedArrayAppender>(isolate, callbacks, array,
5540 valid_descriptors);
5541 }
5542
ContainsMap(MapHandles const & maps,Map * map)5543 static bool ContainsMap(MapHandles const& maps, Map* map) {
5544 DCHECK_NOT_NULL(map);
5545 for (Handle<Map> current : maps) {
5546 if (!current.is_null() && *current == map) return true;
5547 }
5548 return false;
5549 }
5550
FindElementsKindTransitionedMap(Isolate * isolate,MapHandles const & candidates)5551 Map* Map::FindElementsKindTransitionedMap(Isolate* isolate,
5552 MapHandles const& candidates) {
5553 DisallowHeapAllocation no_allocation;
5554 DisallowDeoptimization no_deoptimization(isolate);
5555
5556 if (is_prototype_map()) return nullptr;
5557
5558 ElementsKind kind = elements_kind();
5559 bool packed = IsFastPackedElementsKind(kind);
5560
5561 Map* transition = nullptr;
5562 if (IsTransitionableFastElementsKind(kind)) {
5563 // Check the state of the root map.
5564 Map* root_map = FindRootMap(isolate);
5565 if (!EquivalentToForElementsKindTransition(root_map)) return nullptr;
5566 root_map = root_map->LookupElementsTransitionMap(isolate, kind);
5567 DCHECK_NOT_NULL(root_map);
5568 // Starting from the next existing elements kind transition try to
5569 // replay the property transitions that does not involve instance rewriting
5570 // (ElementsTransitionAndStoreStub does not support that).
5571 for (root_map = root_map->ElementsTransitionMap();
5572 root_map != nullptr && root_map->has_fast_elements();
5573 root_map = root_map->ElementsTransitionMap()) {
5574 Map* current = root_map->TryReplayPropertyTransitions(isolate, this);
5575 if (current == nullptr) continue;
5576 if (InstancesNeedRewriting(current)) continue;
5577
5578 if (ContainsMap(candidates, current) &&
5579 (packed || !IsFastPackedElementsKind(current->elements_kind()))) {
5580 transition = current;
5581 packed = packed && IsFastPackedElementsKind(current->elements_kind());
5582 }
5583 }
5584 }
5585 return transition;
5586 }
5587
FindClosestElementsTransition(Isolate * isolate,Map * map,ElementsKind to_kind)5588 static Map* FindClosestElementsTransition(Isolate* isolate, Map* map,
5589 ElementsKind to_kind) {
5590 // Ensure we are requested to search elements kind transition "near the root".
5591 DCHECK_EQ(map->FindRootMap(isolate)->NumberOfOwnDescriptors(),
5592 map->NumberOfOwnDescriptors());
5593 Map* current_map = map;
5594
5595 ElementsKind kind = map->elements_kind();
5596 while (kind != to_kind) {
5597 Map* next_map = current_map->ElementsTransitionMap();
5598 if (next_map == nullptr) return current_map;
5599 kind = next_map->elements_kind();
5600 current_map = next_map;
5601 }
5602
5603 DCHECK_EQ(to_kind, current_map->elements_kind());
5604 return current_map;
5605 }
5606
LookupElementsTransitionMap(Isolate * isolate,ElementsKind to_kind)5607 Map* Map::LookupElementsTransitionMap(Isolate* isolate, ElementsKind to_kind) {
5608 Map* to_map = FindClosestElementsTransition(isolate, this, to_kind);
5609 if (to_map->elements_kind() == to_kind) return to_map;
5610 return nullptr;
5611 }
5612
IsMapInArrayPrototypeChain(Isolate * isolate) const5613 bool Map::IsMapInArrayPrototypeChain(Isolate* isolate) const {
5614 if (isolate->initial_array_prototype()->map() == this) {
5615 return true;
5616 }
5617
5618 if (isolate->initial_object_prototype()->map() == this) {
5619 return true;
5620 }
5621
5622 return false;
5623 }
5624
AddMissingElementsTransitions(Isolate * isolate,Handle<Map> map,ElementsKind to_kind)5625 static Handle<Map> AddMissingElementsTransitions(Isolate* isolate,
5626 Handle<Map> map,
5627 ElementsKind to_kind) {
5628 DCHECK(IsTransitionElementsKind(map->elements_kind()));
5629
5630 Handle<Map> current_map = map;
5631
5632 ElementsKind kind = map->elements_kind();
5633 TransitionFlag flag;
5634 if (map->is_prototype_map()) {
5635 flag = OMIT_TRANSITION;
5636 } else {
5637 flag = INSERT_TRANSITION;
5638 if (IsFastElementsKind(kind)) {
5639 while (kind != to_kind && !IsTerminalElementsKind(kind)) {
5640 kind = GetNextTransitionElementsKind(kind);
5641 current_map = Map::CopyAsElementsKind(isolate, current_map, kind, flag);
5642 }
5643 }
5644 }
5645
5646 // In case we are exiting the fast elements kind system, just add the map in
5647 // the end.
5648 if (kind != to_kind) {
5649 current_map = Map::CopyAsElementsKind(isolate, current_map, to_kind, flag);
5650 }
5651
5652 DCHECK(current_map->elements_kind() == to_kind);
5653 return current_map;
5654 }
5655
TransitionElementsTo(Isolate * isolate,Handle<Map> map,ElementsKind to_kind)5656 Handle<Map> Map::TransitionElementsTo(Isolate* isolate, Handle<Map> map,
5657 ElementsKind to_kind) {
5658 ElementsKind from_kind = map->elements_kind();
5659 if (from_kind == to_kind) return map;
5660
5661 Context* native_context = isolate->context()->native_context();
5662 if (from_kind == FAST_SLOPPY_ARGUMENTS_ELEMENTS) {
5663 if (*map == native_context->fast_aliased_arguments_map()) {
5664 DCHECK_EQ(SLOW_SLOPPY_ARGUMENTS_ELEMENTS, to_kind);
5665 return handle(native_context->slow_aliased_arguments_map(), isolate);
5666 }
5667 } else if (from_kind == SLOW_SLOPPY_ARGUMENTS_ELEMENTS) {
5668 if (*map == native_context->slow_aliased_arguments_map()) {
5669 DCHECK_EQ(FAST_SLOPPY_ARGUMENTS_ELEMENTS, to_kind);
5670 return handle(native_context->fast_aliased_arguments_map(), isolate);
5671 }
5672 } else if (IsFastElementsKind(from_kind) && IsFastElementsKind(to_kind)) {
5673 // Reuse map transitions for JSArrays.
5674 DisallowHeapAllocation no_gc;
5675 if (native_context->GetInitialJSArrayMap(from_kind) == *map) {
5676 Object* maybe_transitioned_map =
5677 native_context->get(Context::ArrayMapIndex(to_kind));
5678 if (maybe_transitioned_map->IsMap()) {
5679 return handle(Map::cast(maybe_transitioned_map), isolate);
5680 }
5681 }
5682 }
5683
5684 DCHECK(!map->IsUndefined(isolate));
5685 // Check if we can go back in the elements kind transition chain.
5686 if (IsHoleyElementsKind(from_kind) &&
5687 to_kind == GetPackedElementsKind(from_kind) &&
5688 map->GetBackPointer()->IsMap() &&
5689 Map::cast(map->GetBackPointer())->elements_kind() == to_kind) {
5690 return handle(Map::cast(map->GetBackPointer()), isolate);
5691 }
5692
5693 bool allow_store_transition = IsTransitionElementsKind(from_kind);
5694 // Only store fast element maps in ascending generality.
5695 if (IsFastElementsKind(to_kind)) {
5696 allow_store_transition =
5697 allow_store_transition && IsTransitionableFastElementsKind(from_kind) &&
5698 IsMoreGeneralElementsKindTransition(from_kind, to_kind);
5699 }
5700
5701 if (!allow_store_transition) {
5702 return Map::CopyAsElementsKind(isolate, map, to_kind, OMIT_TRANSITION);
5703 }
5704
5705 return Map::ReconfigureElementsKind(isolate, map, to_kind);
5706 }
5707
5708
5709 // static
AsElementsKind(Isolate * isolate,Handle<Map> map,ElementsKind kind)5710 Handle<Map> Map::AsElementsKind(Isolate* isolate, Handle<Map> map,
5711 ElementsKind kind) {
5712 Handle<Map> closest_map(FindClosestElementsTransition(isolate, *map, kind),
5713 isolate);
5714
5715 if (closest_map->elements_kind() == kind) {
5716 return closest_map;
5717 }
5718
5719 return AddMissingElementsTransitions(isolate, closest_map, kind);
5720 }
5721
5722
GetElementsTransitionMap(Handle<JSObject> object,ElementsKind to_kind)5723 Handle<Map> JSObject::GetElementsTransitionMap(Handle<JSObject> object,
5724 ElementsKind to_kind) {
5725 Handle<Map> map(object->map(), object->GetIsolate());
5726 return Map::TransitionElementsTo(object->GetIsolate(), map, to_kind);
5727 }
5728
5729
Revoke(Handle<JSProxy> proxy)5730 void JSProxy::Revoke(Handle<JSProxy> proxy) {
5731 Isolate* isolate = proxy->GetIsolate();
5732 // ES#sec-proxy-revocation-functions
5733 if (!proxy->IsRevoked()) {
5734 // 5. Set p.[[ProxyTarget]] to null.
5735 proxy->set_target(ReadOnlyRoots(isolate).null_value());
5736 // 6. Set p.[[ProxyHandler]] to null.
5737 proxy->set_handler(ReadOnlyRoots(isolate).null_value());
5738 }
5739 DCHECK(proxy->IsRevoked());
5740 }
5741
5742 // static
IsArray(Handle<JSProxy> proxy)5743 Maybe<bool> JSProxy::IsArray(Handle<JSProxy> proxy) {
5744 Isolate* isolate = proxy->GetIsolate();
5745 Handle<JSReceiver> object = Handle<JSReceiver>::cast(proxy);
5746 for (int i = 0; i < JSProxy::kMaxIterationLimit; i++) {
5747 Handle<JSProxy> proxy = Handle<JSProxy>::cast(object);
5748 if (proxy->IsRevoked()) {
5749 isolate->Throw(*isolate->factory()->NewTypeError(
5750 MessageTemplate::kProxyRevoked,
5751 isolate->factory()->NewStringFromAsciiChecked("IsArray")));
5752 return Nothing<bool>();
5753 }
5754 object = handle(JSReceiver::cast(proxy->target()), isolate);
5755 if (object->IsJSArray()) return Just(true);
5756 if (!object->IsJSProxy()) return Just(false);
5757 }
5758
5759 // Too deep recursion, throw a RangeError.
5760 isolate->StackOverflow();
5761 return Nothing<bool>();
5762 }
5763
HasProperty(Isolate * isolate,Handle<JSProxy> proxy,Handle<Name> name)5764 Maybe<bool> JSProxy::HasProperty(Isolate* isolate, Handle<JSProxy> proxy,
5765 Handle<Name> name) {
5766 DCHECK(!name->IsPrivate());
5767 STACK_CHECK(isolate, Nothing<bool>());
5768 // 1. (Assert)
5769 // 2. Let handler be the value of the [[ProxyHandler]] internal slot of O.
5770 Handle<Object> handler(proxy->handler(), isolate);
5771 // 3. If handler is null, throw a TypeError exception.
5772 // 4. Assert: Type(handler) is Object.
5773 if (proxy->IsRevoked()) {
5774 isolate->Throw(*isolate->factory()->NewTypeError(
5775 MessageTemplate::kProxyRevoked, isolate->factory()->has_string()));
5776 return Nothing<bool>();
5777 }
5778 // 5. Let target be the value of the [[ProxyTarget]] internal slot of O.
5779 Handle<JSReceiver> target(JSReceiver::cast(proxy->target()), isolate);
5780 // 6. Let trap be ? GetMethod(handler, "has").
5781 Handle<Object> trap;
5782 ASSIGN_RETURN_ON_EXCEPTION_VALUE(
5783 isolate, trap, Object::GetMethod(Handle<JSReceiver>::cast(handler),
5784 isolate->factory()->has_string()),
5785 Nothing<bool>());
5786 // 7. If trap is undefined, then
5787 if (trap->IsUndefined(isolate)) {
5788 // 7a. Return target.[[HasProperty]](P).
5789 return JSReceiver::HasProperty(target, name);
5790 }
5791 // 8. Let booleanTrapResult be ToBoolean(? Call(trap, handler, «target, P»)).
5792 Handle<Object> trap_result_obj;
5793 Handle<Object> args[] = {target, name};
5794 ASSIGN_RETURN_ON_EXCEPTION_VALUE(
5795 isolate, trap_result_obj,
5796 Execution::Call(isolate, trap, handler, arraysize(args), args),
5797 Nothing<bool>());
5798 bool boolean_trap_result = trap_result_obj->BooleanValue(isolate);
5799 // 9. If booleanTrapResult is false, then:
5800 if (!boolean_trap_result) {
5801 MAYBE_RETURN(JSProxy::CheckHasTrap(isolate, name, target), Nothing<bool>());
5802 }
5803 // 10. Return booleanTrapResult.
5804 return Just(boolean_trap_result);
5805 }
5806
CheckHasTrap(Isolate * isolate,Handle<Name> name,Handle<JSReceiver> target)5807 Maybe<bool> JSProxy::CheckHasTrap(Isolate* isolate, Handle<Name> name,
5808 Handle<JSReceiver> target) {
5809 // 9a. Let targetDesc be ? target.[[GetOwnProperty]](P).
5810 PropertyDescriptor target_desc;
5811 Maybe<bool> target_found =
5812 JSReceiver::GetOwnPropertyDescriptor(isolate, target, name, &target_desc);
5813 MAYBE_RETURN(target_found, Nothing<bool>());
5814 // 9b. If targetDesc is not undefined, then:
5815 if (target_found.FromJust()) {
5816 // 9b i. If targetDesc.[[Configurable]] is false, throw a TypeError
5817 // exception.
5818 if (!target_desc.configurable()) {
5819 isolate->Throw(*isolate->factory()->NewTypeError(
5820 MessageTemplate::kProxyHasNonConfigurable, name));
5821 return Nothing<bool>();
5822 }
5823 // 9b ii. Let extensibleTarget be ? IsExtensible(target).
5824 Maybe<bool> extensible_target = JSReceiver::IsExtensible(target);
5825 MAYBE_RETURN(extensible_target, Nothing<bool>());
5826 // 9b iii. If extensibleTarget is false, throw a TypeError exception.
5827 if (!extensible_target.FromJust()) {
5828 isolate->Throw(*isolate->factory()->NewTypeError(
5829 MessageTemplate::kProxyHasNonExtensible, name));
5830 return Nothing<bool>();
5831 }
5832 }
5833 return Just(true);
5834 }
5835
SetProperty(Handle<JSProxy> proxy,Handle<Name> name,Handle<Object> value,Handle<Object> receiver,LanguageMode language_mode)5836 Maybe<bool> JSProxy::SetProperty(Handle<JSProxy> proxy, Handle<Name> name,
5837 Handle<Object> value, Handle<Object> receiver,
5838 LanguageMode language_mode) {
5839 DCHECK(!name->IsPrivate());
5840 Isolate* isolate = proxy->GetIsolate();
5841 STACK_CHECK(isolate, Nothing<bool>());
5842 Factory* factory = isolate->factory();
5843 Handle<String> trap_name = factory->set_string();
5844 ShouldThrow should_throw =
5845 is_sloppy(language_mode) ? kDontThrow : kThrowOnError;
5846
5847 if (proxy->IsRevoked()) {
5848 isolate->Throw(
5849 *factory->NewTypeError(MessageTemplate::kProxyRevoked, trap_name));
5850 return Nothing<bool>();
5851 }
5852 Handle<JSReceiver> target(JSReceiver::cast(proxy->target()), isolate);
5853 Handle<JSReceiver> handler(JSReceiver::cast(proxy->handler()), isolate);
5854
5855 Handle<Object> trap;
5856 ASSIGN_RETURN_ON_EXCEPTION_VALUE(
5857 isolate, trap, Object::GetMethod(handler, trap_name), Nothing<bool>());
5858 if (trap->IsUndefined(isolate)) {
5859 LookupIterator it =
5860 LookupIterator::PropertyOrElement(isolate, receiver, name, target);
5861 return Object::SetSuperProperty(&it, value, language_mode,
5862 Object::MAY_BE_STORE_FROM_KEYED);
5863 }
5864
5865 Handle<Object> trap_result;
5866 Handle<Object> args[] = {target, name, value, receiver};
5867 ASSIGN_RETURN_ON_EXCEPTION_VALUE(
5868 isolate, trap_result,
5869 Execution::Call(isolate, trap, handler, arraysize(args), args),
5870 Nothing<bool>());
5871 if (!trap_result->BooleanValue(isolate)) {
5872 RETURN_FAILURE(isolate, should_throw,
5873 NewTypeError(MessageTemplate::kProxyTrapReturnedFalsishFor,
5874 trap_name, name));
5875 }
5876
5877 MaybeHandle<Object> result =
5878 JSProxy::CheckGetSetTrapResult(isolate, name, target, value, kSet);
5879
5880 if (result.is_null()) {
5881 return Nothing<bool>();
5882 }
5883 return Just(true);
5884 }
5885
5886
DeletePropertyOrElement(Handle<JSProxy> proxy,Handle<Name> name,LanguageMode language_mode)5887 Maybe<bool> JSProxy::DeletePropertyOrElement(Handle<JSProxy> proxy,
5888 Handle<Name> name,
5889 LanguageMode language_mode) {
5890 DCHECK(!name->IsPrivate());
5891 ShouldThrow should_throw =
5892 is_sloppy(language_mode) ? kDontThrow : kThrowOnError;
5893 Isolate* isolate = proxy->GetIsolate();
5894 STACK_CHECK(isolate, Nothing<bool>());
5895 Factory* factory = isolate->factory();
5896 Handle<String> trap_name = factory->deleteProperty_string();
5897
5898 if (proxy->IsRevoked()) {
5899 isolate->Throw(
5900 *factory->NewTypeError(MessageTemplate::kProxyRevoked, trap_name));
5901 return Nothing<bool>();
5902 }
5903 Handle<JSReceiver> target(JSReceiver::cast(proxy->target()), isolate);
5904 Handle<JSReceiver> handler(JSReceiver::cast(proxy->handler()), isolate);
5905
5906 Handle<Object> trap;
5907 ASSIGN_RETURN_ON_EXCEPTION_VALUE(
5908 isolate, trap, Object::GetMethod(handler, trap_name), Nothing<bool>());
5909 if (trap->IsUndefined(isolate)) {
5910 return JSReceiver::DeletePropertyOrElement(target, name, language_mode);
5911 }
5912
5913 Handle<Object> trap_result;
5914 Handle<Object> args[] = {target, name};
5915 ASSIGN_RETURN_ON_EXCEPTION_VALUE(
5916 isolate, trap_result,
5917 Execution::Call(isolate, trap, handler, arraysize(args), args),
5918 Nothing<bool>());
5919 if (!trap_result->BooleanValue(isolate)) {
5920 RETURN_FAILURE(isolate, should_throw,
5921 NewTypeError(MessageTemplate::kProxyTrapReturnedFalsishFor,
5922 trap_name, name));
5923 }
5924
5925 // Enforce the invariant.
5926 PropertyDescriptor target_desc;
5927 Maybe<bool> owned =
5928 JSReceiver::GetOwnPropertyDescriptor(isolate, target, name, &target_desc);
5929 MAYBE_RETURN(owned, Nothing<bool>());
5930 if (owned.FromJust() && !target_desc.configurable()) {
5931 isolate->Throw(*factory->NewTypeError(
5932 MessageTemplate::kProxyDeletePropertyNonConfigurable, name));
5933 return Nothing<bool>();
5934 }
5935 return Just(true);
5936 }
5937
5938
5939 // static
New(Isolate * isolate,Handle<Object> target,Handle<Object> handler)5940 MaybeHandle<JSProxy> JSProxy::New(Isolate* isolate, Handle<Object> target,
5941 Handle<Object> handler) {
5942 if (!target->IsJSReceiver()) {
5943 THROW_NEW_ERROR(isolate, NewTypeError(MessageTemplate::kProxyNonObject),
5944 JSProxy);
5945 }
5946 if (target->IsJSProxy() && JSProxy::cast(*target)->IsRevoked()) {
5947 THROW_NEW_ERROR(isolate,
5948 NewTypeError(MessageTemplate::kProxyHandlerOrTargetRevoked),
5949 JSProxy);
5950 }
5951 if (!handler->IsJSReceiver()) {
5952 THROW_NEW_ERROR(isolate, NewTypeError(MessageTemplate::kProxyNonObject),
5953 JSProxy);
5954 }
5955 if (handler->IsJSProxy() && JSProxy::cast(*handler)->IsRevoked()) {
5956 THROW_NEW_ERROR(isolate,
5957 NewTypeError(MessageTemplate::kProxyHandlerOrTargetRevoked),
5958 JSProxy);
5959 }
5960 return isolate->factory()->NewJSProxy(Handle<JSReceiver>::cast(target),
5961 Handle<JSReceiver>::cast(handler));
5962 }
5963
5964
5965 // static
GetFunctionRealm(Handle<JSProxy> proxy)5966 MaybeHandle<Context> JSProxy::GetFunctionRealm(Handle<JSProxy> proxy) {
5967 DCHECK(proxy->map()->is_constructor());
5968 if (proxy->IsRevoked()) {
5969 THROW_NEW_ERROR(proxy->GetIsolate(),
5970 NewTypeError(MessageTemplate::kProxyRevoked), Context);
5971 }
5972 Handle<JSReceiver> target(JSReceiver::cast(proxy->target()),
5973 proxy->GetIsolate());
5974 return JSReceiver::GetFunctionRealm(target);
5975 }
5976
5977
5978 // static
GetFunctionRealm(Handle<JSBoundFunction> function)5979 MaybeHandle<Context> JSBoundFunction::GetFunctionRealm(
5980 Handle<JSBoundFunction> function) {
5981 DCHECK(function->map()->is_constructor());
5982 return JSReceiver::GetFunctionRealm(
5983 handle(function->bound_target_function(), function->GetIsolate()));
5984 }
5985
5986 // static
GetName(Isolate * isolate,Handle<JSBoundFunction> function)5987 MaybeHandle<String> JSBoundFunction::GetName(Isolate* isolate,
5988 Handle<JSBoundFunction> function) {
5989 Handle<String> prefix = isolate->factory()->bound__string();
5990 Handle<String> target_name = prefix;
5991 Factory* factory = isolate->factory();
5992 // Concatenate the "bound " up to the last non-bound target.
5993 while (function->bound_target_function()->IsJSBoundFunction()) {
5994 ASSIGN_RETURN_ON_EXCEPTION(isolate, target_name,
5995 factory->NewConsString(prefix, target_name),
5996 String);
5997 function = handle(JSBoundFunction::cast(function->bound_target_function()),
5998 isolate);
5999 }
6000 if (function->bound_target_function()->IsJSFunction()) {
6001 Handle<JSFunction> target(
6002 JSFunction::cast(function->bound_target_function()), isolate);
6003 Handle<Object> name = JSFunction::GetName(isolate, target);
6004 if (!name->IsString()) return target_name;
6005 return factory->NewConsString(target_name, Handle<String>::cast(name));
6006 }
6007 // This will omit the proper target name for bound JSProxies.
6008 return target_name;
6009 }
6010
6011 // static
GetLength(Isolate * isolate,Handle<JSBoundFunction> function)6012 Maybe<int> JSBoundFunction::GetLength(Isolate* isolate,
6013 Handle<JSBoundFunction> function) {
6014 int nof_bound_arguments = function->bound_arguments()->length();
6015 while (function->bound_target_function()->IsJSBoundFunction()) {
6016 function = handle(JSBoundFunction::cast(function->bound_target_function()),
6017 isolate);
6018 // Make sure we never overflow {nof_bound_arguments}, the number of
6019 // arguments of a function is strictly limited by the max length of an
6020 // JSAarray, Smi::kMaxValue is thus a reasonably good overestimate.
6021 int length = function->bound_arguments()->length();
6022 if (V8_LIKELY(Smi::kMaxValue - nof_bound_arguments > length)) {
6023 nof_bound_arguments += length;
6024 } else {
6025 nof_bound_arguments = Smi::kMaxValue;
6026 }
6027 }
6028 // All non JSFunction targets get a direct property and don't use this
6029 // accessor.
6030 Handle<JSFunction> target(JSFunction::cast(function->bound_target_function()),
6031 isolate);
6032 Maybe<int> target_length = JSFunction::GetLength(isolate, target);
6033 if (target_length.IsNothing()) return target_length;
6034
6035 int length = Max(0, target_length.FromJust() - nof_bound_arguments);
6036 return Just(length);
6037 }
6038
6039 // static
GetName(Isolate * isolate,Handle<JSFunction> function)6040 Handle<Object> JSFunction::GetName(Isolate* isolate,
6041 Handle<JSFunction> function) {
6042 if (function->shared()->name_should_print_as_anonymous()) {
6043 return isolate->factory()->anonymous_string();
6044 }
6045 return handle(function->shared()->Name(), isolate);
6046 }
6047
6048 // static
GetLength(Isolate * isolate,Handle<JSFunction> function)6049 Maybe<int> JSFunction::GetLength(Isolate* isolate,
6050 Handle<JSFunction> function) {
6051 int length = 0;
6052 if (function->shared()->is_compiled()) {
6053 length = function->shared()->GetLength();
6054 } else {
6055 // If the function isn't compiled yet, the length is not computed
6056 // correctly yet. Compile it now and return the right length.
6057 if (Compiler::Compile(function, Compiler::KEEP_EXCEPTION)) {
6058 length = function->shared()->GetLength();
6059 }
6060 if (isolate->has_pending_exception()) return Nothing<int>();
6061 }
6062 DCHECK_GE(length, 0);
6063 return Just(length);
6064 }
6065
6066 // static
GetFunctionRealm(Handle<JSFunction> function)6067 Handle<Context> JSFunction::GetFunctionRealm(Handle<JSFunction> function) {
6068 DCHECK(function->map()->is_constructor());
6069 return handle(function->context()->native_context(), function->GetIsolate());
6070 }
6071
6072
6073 // static
GetFunctionRealm(Handle<JSObject> object)6074 MaybeHandle<Context> JSObject::GetFunctionRealm(Handle<JSObject> object) {
6075 DCHECK(object->map()->is_constructor());
6076 DCHECK(!object->IsJSFunction());
6077 return object->GetCreationContext();
6078 }
6079
6080
6081 // static
GetFunctionRealm(Handle<JSReceiver> receiver)6082 MaybeHandle<Context> JSReceiver::GetFunctionRealm(Handle<JSReceiver> receiver) {
6083 if (receiver->IsJSProxy()) {
6084 return JSProxy::GetFunctionRealm(Handle<JSProxy>::cast(receiver));
6085 }
6086
6087 if (receiver->IsJSFunction()) {
6088 return JSFunction::GetFunctionRealm(Handle<JSFunction>::cast(receiver));
6089 }
6090
6091 if (receiver->IsJSBoundFunction()) {
6092 return JSBoundFunction::GetFunctionRealm(
6093 Handle<JSBoundFunction>::cast(receiver));
6094 }
6095
6096 return JSObject::GetFunctionRealm(Handle<JSObject>::cast(receiver));
6097 }
6098
6099
GetPropertyAttributes(LookupIterator * it)6100 Maybe<PropertyAttributes> JSProxy::GetPropertyAttributes(LookupIterator* it) {
6101 PropertyDescriptor desc;
6102 Maybe<bool> found = JSProxy::GetOwnPropertyDescriptor(
6103 it->isolate(), it->GetHolder<JSProxy>(), it->GetName(), &desc);
6104 MAYBE_RETURN(found, Nothing<PropertyAttributes>());
6105 if (!found.FromJust()) return Just(ABSENT);
6106 return Just(desc.ToAttributes());
6107 }
6108
6109
AllocateStorageForMap(Handle<JSObject> object,Handle<Map> map)6110 void JSObject::AllocateStorageForMap(Handle<JSObject> object, Handle<Map> map) {
6111 DCHECK(object->map()->GetInObjectProperties() ==
6112 map->GetInObjectProperties());
6113 ElementsKind obj_kind = object->map()->elements_kind();
6114 ElementsKind map_kind = map->elements_kind();
6115 if (map_kind != obj_kind) {
6116 ElementsKind to_kind = GetMoreGeneralElementsKind(map_kind, obj_kind);
6117 if (IsDictionaryElementsKind(obj_kind)) {
6118 to_kind = obj_kind;
6119 }
6120 if (IsDictionaryElementsKind(to_kind)) {
6121 NormalizeElements(object);
6122 } else {
6123 TransitionElementsKind(object, to_kind);
6124 }
6125 map = Map::ReconfigureElementsKind(object->GetIsolate(), map, to_kind);
6126 }
6127 int number_of_fields = map->NumberOfFields();
6128 int inobject = map->GetInObjectProperties();
6129 int unused = map->UnusedPropertyFields();
6130 int total_size = number_of_fields + unused;
6131 int external = total_size - inobject;
6132 // Allocate mutable double boxes if necessary. It is always necessary if we
6133 // have external properties, but is also necessary if we only have inobject
6134 // properties but don't unbox double fields.
6135 if (!FLAG_unbox_double_fields || external > 0) {
6136 Isolate* isolate = object->GetIsolate();
6137
6138 Handle<DescriptorArray> descriptors(map->instance_descriptors(), isolate);
6139 Handle<FixedArray> storage;
6140 if (!FLAG_unbox_double_fields) {
6141 storage = isolate->factory()->NewFixedArray(inobject);
6142 }
6143
6144 Handle<PropertyArray> array =
6145 isolate->factory()->NewPropertyArray(external);
6146
6147 for (int i = 0; i < map->NumberOfOwnDescriptors(); i++) {
6148 PropertyDetails details = descriptors->GetDetails(i);
6149 Representation representation = details.representation();
6150 if (!representation.IsDouble()) continue;
6151 FieldIndex index = FieldIndex::ForDescriptor(*map, i);
6152 if (map->IsUnboxedDoubleField(index)) continue;
6153 auto box = isolate->factory()->NewMutableHeapNumberWithHoleNaN();
6154 if (index.is_inobject()) {
6155 storage->set(index.property_index(), *box);
6156 } else {
6157 array->set(index.outobject_array_index(), *box);
6158 }
6159 }
6160
6161 object->SetProperties(*array);
6162
6163 if (!FLAG_unbox_double_fields) {
6164 for (int i = 0; i < inobject; i++) {
6165 FieldIndex index = FieldIndex::ForPropertyIndex(*map, i);
6166 Object* value = storage->get(i);
6167 object->RawFastPropertyAtPut(index, value);
6168 }
6169 }
6170 }
6171 object->synchronized_set_map(*map);
6172 }
6173
6174
MigrateInstance(Handle<JSObject> object)6175 void JSObject::MigrateInstance(Handle<JSObject> object) {
6176 Handle<Map> original_map(object->map(), object->GetIsolate());
6177 Handle<Map> map = Map::Update(object->GetIsolate(), original_map);
6178 map->set_is_migration_target(true);
6179 MigrateToMap(object, map);
6180 if (FLAG_trace_migration) {
6181 object->PrintInstanceMigration(stdout, *original_map, *map);
6182 }
6183 #if VERIFY_HEAP
6184 if (FLAG_verify_heap) {
6185 object->JSObjectVerify(object->GetIsolate());
6186 }
6187 #endif
6188 }
6189
6190
6191 // static
TryMigrateInstance(Handle<JSObject> object)6192 bool JSObject::TryMigrateInstance(Handle<JSObject> object) {
6193 Isolate* isolate = object->GetIsolate();
6194 DisallowDeoptimization no_deoptimization(isolate);
6195 Handle<Map> original_map(object->map(), isolate);
6196 Handle<Map> new_map;
6197 if (!Map::TryUpdate(isolate, original_map).ToHandle(&new_map)) {
6198 return false;
6199 }
6200 JSObject::MigrateToMap(object, new_map);
6201 if (FLAG_trace_migration && *original_map != object->map()) {
6202 object->PrintInstanceMigration(stdout, *original_map, object->map());
6203 }
6204 #if VERIFY_HEAP
6205 if (FLAG_verify_heap) {
6206 object->JSObjectVerify(isolate);
6207 }
6208 #endif
6209 return true;
6210 }
6211
AddProperty(Isolate * isolate,Handle<JSObject> object,Handle<Name> name,Handle<Object> value,PropertyAttributes attributes)6212 void JSObject::AddProperty(Isolate* isolate, Handle<JSObject> object,
6213 Handle<Name> name, Handle<Object> value,
6214 PropertyAttributes attributes) {
6215 LookupIterator it(isolate, object, name, object,
6216 LookupIterator::OWN_SKIP_INTERCEPTOR);
6217 CHECK_NE(LookupIterator::ACCESS_CHECK, it.state());
6218 #ifdef DEBUG
6219 uint32_t index;
6220 DCHECK(!object->IsJSProxy());
6221 DCHECK(!name->AsArrayIndex(&index));
6222 Maybe<PropertyAttributes> maybe = GetPropertyAttributes(&it);
6223 DCHECK(maybe.IsJust());
6224 DCHECK(!it.IsFound());
6225 DCHECK(object->map()->is_extensible() || name->IsPrivate());
6226 #endif
6227 CHECK(AddDataProperty(&it, value, attributes, kThrowOnError,
6228 CERTAINLY_NOT_STORE_FROM_KEYED)
6229 .IsJust());
6230 }
6231
6232
6233 // Reconfigures a property to a data property with attributes, even if it is not
6234 // reconfigurable.
6235 // Requires a LookupIterator that does not look at the prototype chain beyond
6236 // hidden prototypes.
DefineOwnPropertyIgnoreAttributes(LookupIterator * it,Handle<Object> value,PropertyAttributes attributes,AccessorInfoHandling handling)6237 MaybeHandle<Object> JSObject::DefineOwnPropertyIgnoreAttributes(
6238 LookupIterator* it, Handle<Object> value, PropertyAttributes attributes,
6239 AccessorInfoHandling handling) {
6240 MAYBE_RETURN_NULL(DefineOwnPropertyIgnoreAttributes(it, value, attributes,
6241 kThrowOnError, handling));
6242 return value;
6243 }
6244
6245
DefineOwnPropertyIgnoreAttributes(LookupIterator * it,Handle<Object> value,PropertyAttributes attributes,ShouldThrow should_throw,AccessorInfoHandling handling)6246 Maybe<bool> JSObject::DefineOwnPropertyIgnoreAttributes(
6247 LookupIterator* it, Handle<Object> value, PropertyAttributes attributes,
6248 ShouldThrow should_throw, AccessorInfoHandling handling) {
6249 it->UpdateProtector();
6250 Handle<JSObject> object = Handle<JSObject>::cast(it->GetReceiver());
6251
6252 for (; it->IsFound(); it->Next()) {
6253 switch (it->state()) {
6254 case LookupIterator::JSPROXY:
6255 case LookupIterator::NOT_FOUND:
6256 case LookupIterator::TRANSITION:
6257 UNREACHABLE();
6258
6259 case LookupIterator::ACCESS_CHECK:
6260 if (!it->HasAccess()) {
6261 it->isolate()->ReportFailedAccessCheck(it->GetHolder<JSObject>());
6262 RETURN_VALUE_IF_SCHEDULED_EXCEPTION(it->isolate(), Nothing<bool>());
6263 return Just(true);
6264 }
6265 break;
6266
6267 // If there's an interceptor, try to store the property with the
6268 // interceptor.
6269 // In case of success, the attributes will have been reset to the default
6270 // attributes of the interceptor, rather than the incoming attributes.
6271 //
6272 // TODO(verwaest): JSProxy afterwards verify the attributes that the
6273 // JSProxy claims it has, and verifies that they are compatible. If not,
6274 // they throw. Here we should do the same.
6275 case LookupIterator::INTERCEPTOR:
6276 if (handling == DONT_FORCE_FIELD) {
6277 Maybe<bool> result =
6278 JSObject::SetPropertyWithInterceptor(it, should_throw, value);
6279 if (result.IsNothing() || result.FromJust()) return result;
6280 }
6281 break;
6282
6283 case LookupIterator::ACCESSOR: {
6284 Handle<Object> accessors = it->GetAccessors();
6285
6286 // Special handling for AccessorInfo, which behaves like a data
6287 // property.
6288 if (accessors->IsAccessorInfo() && handling == DONT_FORCE_FIELD) {
6289 PropertyAttributes current_attributes = it->property_attributes();
6290 // Ensure the context isn't changed after calling into accessors.
6291 AssertNoContextChange ncc(it->isolate());
6292
6293 // Update the attributes before calling the setter. The setter may
6294 // later change the shape of the property.
6295 if (current_attributes != attributes) {
6296 it->TransitionToAccessorPair(accessors, attributes);
6297 }
6298
6299 return JSObject::SetPropertyWithAccessor(it, value, should_throw);
6300 }
6301
6302 it->ReconfigureDataProperty(value, attributes);
6303 return Just(true);
6304 }
6305 case LookupIterator::INTEGER_INDEXED_EXOTIC:
6306 return RedefineIncompatibleProperty(it->isolate(), it->GetName(), value,
6307 should_throw);
6308
6309 case LookupIterator::DATA: {
6310 // Regular property update if the attributes match.
6311 if (it->property_attributes() == attributes) {
6312 return SetDataProperty(it, value);
6313 }
6314
6315 // Special case: properties of typed arrays cannot be reconfigured to
6316 // non-writable nor to non-enumerable.
6317 if (it->IsElement() && object->HasFixedTypedArrayElements()) {
6318 return RedefineIncompatibleProperty(it->isolate(), it->GetName(),
6319 value, should_throw);
6320 }
6321
6322 // Reconfigure the data property if the attributes mismatch.
6323 it->ReconfigureDataProperty(value, attributes);
6324
6325 return Just(true);
6326 }
6327 }
6328 }
6329
6330 return AddDataProperty(it, value, attributes, should_throw,
6331 CERTAINLY_NOT_STORE_FROM_KEYED);
6332 }
6333
SetOwnPropertyIgnoreAttributes(Handle<JSObject> object,Handle<Name> name,Handle<Object> value,PropertyAttributes attributes)6334 MaybeHandle<Object> JSObject::SetOwnPropertyIgnoreAttributes(
6335 Handle<JSObject> object, Handle<Name> name, Handle<Object> value,
6336 PropertyAttributes attributes) {
6337 DCHECK(!value->IsTheHole());
6338 LookupIterator it(object, name, object, LookupIterator::OWN);
6339 return DefineOwnPropertyIgnoreAttributes(&it, value, attributes);
6340 }
6341
SetOwnElementIgnoreAttributes(Handle<JSObject> object,uint32_t index,Handle<Object> value,PropertyAttributes attributes)6342 MaybeHandle<Object> JSObject::SetOwnElementIgnoreAttributes(
6343 Handle<JSObject> object, uint32_t index, Handle<Object> value,
6344 PropertyAttributes attributes) {
6345 Isolate* isolate = object->GetIsolate();
6346 LookupIterator it(isolate, object, index, object, LookupIterator::OWN);
6347 return DefineOwnPropertyIgnoreAttributes(&it, value, attributes);
6348 }
6349
DefinePropertyOrElementIgnoreAttributes(Handle<JSObject> object,Handle<Name> name,Handle<Object> value,PropertyAttributes attributes)6350 MaybeHandle<Object> JSObject::DefinePropertyOrElementIgnoreAttributes(
6351 Handle<JSObject> object, Handle<Name> name, Handle<Object> value,
6352 PropertyAttributes attributes) {
6353 Isolate* isolate = object->GetIsolate();
6354 LookupIterator it = LookupIterator::PropertyOrElement(
6355 isolate, object, name, object, LookupIterator::OWN);
6356 return DefineOwnPropertyIgnoreAttributes(&it, value, attributes);
6357 }
6358
GetPropertyAttributesWithInterceptor(LookupIterator * it)6359 Maybe<PropertyAttributes> JSObject::GetPropertyAttributesWithInterceptor(
6360 LookupIterator* it) {
6361 return GetPropertyAttributesWithInterceptorInternal(it, it->GetInterceptor());
6362 }
6363
GetPropertyAttributes(LookupIterator * it)6364 Maybe<PropertyAttributes> JSReceiver::GetPropertyAttributes(
6365 LookupIterator* it) {
6366 for (; it->IsFound(); it->Next()) {
6367 switch (it->state()) {
6368 case LookupIterator::NOT_FOUND:
6369 case LookupIterator::TRANSITION:
6370 UNREACHABLE();
6371 case LookupIterator::JSPROXY:
6372 return JSProxy::GetPropertyAttributes(it);
6373 case LookupIterator::INTERCEPTOR: {
6374 Maybe<PropertyAttributes> result =
6375 JSObject::GetPropertyAttributesWithInterceptor(it);
6376 if (result.IsNothing()) return result;
6377 if (result.FromJust() != ABSENT) return result;
6378 break;
6379 }
6380 case LookupIterator::ACCESS_CHECK:
6381 if (it->HasAccess()) break;
6382 return JSObject::GetPropertyAttributesWithFailedAccessCheck(it);
6383 case LookupIterator::INTEGER_INDEXED_EXOTIC:
6384 return Just(ABSENT);
6385 case LookupIterator::ACCESSOR:
6386 if (it->GetHolder<Object>()->IsJSModuleNamespace()) {
6387 return JSModuleNamespace::GetPropertyAttributes(it);
6388 } else {
6389 return Just(it->property_attributes());
6390 }
6391 case LookupIterator::DATA:
6392 return Just(it->property_attributes());
6393 }
6394 }
6395 return Just(ABSENT);
6396 }
6397
6398
New(Isolate * isolate)6399 Handle<NormalizedMapCache> NormalizedMapCache::New(Isolate* isolate) {
6400 Handle<WeakFixedArray> array(
6401 isolate->factory()->NewWeakFixedArray(kEntries, TENURED));
6402 return Handle<NormalizedMapCache>::cast(array);
6403 }
6404
6405
Get(Handle<Map> fast_map,PropertyNormalizationMode mode)6406 MaybeHandle<Map> NormalizedMapCache::Get(Handle<Map> fast_map,
6407 PropertyNormalizationMode mode) {
6408 DisallowHeapAllocation no_gc;
6409 MaybeObject* value = WeakFixedArray::Get(GetIndex(fast_map));
6410 HeapObject* heap_object;
6411 if (!value->ToWeakHeapObject(&heap_object)) {
6412 return MaybeHandle<Map>();
6413 }
6414
6415 Map* normalized_map = Map::cast(heap_object);
6416 if (!normalized_map->EquivalentToForNormalization(*fast_map, mode)) {
6417 return MaybeHandle<Map>();
6418 }
6419 return handle(normalized_map, GetIsolate());
6420 }
6421
Set(Handle<Map> fast_map,Handle<Map> normalized_map)6422 void NormalizedMapCache::Set(Handle<Map> fast_map, Handle<Map> normalized_map) {
6423 DisallowHeapAllocation no_gc;
6424 DCHECK(normalized_map->is_dictionary_map());
6425 WeakFixedArray::Set(GetIndex(fast_map),
6426 HeapObjectReference::Weak(*normalized_map));
6427 }
6428
NormalizeProperties(Handle<JSObject> object,PropertyNormalizationMode mode,int expected_additional_properties,const char * reason)6429 void JSObject::NormalizeProperties(Handle<JSObject> object,
6430 PropertyNormalizationMode mode,
6431 int expected_additional_properties,
6432 const char* reason) {
6433 if (!object->HasFastProperties()) return;
6434
6435 Handle<Map> map(object->map(), object->GetIsolate());
6436 Handle<Map> new_map = Map::Normalize(object->GetIsolate(), map, mode, reason);
6437
6438 MigrateToMap(object, new_map, expected_additional_properties);
6439 }
6440
6441
MigrateSlowToFast(Handle<JSObject> object,int unused_property_fields,const char * reason)6442 void JSObject::MigrateSlowToFast(Handle<JSObject> object,
6443 int unused_property_fields,
6444 const char* reason) {
6445 if (object->HasFastProperties()) return;
6446 DCHECK(!object->IsJSGlobalObject());
6447 Isolate* isolate = object->GetIsolate();
6448 Factory* factory = isolate->factory();
6449 Handle<NameDictionary> dictionary(object->property_dictionary(), isolate);
6450
6451 // Make sure we preserve dictionary representation if there are too many
6452 // descriptors.
6453 int number_of_elements = dictionary->NumberOfElements();
6454 if (number_of_elements > kMaxNumberOfDescriptors) return;
6455
6456 Handle<FixedArray> iteration_order =
6457 NameDictionary::IterationIndices(isolate, dictionary);
6458
6459 int instance_descriptor_length = iteration_order->length();
6460 int number_of_fields = 0;
6461
6462 // Compute the length of the instance descriptor.
6463 ReadOnlyRoots roots(isolate);
6464 for (int i = 0; i < instance_descriptor_length; i++) {
6465 int index = Smi::ToInt(iteration_order->get(i));
6466 DCHECK(dictionary->IsKey(roots, dictionary->KeyAt(index)));
6467
6468 PropertyKind kind = dictionary->DetailsAt(index).kind();
6469 if (kind == kData) {
6470 if (FLAG_track_constant_fields) {
6471 number_of_fields += 1;
6472 } else {
6473 Object* value = dictionary->ValueAt(index);
6474 if (!value->IsJSFunction()) {
6475 number_of_fields += 1;
6476 }
6477 }
6478 }
6479 }
6480
6481 Handle<Map> old_map(object->map(), isolate);
6482
6483 int inobject_props = old_map->GetInObjectProperties();
6484
6485 // Allocate new map.
6486 Handle<Map> new_map = Map::CopyDropDescriptors(isolate, old_map);
6487 if (new_map->has_named_interceptor() || new_map->is_access_check_needed()) {
6488 // Force certain slow paths when API interceptors are used, or if an access
6489 // check is required.
6490 new_map->set_may_have_interesting_symbols(true);
6491 }
6492 new_map->set_is_dictionary_map(false);
6493
6494 NotifyMapChange(old_map, new_map, isolate);
6495
6496 if (FLAG_trace_maps) {
6497 LOG(isolate, MapEvent("SlowToFast", *old_map, *new_map, reason));
6498 }
6499
6500 if (instance_descriptor_length == 0) {
6501 DisallowHeapAllocation no_gc;
6502 DCHECK_LE(unused_property_fields, inobject_props);
6503 // Transform the object.
6504 new_map->SetInObjectUnusedPropertyFields(inobject_props);
6505 object->synchronized_set_map(*new_map);
6506 object->SetProperties(ReadOnlyRoots(isolate).empty_fixed_array());
6507 // Check that it really works.
6508 DCHECK(object->HasFastProperties());
6509 return;
6510 }
6511
6512 // Allocate the instance descriptor.
6513 Handle<DescriptorArray> descriptors = DescriptorArray::Allocate(
6514 isolate, instance_descriptor_length, 0, TENURED);
6515
6516 int number_of_allocated_fields =
6517 number_of_fields + unused_property_fields - inobject_props;
6518 if (number_of_allocated_fields < 0) {
6519 // There is enough inobject space for all fields (including unused).
6520 number_of_allocated_fields = 0;
6521 unused_property_fields = inobject_props - number_of_fields;
6522 }
6523
6524 // Allocate the property array for the fields.
6525 Handle<PropertyArray> fields =
6526 factory->NewPropertyArray(number_of_allocated_fields);
6527
6528 bool is_transitionable_elements_kind =
6529 IsTransitionableFastElementsKind(old_map->elements_kind());
6530
6531 // Fill in the instance descriptor and the fields.
6532 int current_offset = 0;
6533 for (int i = 0; i < instance_descriptor_length; i++) {
6534 int index = Smi::ToInt(iteration_order->get(i));
6535 Name* k = dictionary->NameAt(index);
6536 // Dictionary keys are internalized upon insertion.
6537 // TODO(jkummerow): Turn this into a DCHECK if it's not hit in the wild.
6538 CHECK(k->IsUniqueName());
6539 Handle<Name> key(k, isolate);
6540
6541 // Properly mark the {new_map} if the {key} is an "interesting symbol".
6542 if (key->IsInterestingSymbol()) {
6543 new_map->set_may_have_interesting_symbols(true);
6544 }
6545
6546 Object* value = dictionary->ValueAt(index);
6547
6548 PropertyDetails details = dictionary->DetailsAt(index);
6549 DCHECK_EQ(kField, details.location());
6550 DCHECK_EQ(PropertyConstness::kMutable, details.constness());
6551
6552 Descriptor d;
6553 if (details.kind() == kData) {
6554 if (!FLAG_track_constant_fields && value->IsJSFunction()) {
6555 d = Descriptor::DataConstant(key, handle(value, isolate),
6556 details.attributes());
6557 } else {
6558 // Ensure that we make constant field only when elements kind is not
6559 // transitionable.
6560 PropertyConstness constness =
6561 FLAG_track_constant_fields && !is_transitionable_elements_kind
6562 ? PropertyConstness::kConst
6563 : PropertyConstness::kMutable;
6564 d = Descriptor::DataField(
6565 key, current_offset, details.attributes(), constness,
6566 // TODO(verwaest): value->OptimalRepresentation();
6567 Representation::Tagged(),
6568 MaybeObjectHandle(FieldType::Any(isolate)));
6569 }
6570 } else {
6571 DCHECK_EQ(kAccessor, details.kind());
6572 d = Descriptor::AccessorConstant(key, handle(value, isolate),
6573 details.attributes());
6574 }
6575 details = d.GetDetails();
6576 if (details.location() == kField) {
6577 if (current_offset < inobject_props) {
6578 object->InObjectPropertyAtPut(current_offset, value,
6579 UPDATE_WRITE_BARRIER);
6580 } else {
6581 int offset = current_offset - inobject_props;
6582 fields->set(offset, value);
6583 }
6584 current_offset += details.field_width_in_words();
6585 }
6586 descriptors->Set(i, &d);
6587 }
6588 DCHECK(current_offset == number_of_fields);
6589
6590 descriptors->Sort();
6591
6592 Handle<LayoutDescriptor> layout_descriptor = LayoutDescriptor::New(
6593 isolate, new_map, descriptors, descriptors->number_of_descriptors());
6594
6595 DisallowHeapAllocation no_gc;
6596 new_map->InitializeDescriptors(*descriptors, *layout_descriptor);
6597 if (number_of_allocated_fields == 0) {
6598 new_map->SetInObjectUnusedPropertyFields(unused_property_fields);
6599 } else {
6600 new_map->SetOutOfObjectUnusedPropertyFields(unused_property_fields);
6601 }
6602
6603 // Transform the object.
6604 object->synchronized_set_map(*new_map);
6605
6606 object->SetProperties(*fields);
6607 DCHECK(object->IsJSObject());
6608
6609 // Check that it really works.
6610 DCHECK(object->HasFastProperties());
6611 }
6612
RequireSlowElements(NumberDictionary * dictionary)6613 void JSObject::RequireSlowElements(NumberDictionary* dictionary) {
6614 if (dictionary->requires_slow_elements()) return;
6615 dictionary->set_requires_slow_elements();
6616 if (map()->is_prototype_map()) {
6617 // If this object is a prototype (the callee will check), invalidate any
6618 // prototype chains involving it.
6619 InvalidatePrototypeChains(map());
6620 }
6621 }
6622
NormalizeElements(Handle<JSObject> object)6623 Handle<NumberDictionary> JSObject::NormalizeElements(Handle<JSObject> object) {
6624 DCHECK(!object->HasFixedTypedArrayElements());
6625 Isolate* isolate = object->GetIsolate();
6626 bool is_sloppy_arguments = object->HasSloppyArgumentsElements();
6627 {
6628 DisallowHeapAllocation no_gc;
6629 FixedArrayBase* elements = object->elements();
6630
6631 if (is_sloppy_arguments) {
6632 elements = SloppyArgumentsElements::cast(elements)->arguments();
6633 }
6634
6635 if (elements->IsNumberDictionary()) {
6636 return handle(NumberDictionary::cast(elements), isolate);
6637 }
6638 }
6639
6640 DCHECK(object->HasSmiOrObjectElements() || object->HasDoubleElements() ||
6641 object->HasFastArgumentsElements() ||
6642 object->HasFastStringWrapperElements());
6643
6644 Handle<NumberDictionary> dictionary =
6645 object->GetElementsAccessor()->Normalize(object);
6646
6647 // Switch to using the dictionary as the backing storage for elements.
6648 ElementsKind target_kind = is_sloppy_arguments
6649 ? SLOW_SLOPPY_ARGUMENTS_ELEMENTS
6650 : object->HasFastStringWrapperElements()
6651 ? SLOW_STRING_WRAPPER_ELEMENTS
6652 : DICTIONARY_ELEMENTS;
6653 Handle<Map> new_map = JSObject::GetElementsTransitionMap(object, target_kind);
6654 // Set the new map first to satify the elements type assert in set_elements().
6655 JSObject::MigrateToMap(object, new_map);
6656
6657 if (is_sloppy_arguments) {
6658 SloppyArgumentsElements::cast(object->elements())
6659 ->set_arguments(*dictionary);
6660 } else {
6661 object->set_elements(*dictionary);
6662 }
6663
6664 isolate->counters()->elements_to_dictionary()->Increment();
6665
6666 #ifdef DEBUG
6667 if (FLAG_trace_normalization) {
6668 StdoutStream os;
6669 os << "Object elements have been normalized:\n";
6670 object->Print(os);
6671 }
6672 #endif
6673
6674 DCHECK(object->HasDictionaryElements() ||
6675 object->HasSlowArgumentsElements() ||
6676 object->HasSlowStringWrapperElements());
6677 return dictionary;
6678 }
6679
6680 namespace {
6681
SetHashAndUpdateProperties(Isolate * isolate,HeapObject * properties,int hash)6682 Object* SetHashAndUpdateProperties(Isolate* isolate, HeapObject* properties,
6683 int hash) {
6684 DCHECK_NE(PropertyArray::kNoHashSentinel, hash);
6685 DCHECK(PropertyArray::HashField::is_valid(hash));
6686
6687 Heap* heap = isolate->heap();
6688 ReadOnlyRoots roots(heap);
6689 if (properties == roots.empty_fixed_array() ||
6690 properties == roots.empty_property_array() ||
6691 properties == heap->empty_property_dictionary()) {
6692 return Smi::FromInt(hash);
6693 }
6694
6695 if (properties->IsPropertyArray()) {
6696 PropertyArray::cast(properties)->SetHash(hash);
6697 DCHECK_LT(0, PropertyArray::cast(properties)->length());
6698 return properties;
6699 }
6700
6701 DCHECK(properties->IsNameDictionary());
6702 NameDictionary::cast(properties)->SetHash(hash);
6703 return properties;
6704 }
6705
GetIdentityHashHelper(Isolate * isolate,JSReceiver * object)6706 int GetIdentityHashHelper(Isolate* isolate, JSReceiver* object) {
6707 DisallowHeapAllocation no_gc;
6708 Object* properties = object->raw_properties_or_hash();
6709 if (properties->IsSmi()) {
6710 return Smi::ToInt(properties);
6711 }
6712
6713 if (properties->IsPropertyArray()) {
6714 return PropertyArray::cast(properties)->Hash();
6715 }
6716
6717 if (properties->IsNameDictionary()) {
6718 return NameDictionary::cast(properties)->Hash();
6719 }
6720
6721 if (properties->IsGlobalDictionary()) {
6722 return GlobalDictionary::cast(properties)->Hash();
6723 }
6724
6725 #ifdef DEBUG
6726 FixedArray* empty_fixed_array = ReadOnlyRoots(isolate).empty_fixed_array();
6727 FixedArray* empty_property_dictionary =
6728 isolate->heap()->empty_property_dictionary();
6729 DCHECK(properties == empty_fixed_array ||
6730 properties == empty_property_dictionary);
6731 #endif
6732
6733 return PropertyArray::kNoHashSentinel;
6734 }
6735 } // namespace
6736
SetIdentityHash(int hash)6737 void JSReceiver::SetIdentityHash(int hash) {
6738 DisallowHeapAllocation no_gc;
6739 DCHECK_NE(PropertyArray::kNoHashSentinel, hash);
6740 DCHECK(PropertyArray::HashField::is_valid(hash));
6741
6742 HeapObject* existing_properties = HeapObject::cast(raw_properties_or_hash());
6743 Object* new_properties =
6744 SetHashAndUpdateProperties(GetIsolate(), existing_properties, hash);
6745 set_raw_properties_or_hash(new_properties);
6746 }
6747
SetProperties(HeapObject * properties)6748 void JSReceiver::SetProperties(HeapObject* properties) {
6749 DCHECK_IMPLIES(properties->IsPropertyArray() &&
6750 PropertyArray::cast(properties)->length() == 0,
6751 properties == GetReadOnlyRoots().empty_property_array());
6752 DisallowHeapAllocation no_gc;
6753 Isolate* isolate = GetIsolate();
6754 int hash = GetIdentityHashHelper(isolate, this);
6755 Object* new_properties = properties;
6756
6757 // TODO(cbruni): Make GetIdentityHashHelper return a bool so that we
6758 // don't have to manually compare against kNoHashSentinel.
6759 if (hash != PropertyArray::kNoHashSentinel) {
6760 new_properties = SetHashAndUpdateProperties(isolate, properties, hash);
6761 }
6762
6763 set_raw_properties_or_hash(new_properties);
6764 }
6765
GetIdentityHash(Isolate * isolate)6766 Object* JSReceiver::GetIdentityHash(Isolate* isolate) {
6767 DisallowHeapAllocation no_gc;
6768
6769 int hash = GetIdentityHashHelper(isolate, this);
6770 if (hash == PropertyArray::kNoHashSentinel) {
6771 return ReadOnlyRoots(isolate).undefined_value();
6772 }
6773
6774 return Smi::FromInt(hash);
6775 }
6776
6777 // static
CreateIdentityHash(Isolate * isolate,JSReceiver * key)6778 Smi* JSReceiver::CreateIdentityHash(Isolate* isolate, JSReceiver* key) {
6779 DisallowHeapAllocation no_gc;
6780 int hash = isolate->GenerateIdentityHash(PropertyArray::HashField::kMax);
6781 DCHECK_NE(PropertyArray::kNoHashSentinel, hash);
6782
6783 key->SetIdentityHash(hash);
6784 return Smi::FromInt(hash);
6785 }
6786
GetOrCreateIdentityHash(Isolate * isolate)6787 Smi* JSReceiver::GetOrCreateIdentityHash(Isolate* isolate) {
6788 DisallowHeapAllocation no_gc;
6789
6790 Object* hash_obj = GetIdentityHash(isolate);
6791 if (!hash_obj->IsUndefined(isolate)) {
6792 return Smi::cast(hash_obj);
6793 }
6794
6795 return JSReceiver::CreateIdentityHash(isolate, this);
6796 }
6797
DeletePropertyWithInterceptor(LookupIterator * it,ShouldThrow should_throw)6798 Maybe<bool> JSObject::DeletePropertyWithInterceptor(LookupIterator* it,
6799 ShouldThrow should_throw) {
6800 Isolate* isolate = it->isolate();
6801 // Make sure that the top context does not change when doing callbacks or
6802 // interceptor calls.
6803 AssertNoContextChange ncc(isolate);
6804
6805 DCHECK_EQ(LookupIterator::INTERCEPTOR, it->state());
6806 Handle<InterceptorInfo> interceptor(it->GetInterceptor());
6807 if (interceptor->deleter()->IsUndefined(isolate)) return Nothing<bool>();
6808
6809 Handle<JSObject> holder = it->GetHolder<JSObject>();
6810 Handle<Object> receiver = it->GetReceiver();
6811 if (!receiver->IsJSReceiver()) {
6812 ASSIGN_RETURN_ON_EXCEPTION_VALUE(isolate, receiver,
6813 Object::ConvertReceiver(isolate, receiver),
6814 Nothing<bool>());
6815 }
6816
6817 PropertyCallbackArguments args(isolate, interceptor->data(), *receiver,
6818 *holder, should_throw);
6819 Handle<Object> result;
6820 if (it->IsElement()) {
6821 result = args.CallIndexedDeleter(interceptor, it->index());
6822 } else {
6823 result = args.CallNamedDeleter(interceptor, it->name());
6824 }
6825
6826 RETURN_VALUE_IF_SCHEDULED_EXCEPTION(isolate, Nothing<bool>());
6827 if (result.is_null()) return Nothing<bool>();
6828
6829 DCHECK(result->IsBoolean());
6830 // Rebox CustomArguments::kReturnValueOffset before returning.
6831 return Just(result->IsTrue(isolate));
6832 }
6833
DeleteNormalizedProperty(Handle<JSReceiver> object,int entry)6834 void JSReceiver::DeleteNormalizedProperty(Handle<JSReceiver> object,
6835 int entry) {
6836 DCHECK(!object->HasFastProperties());
6837 Isolate* isolate = object->GetIsolate();
6838
6839 if (object->IsJSGlobalObject()) {
6840 // If we have a global object, invalidate the cell and swap in a new one.
6841 Handle<GlobalDictionary> dictionary(
6842 JSGlobalObject::cast(*object)->global_dictionary(), isolate);
6843 DCHECK_NE(GlobalDictionary::kNotFound, entry);
6844
6845 auto cell = PropertyCell::InvalidateEntry(isolate, dictionary, entry);
6846 cell->set_value(ReadOnlyRoots(isolate).the_hole_value());
6847 cell->set_property_details(
6848 PropertyDetails::Empty(PropertyCellType::kUninitialized));
6849 } else {
6850 Handle<NameDictionary> dictionary(object->property_dictionary(), isolate);
6851 DCHECK_NE(NameDictionary::kNotFound, entry);
6852
6853 dictionary = NameDictionary::DeleteEntry(isolate, dictionary, entry);
6854 object->SetProperties(*dictionary);
6855 }
6856 if (object->map()->is_prototype_map()) {
6857 // Invalidate prototype validity cell as this may invalidate transitioning
6858 // store IC handlers.
6859 JSObject::InvalidatePrototypeChains(object->map());
6860 }
6861 }
6862
6863
DeleteProperty(LookupIterator * it,LanguageMode language_mode)6864 Maybe<bool> JSReceiver::DeleteProperty(LookupIterator* it,
6865 LanguageMode language_mode) {
6866 it->UpdateProtector();
6867
6868 Isolate* isolate = it->isolate();
6869
6870 if (it->state() == LookupIterator::JSPROXY) {
6871 return JSProxy::DeletePropertyOrElement(it->GetHolder<JSProxy>(),
6872 it->GetName(), language_mode);
6873 }
6874
6875 if (it->GetReceiver()->IsJSProxy()) {
6876 if (it->state() != LookupIterator::NOT_FOUND) {
6877 DCHECK_EQ(LookupIterator::DATA, it->state());
6878 DCHECK(it->name()->IsPrivate());
6879 it->Delete();
6880 }
6881 return Just(true);
6882 }
6883 Handle<JSObject> receiver = Handle<JSObject>::cast(it->GetReceiver());
6884
6885 for (; it->IsFound(); it->Next()) {
6886 switch (it->state()) {
6887 case LookupIterator::JSPROXY:
6888 case LookupIterator::NOT_FOUND:
6889 case LookupIterator::TRANSITION:
6890 UNREACHABLE();
6891 case LookupIterator::ACCESS_CHECK:
6892 if (it->HasAccess()) break;
6893 isolate->ReportFailedAccessCheck(it->GetHolder<JSObject>());
6894 RETURN_VALUE_IF_SCHEDULED_EXCEPTION(isolate, Nothing<bool>());
6895 return Just(false);
6896 case LookupIterator::INTERCEPTOR: {
6897 ShouldThrow should_throw =
6898 is_sloppy(language_mode) ? kDontThrow : kThrowOnError;
6899 Maybe<bool> result =
6900 JSObject::DeletePropertyWithInterceptor(it, should_throw);
6901 // An exception was thrown in the interceptor. Propagate.
6902 if (isolate->has_pending_exception()) return Nothing<bool>();
6903 // Delete with interceptor succeeded. Return result.
6904 // TODO(neis): In strict mode, we should probably throw if the
6905 // interceptor returns false.
6906 if (result.IsJust()) return result;
6907 break;
6908 }
6909 case LookupIterator::INTEGER_INDEXED_EXOTIC:
6910 return Just(true);
6911 case LookupIterator::DATA:
6912 case LookupIterator::ACCESSOR: {
6913 if (!it->IsConfigurable()) {
6914 // Fail if the property is not configurable.
6915 if (is_strict(language_mode)) {
6916 isolate->Throw(*isolate->factory()->NewTypeError(
6917 MessageTemplate::kStrictDeleteProperty, it->GetName(),
6918 receiver));
6919 return Nothing<bool>();
6920 }
6921 return Just(false);
6922 }
6923
6924 it->Delete();
6925
6926 return Just(true);
6927 }
6928 }
6929 }
6930
6931 return Just(true);
6932 }
6933
6934
DeleteElement(Handle<JSReceiver> object,uint32_t index,LanguageMode language_mode)6935 Maybe<bool> JSReceiver::DeleteElement(Handle<JSReceiver> object, uint32_t index,
6936 LanguageMode language_mode) {
6937 LookupIterator it(object->GetIsolate(), object, index, object,
6938 LookupIterator::OWN);
6939 return DeleteProperty(&it, language_mode);
6940 }
6941
6942
DeleteProperty(Handle<JSReceiver> object,Handle<Name> name,LanguageMode language_mode)6943 Maybe<bool> JSReceiver::DeleteProperty(Handle<JSReceiver> object,
6944 Handle<Name> name,
6945 LanguageMode language_mode) {
6946 LookupIterator it(object, name, object, LookupIterator::OWN);
6947 return DeleteProperty(&it, language_mode);
6948 }
6949
6950
DeletePropertyOrElement(Handle<JSReceiver> object,Handle<Name> name,LanguageMode language_mode)6951 Maybe<bool> JSReceiver::DeletePropertyOrElement(Handle<JSReceiver> object,
6952 Handle<Name> name,
6953 LanguageMode language_mode) {
6954 LookupIterator it = LookupIterator::PropertyOrElement(
6955 object->GetIsolate(), object, name, object, LookupIterator::OWN);
6956 return DeleteProperty(&it, language_mode);
6957 }
6958
6959 // ES6 19.1.2.4
6960 // static
DefineProperty(Isolate * isolate,Handle<Object> object,Handle<Object> key,Handle<Object> attributes)6961 Object* JSReceiver::DefineProperty(Isolate* isolate, Handle<Object> object,
6962 Handle<Object> key,
6963 Handle<Object> attributes) {
6964 // 1. If Type(O) is not Object, throw a TypeError exception.
6965 if (!object->IsJSReceiver()) {
6966 Handle<String> fun_name =
6967 isolate->factory()->InternalizeUtf8String("Object.defineProperty");
6968 THROW_NEW_ERROR_RETURN_FAILURE(
6969 isolate, NewTypeError(MessageTemplate::kCalledOnNonObject, fun_name));
6970 }
6971 // 2. Let key be ToPropertyKey(P).
6972 // 3. ReturnIfAbrupt(key).
6973 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, key, ToPropertyKey(isolate, key));
6974 // 4. Let desc be ToPropertyDescriptor(Attributes).
6975 // 5. ReturnIfAbrupt(desc).
6976 PropertyDescriptor desc;
6977 if (!PropertyDescriptor::ToPropertyDescriptor(isolate, attributes, &desc)) {
6978 return ReadOnlyRoots(isolate).exception();
6979 }
6980 // 6. Let success be DefinePropertyOrThrow(O,key, desc).
6981 Maybe<bool> success = DefineOwnProperty(
6982 isolate, Handle<JSReceiver>::cast(object), key, &desc, kThrowOnError);
6983 // 7. ReturnIfAbrupt(success).
6984 MAYBE_RETURN(success, ReadOnlyRoots(isolate).exception());
6985 CHECK(success.FromJust());
6986 // 8. Return O.
6987 return *object;
6988 }
6989
6990
6991 // ES6 19.1.2.3.1
6992 // static
DefineProperties(Isolate * isolate,Handle<Object> object,Handle<Object> properties)6993 MaybeHandle<Object> JSReceiver::DefineProperties(Isolate* isolate,
6994 Handle<Object> object,
6995 Handle<Object> properties) {
6996 // 1. If Type(O) is not Object, throw a TypeError exception.
6997 if (!object->IsJSReceiver()) {
6998 Handle<String> fun_name =
6999 isolate->factory()->InternalizeUtf8String("Object.defineProperties");
7000 THROW_NEW_ERROR(isolate,
7001 NewTypeError(MessageTemplate::kCalledOnNonObject, fun_name),
7002 Object);
7003 }
7004 // 2. Let props be ToObject(Properties).
7005 // 3. ReturnIfAbrupt(props).
7006 Handle<JSReceiver> props;
7007 ASSIGN_RETURN_ON_EXCEPTION(isolate, props,
7008 Object::ToObject(isolate, properties), Object);
7009
7010 // 4. Let keys be props.[[OwnPropertyKeys]]().
7011 // 5. ReturnIfAbrupt(keys).
7012 Handle<FixedArray> keys;
7013 ASSIGN_RETURN_ON_EXCEPTION(
7014 isolate, keys, KeyAccumulator::GetKeys(props, KeyCollectionMode::kOwnOnly,
7015 ALL_PROPERTIES),
7016 Object);
7017 // 6. Let descriptors be an empty List.
7018 int capacity = keys->length();
7019 std::vector<PropertyDescriptor> descriptors(capacity);
7020 size_t descriptors_index = 0;
7021 // 7. Repeat for each element nextKey of keys in List order,
7022 for (int i = 0; i < keys->length(); ++i) {
7023 Handle<Object> next_key(keys->get(i), isolate);
7024 // 7a. Let propDesc be props.[[GetOwnProperty]](nextKey).
7025 // 7b. ReturnIfAbrupt(propDesc).
7026 bool success = false;
7027 LookupIterator it = LookupIterator::PropertyOrElement(
7028 isolate, props, next_key, &success, LookupIterator::OWN);
7029 DCHECK(success);
7030 Maybe<PropertyAttributes> maybe = JSReceiver::GetPropertyAttributes(&it);
7031 if (maybe.IsNothing()) return MaybeHandle<Object>();
7032 PropertyAttributes attrs = maybe.FromJust();
7033 // 7c. If propDesc is not undefined and propDesc.[[Enumerable]] is true:
7034 if (attrs == ABSENT) continue;
7035 if (attrs & DONT_ENUM) continue;
7036 // 7c i. Let descObj be Get(props, nextKey).
7037 // 7c ii. ReturnIfAbrupt(descObj).
7038 Handle<Object> desc_obj;
7039 ASSIGN_RETURN_ON_EXCEPTION(isolate, desc_obj, Object::GetProperty(&it),
7040 Object);
7041 // 7c iii. Let desc be ToPropertyDescriptor(descObj).
7042 success = PropertyDescriptor::ToPropertyDescriptor(
7043 isolate, desc_obj, &descriptors[descriptors_index]);
7044 // 7c iv. ReturnIfAbrupt(desc).
7045 if (!success) return MaybeHandle<Object>();
7046 // 7c v. Append the pair (a two element List) consisting of nextKey and
7047 // desc to the end of descriptors.
7048 descriptors[descriptors_index].set_name(next_key);
7049 descriptors_index++;
7050 }
7051 // 8. For each pair from descriptors in list order,
7052 for (size_t i = 0; i < descriptors_index; ++i) {
7053 PropertyDescriptor* desc = &descriptors[i];
7054 // 8a. Let P be the first element of pair.
7055 // 8b. Let desc be the second element of pair.
7056 // 8c. Let status be DefinePropertyOrThrow(O, P, desc).
7057 Maybe<bool> status =
7058 DefineOwnProperty(isolate, Handle<JSReceiver>::cast(object),
7059 desc->name(), desc, kThrowOnError);
7060 // 8d. ReturnIfAbrupt(status).
7061 if (status.IsNothing()) return MaybeHandle<Object>();
7062 CHECK(status.FromJust());
7063 }
7064 // 9. Return o.
7065 return object;
7066 }
7067
7068 // static
DefineOwnProperty(Isolate * isolate,Handle<JSReceiver> object,Handle<Object> key,PropertyDescriptor * desc,ShouldThrow should_throw)7069 Maybe<bool> JSReceiver::DefineOwnProperty(Isolate* isolate,
7070 Handle<JSReceiver> object,
7071 Handle<Object> key,
7072 PropertyDescriptor* desc,
7073 ShouldThrow should_throw) {
7074 if (object->IsJSArray()) {
7075 return JSArray::DefineOwnProperty(isolate, Handle<JSArray>::cast(object),
7076 key, desc, should_throw);
7077 }
7078 if (object->IsJSProxy()) {
7079 return JSProxy::DefineOwnProperty(isolate, Handle<JSProxy>::cast(object),
7080 key, desc, should_throw);
7081 }
7082 if (object->IsJSTypedArray()) {
7083 return JSTypedArray::DefineOwnProperty(
7084 isolate, Handle<JSTypedArray>::cast(object), key, desc, should_throw);
7085 }
7086
7087 // OrdinaryDefineOwnProperty, by virtue of calling
7088 // DefineOwnPropertyIgnoreAttributes, can handle arguments
7089 // (ES#sec-arguments-exotic-objects-defineownproperty-p-desc).
7090 return OrdinaryDefineOwnProperty(isolate, Handle<JSObject>::cast(object), key,
7091 desc, should_throw);
7092 }
7093
7094
7095 // static
OrdinaryDefineOwnProperty(Isolate * isolate,Handle<JSObject> object,Handle<Object> key,PropertyDescriptor * desc,ShouldThrow should_throw)7096 Maybe<bool> JSReceiver::OrdinaryDefineOwnProperty(Isolate* isolate,
7097 Handle<JSObject> object,
7098 Handle<Object> key,
7099 PropertyDescriptor* desc,
7100 ShouldThrow should_throw) {
7101 bool success = false;
7102 DCHECK(key->IsName() || key->IsNumber()); // |key| is a PropertyKey...
7103 LookupIterator it = LookupIterator::PropertyOrElement(
7104 isolate, object, key, &success, LookupIterator::OWN);
7105 DCHECK(success); // ...so creating a LookupIterator can't fail.
7106
7107 // Deal with access checks first.
7108 if (it.state() == LookupIterator::ACCESS_CHECK) {
7109 if (!it.HasAccess()) {
7110 isolate->ReportFailedAccessCheck(it.GetHolder<JSObject>());
7111 RETURN_VALUE_IF_SCHEDULED_EXCEPTION(isolate, Nothing<bool>());
7112 return Just(true);
7113 }
7114 it.Next();
7115 }
7116
7117 return OrdinaryDefineOwnProperty(&it, desc, should_throw);
7118 }
7119
7120
7121 // ES6 9.1.6.1
7122 // static
OrdinaryDefineOwnProperty(LookupIterator * it,PropertyDescriptor * desc,ShouldThrow should_throw)7123 Maybe<bool> JSReceiver::OrdinaryDefineOwnProperty(LookupIterator* it,
7124 PropertyDescriptor* desc,
7125 ShouldThrow should_throw) {
7126 Isolate* isolate = it->isolate();
7127 // 1. Let current be O.[[GetOwnProperty]](P).
7128 // 2. ReturnIfAbrupt(current).
7129 PropertyDescriptor current;
7130 MAYBE_RETURN(GetOwnPropertyDescriptor(it, ¤t), Nothing<bool>());
7131
7132 it->Restart();
7133 // Handle interceptor
7134 for (; it->IsFound(); it->Next()) {
7135 if (it->state() == LookupIterator::INTERCEPTOR) {
7136 if (it->HolderIsReceiverOrHiddenPrototype()) {
7137 Maybe<bool> result = DefinePropertyWithInterceptorInternal(
7138 it, it->GetInterceptor(), should_throw, *desc);
7139 if (result.IsNothing() || result.FromJust()) {
7140 return result;
7141 }
7142 }
7143 }
7144 }
7145
7146 // TODO(jkummerow/verwaest): It would be nice if we didn't have to reset
7147 // the iterator every time. Currently, the reasons why we need it are:
7148 // - handle interceptors correctly
7149 // - handle accessors correctly (which might change the holder's map)
7150 it->Restart();
7151 // 3. Let extensible be the value of the [[Extensible]] internal slot of O.
7152 Handle<JSObject> object = Handle<JSObject>::cast(it->GetReceiver());
7153 bool extensible = JSObject::IsExtensible(object);
7154
7155 return ValidateAndApplyPropertyDescriptor(
7156 isolate, it, extensible, desc, ¤t, should_throw, Handle<Name>());
7157 }
7158
7159
7160 // ES6 9.1.6.2
7161 // static
IsCompatiblePropertyDescriptor(Isolate * isolate,bool extensible,PropertyDescriptor * desc,PropertyDescriptor * current,Handle<Name> property_name,ShouldThrow should_throw)7162 Maybe<bool> JSReceiver::IsCompatiblePropertyDescriptor(
7163 Isolate* isolate, bool extensible, PropertyDescriptor* desc,
7164 PropertyDescriptor* current, Handle<Name> property_name,
7165 ShouldThrow should_throw) {
7166 // 1. Return ValidateAndApplyPropertyDescriptor(undefined, undefined,
7167 // Extensible, Desc, Current).
7168 return ValidateAndApplyPropertyDescriptor(
7169 isolate, nullptr, extensible, desc, current, should_throw, property_name);
7170 }
7171
7172
7173 // ES6 9.1.6.3
7174 // static
ValidateAndApplyPropertyDescriptor(Isolate * isolate,LookupIterator * it,bool extensible,PropertyDescriptor * desc,PropertyDescriptor * current,ShouldThrow should_throw,Handle<Name> property_name)7175 Maybe<bool> JSReceiver::ValidateAndApplyPropertyDescriptor(
7176 Isolate* isolate, LookupIterator* it, bool extensible,
7177 PropertyDescriptor* desc, PropertyDescriptor* current,
7178 ShouldThrow should_throw, Handle<Name> property_name) {
7179 // We either need a LookupIterator, or a property name.
7180 DCHECK((it == nullptr) != property_name.is_null());
7181 Handle<JSObject> object;
7182 if (it != nullptr) object = Handle<JSObject>::cast(it->GetReceiver());
7183 bool desc_is_data_descriptor = PropertyDescriptor::IsDataDescriptor(desc);
7184 bool desc_is_accessor_descriptor =
7185 PropertyDescriptor::IsAccessorDescriptor(desc);
7186 bool desc_is_generic_descriptor =
7187 PropertyDescriptor::IsGenericDescriptor(desc);
7188 // 1. (Assert)
7189 // 2. If current is undefined, then
7190 if (current->is_empty()) {
7191 // 2a. If extensible is false, return false.
7192 if (!extensible) {
7193 RETURN_FAILURE(
7194 isolate, should_throw,
7195 NewTypeError(MessageTemplate::kDefineDisallowed,
7196 it != nullptr ? it->GetName() : property_name));
7197 }
7198 // 2c. If IsGenericDescriptor(Desc) or IsDataDescriptor(Desc) is true, then:
7199 // (This is equivalent to !IsAccessorDescriptor(desc).)
7200 DCHECK((desc_is_generic_descriptor || desc_is_data_descriptor) ==
7201 !desc_is_accessor_descriptor);
7202 if (!desc_is_accessor_descriptor) {
7203 // 2c i. If O is not undefined, create an own data property named P of
7204 // object O whose [[Value]], [[Writable]], [[Enumerable]] and
7205 // [[Configurable]] attribute values are described by Desc. If the value
7206 // of an attribute field of Desc is absent, the attribute of the newly
7207 // created property is set to its default value.
7208 if (it != nullptr) {
7209 if (!desc->has_writable()) desc->set_writable(false);
7210 if (!desc->has_enumerable()) desc->set_enumerable(false);
7211 if (!desc->has_configurable()) desc->set_configurable(false);
7212 Handle<Object> value(
7213 desc->has_value()
7214 ? desc->value()
7215 : Handle<Object>::cast(isolate->factory()->undefined_value()));
7216 MaybeHandle<Object> result =
7217 JSObject::DefineOwnPropertyIgnoreAttributes(it, value,
7218 desc->ToAttributes());
7219 if (result.is_null()) return Nothing<bool>();
7220 }
7221 } else {
7222 // 2d. Else Desc must be an accessor Property Descriptor,
7223 DCHECK(desc_is_accessor_descriptor);
7224 // 2d i. If O is not undefined, create an own accessor property named P
7225 // of object O whose [[Get]], [[Set]], [[Enumerable]] and
7226 // [[Configurable]] attribute values are described by Desc. If the value
7227 // of an attribute field of Desc is absent, the attribute of the newly
7228 // created property is set to its default value.
7229 if (it != nullptr) {
7230 if (!desc->has_enumerable()) desc->set_enumerable(false);
7231 if (!desc->has_configurable()) desc->set_configurable(false);
7232 Handle<Object> getter(
7233 desc->has_get()
7234 ? desc->get()
7235 : Handle<Object>::cast(isolate->factory()->null_value()));
7236 Handle<Object> setter(
7237 desc->has_set()
7238 ? desc->set()
7239 : Handle<Object>::cast(isolate->factory()->null_value()));
7240 MaybeHandle<Object> result =
7241 JSObject::DefineAccessor(it, getter, setter, desc->ToAttributes());
7242 if (result.is_null()) return Nothing<bool>();
7243 }
7244 }
7245 // 2e. Return true.
7246 return Just(true);
7247 }
7248 // 3. Return true, if every field in Desc is absent.
7249 // 4. Return true, if every field in Desc also occurs in current and the
7250 // value of every field in Desc is the same value as the corresponding field
7251 // in current when compared using the SameValue algorithm.
7252 if ((!desc->has_enumerable() ||
7253 desc->enumerable() == current->enumerable()) &&
7254 (!desc->has_configurable() ||
7255 desc->configurable() == current->configurable()) &&
7256 (!desc->has_value() ||
7257 (current->has_value() && current->value()->SameValue(*desc->value()))) &&
7258 (!desc->has_writable() ||
7259 (current->has_writable() && current->writable() == desc->writable())) &&
7260 (!desc->has_get() ||
7261 (current->has_get() && current->get()->SameValue(*desc->get()))) &&
7262 (!desc->has_set() ||
7263 (current->has_set() && current->set()->SameValue(*desc->set())))) {
7264 return Just(true);
7265 }
7266 // 5. If the [[Configurable]] field of current is false, then
7267 if (!current->configurable()) {
7268 // 5a. Return false, if the [[Configurable]] field of Desc is true.
7269 if (desc->has_configurable() && desc->configurable()) {
7270 RETURN_FAILURE(
7271 isolate, should_throw,
7272 NewTypeError(MessageTemplate::kRedefineDisallowed,
7273 it != nullptr ? it->GetName() : property_name));
7274 }
7275 // 5b. Return false, if the [[Enumerable]] field of Desc is present and the
7276 // [[Enumerable]] fields of current and Desc are the Boolean negation of
7277 // each other.
7278 if (desc->has_enumerable() && desc->enumerable() != current->enumerable()) {
7279 RETURN_FAILURE(
7280 isolate, should_throw,
7281 NewTypeError(MessageTemplate::kRedefineDisallowed,
7282 it != nullptr ? it->GetName() : property_name));
7283 }
7284 }
7285
7286 bool current_is_data_descriptor =
7287 PropertyDescriptor::IsDataDescriptor(current);
7288 // 6. If IsGenericDescriptor(Desc) is true, no further validation is required.
7289 if (desc_is_generic_descriptor) {
7290 // Nothing to see here.
7291
7292 // 7. Else if IsDataDescriptor(current) and IsDataDescriptor(Desc) have
7293 // different results, then:
7294 } else if (current_is_data_descriptor != desc_is_data_descriptor) {
7295 // 7a. Return false, if the [[Configurable]] field of current is false.
7296 if (!current->configurable()) {
7297 RETURN_FAILURE(
7298 isolate, should_throw,
7299 NewTypeError(MessageTemplate::kRedefineDisallowed,
7300 it != nullptr ? it->GetName() : property_name));
7301 }
7302 // 7b. If IsDataDescriptor(current) is true, then:
7303 if (current_is_data_descriptor) {
7304 // 7b i. If O is not undefined, convert the property named P of object O
7305 // from a data property to an accessor property. Preserve the existing
7306 // values of the converted property's [[Configurable]] and [[Enumerable]]
7307 // attributes and set the rest of the property's attributes to their
7308 // default values.
7309 // --> Folded into step 10.
7310 } else {
7311 // 7c i. If O is not undefined, convert the property named P of object O
7312 // from an accessor property to a data property. Preserve the existing
7313 // values of the converted property’s [[Configurable]] and [[Enumerable]]
7314 // attributes and set the rest of the property’s attributes to their
7315 // default values.
7316 // --> Folded into step 10.
7317 }
7318
7319 // 8. Else if IsDataDescriptor(current) and IsDataDescriptor(Desc) are both
7320 // true, then:
7321 } else if (current_is_data_descriptor && desc_is_data_descriptor) {
7322 // 8a. If the [[Configurable]] field of current is false, then:
7323 if (!current->configurable()) {
7324 // 8a i. Return false, if the [[Writable]] field of current is false and
7325 // the [[Writable]] field of Desc is true.
7326 if (!current->writable() && desc->has_writable() && desc->writable()) {
7327 RETURN_FAILURE(
7328 isolate, should_throw,
7329 NewTypeError(MessageTemplate::kRedefineDisallowed,
7330 it != nullptr ? it->GetName() : property_name));
7331 }
7332 // 8a ii. If the [[Writable]] field of current is false, then:
7333 if (!current->writable()) {
7334 // 8a ii 1. Return false, if the [[Value]] field of Desc is present and
7335 // SameValue(Desc.[[Value]], current.[[Value]]) is false.
7336 if (desc->has_value() && !desc->value()->SameValue(*current->value())) {
7337 RETURN_FAILURE(
7338 isolate, should_throw,
7339 NewTypeError(MessageTemplate::kRedefineDisallowed,
7340 it != nullptr ? it->GetName() : property_name));
7341 }
7342 }
7343 }
7344 } else {
7345 // 9. Else IsAccessorDescriptor(current) and IsAccessorDescriptor(Desc)
7346 // are both true,
7347 DCHECK(PropertyDescriptor::IsAccessorDescriptor(current) &&
7348 desc_is_accessor_descriptor);
7349 // 9a. If the [[Configurable]] field of current is false, then:
7350 if (!current->configurable()) {
7351 // 9a i. Return false, if the [[Set]] field of Desc is present and
7352 // SameValue(Desc.[[Set]], current.[[Set]]) is false.
7353 if (desc->has_set() && !desc->set()->SameValue(*current->set())) {
7354 RETURN_FAILURE(
7355 isolate, should_throw,
7356 NewTypeError(MessageTemplate::kRedefineDisallowed,
7357 it != nullptr ? it->GetName() : property_name));
7358 }
7359 // 9a ii. Return false, if the [[Get]] field of Desc is present and
7360 // SameValue(Desc.[[Get]], current.[[Get]]) is false.
7361 if (desc->has_get() && !desc->get()->SameValue(*current->get())) {
7362 RETURN_FAILURE(
7363 isolate, should_throw,
7364 NewTypeError(MessageTemplate::kRedefineDisallowed,
7365 it != nullptr ? it->GetName() : property_name));
7366 }
7367 }
7368 }
7369
7370 // 10. If O is not undefined, then:
7371 if (it != nullptr) {
7372 // 10a. For each field of Desc that is present, set the corresponding
7373 // attribute of the property named P of object O to the value of the field.
7374 PropertyAttributes attrs = NONE;
7375
7376 if (desc->has_enumerable()) {
7377 attrs = static_cast<PropertyAttributes>(
7378 attrs | (desc->enumerable() ? NONE : DONT_ENUM));
7379 } else {
7380 attrs = static_cast<PropertyAttributes>(
7381 attrs | (current->enumerable() ? NONE : DONT_ENUM));
7382 }
7383 if (desc->has_configurable()) {
7384 attrs = static_cast<PropertyAttributes>(
7385 attrs | (desc->configurable() ? NONE : DONT_DELETE));
7386 } else {
7387 attrs = static_cast<PropertyAttributes>(
7388 attrs | (current->configurable() ? NONE : DONT_DELETE));
7389 }
7390 if (desc_is_data_descriptor ||
7391 (desc_is_generic_descriptor && current_is_data_descriptor)) {
7392 if (desc->has_writable()) {
7393 attrs = static_cast<PropertyAttributes>(
7394 attrs | (desc->writable() ? NONE : READ_ONLY));
7395 } else {
7396 attrs = static_cast<PropertyAttributes>(
7397 attrs | (current->writable() ? NONE : READ_ONLY));
7398 }
7399 Handle<Object> value(
7400 desc->has_value() ? desc->value()
7401 : current->has_value()
7402 ? current->value()
7403 : Handle<Object>::cast(
7404 isolate->factory()->undefined_value()));
7405 return JSObject::DefineOwnPropertyIgnoreAttributes(it, value, attrs,
7406 should_throw);
7407 } else {
7408 DCHECK(desc_is_accessor_descriptor ||
7409 (desc_is_generic_descriptor &&
7410 PropertyDescriptor::IsAccessorDescriptor(current)));
7411 Handle<Object> getter(
7412 desc->has_get()
7413 ? desc->get()
7414 : current->has_get()
7415 ? current->get()
7416 : Handle<Object>::cast(isolate->factory()->null_value()));
7417 Handle<Object> setter(
7418 desc->has_set()
7419 ? desc->set()
7420 : current->has_set()
7421 ? current->set()
7422 : Handle<Object>::cast(isolate->factory()->null_value()));
7423 MaybeHandle<Object> result =
7424 JSObject::DefineAccessor(it, getter, setter, attrs);
7425 if (result.is_null()) return Nothing<bool>();
7426 }
7427 }
7428
7429 // 11. Return true.
7430 return Just(true);
7431 }
7432
7433 // static
CreateDataProperty(Isolate * isolate,Handle<JSReceiver> object,Handle<Name> key,Handle<Object> value,ShouldThrow should_throw)7434 Maybe<bool> JSReceiver::CreateDataProperty(Isolate* isolate,
7435 Handle<JSReceiver> object,
7436 Handle<Name> key,
7437 Handle<Object> value,
7438 ShouldThrow should_throw) {
7439 LookupIterator it = LookupIterator::PropertyOrElement(isolate, object, key,
7440 LookupIterator::OWN);
7441 return CreateDataProperty(&it, value, should_throw);
7442 }
7443
7444 // static
CreateDataProperty(LookupIterator * it,Handle<Object> value,ShouldThrow should_throw)7445 Maybe<bool> JSReceiver::CreateDataProperty(LookupIterator* it,
7446 Handle<Object> value,
7447 ShouldThrow should_throw) {
7448 DCHECK(!it->check_prototype_chain());
7449 Handle<JSReceiver> receiver = Handle<JSReceiver>::cast(it->GetReceiver());
7450 Isolate* isolate = receiver->GetIsolate();
7451
7452 if (receiver->IsJSObject()) {
7453 return JSObject::CreateDataProperty(it, value, should_throw); // Shortcut.
7454 }
7455
7456 PropertyDescriptor new_desc;
7457 new_desc.set_value(value);
7458 new_desc.set_writable(true);
7459 new_desc.set_enumerable(true);
7460 new_desc.set_configurable(true);
7461
7462 return JSReceiver::DefineOwnProperty(isolate, receiver, it->GetName(),
7463 &new_desc, should_throw);
7464 }
7465
CreateDataProperty(LookupIterator * it,Handle<Object> value,ShouldThrow should_throw)7466 Maybe<bool> JSObject::CreateDataProperty(LookupIterator* it,
7467 Handle<Object> value,
7468 ShouldThrow should_throw) {
7469 DCHECK(it->GetReceiver()->IsJSObject());
7470 MAYBE_RETURN(JSReceiver::GetPropertyAttributes(it), Nothing<bool>());
7471 Handle<JSReceiver> receiver = Handle<JSReceiver>::cast(it->GetReceiver());
7472 Isolate* isolate = receiver->GetIsolate();
7473
7474 if (it->IsFound()) {
7475 Maybe<PropertyAttributes> attributes = GetPropertyAttributes(it);
7476 MAYBE_RETURN(attributes, Nothing<bool>());
7477 if ((attributes.FromJust() & DONT_DELETE) != 0) {
7478 RETURN_FAILURE(
7479 isolate, should_throw,
7480 NewTypeError(MessageTemplate::kRedefineDisallowed, it->GetName()));
7481 }
7482 } else {
7483 if (!JSObject::IsExtensible(Handle<JSObject>::cast(it->GetReceiver()))) {
7484 RETURN_FAILURE(
7485 isolate, should_throw,
7486 NewTypeError(MessageTemplate::kDefineDisallowed, it->GetName()));
7487 }
7488 }
7489
7490 RETURN_ON_EXCEPTION_VALUE(it->isolate(),
7491 DefineOwnPropertyIgnoreAttributes(it, value, NONE),
7492 Nothing<bool>());
7493
7494 return Just(true);
7495 }
7496
7497 // TODO(jkummerow): Consider unification with FastAsArrayLength() in
7498 // accessors.cc.
PropertyKeyToArrayLength(Handle<Object> value,uint32_t * length)7499 bool PropertyKeyToArrayLength(Handle<Object> value, uint32_t* length) {
7500 DCHECK(value->IsNumber() || value->IsName());
7501 if (value->ToArrayLength(length)) return true;
7502 if (value->IsString()) return String::cast(*value)->AsArrayIndex(length);
7503 return false;
7504 }
7505
PropertyKeyToArrayIndex(Handle<Object> index_obj,uint32_t * output)7506 bool PropertyKeyToArrayIndex(Handle<Object> index_obj, uint32_t* output) {
7507 return PropertyKeyToArrayLength(index_obj, output) && *output != kMaxUInt32;
7508 }
7509
7510
7511 // ES6 9.4.2.1
7512 // static
DefineOwnProperty(Isolate * isolate,Handle<JSArray> o,Handle<Object> name,PropertyDescriptor * desc,ShouldThrow should_throw)7513 Maybe<bool> JSArray::DefineOwnProperty(Isolate* isolate, Handle<JSArray> o,
7514 Handle<Object> name,
7515 PropertyDescriptor* desc,
7516 ShouldThrow should_throw) {
7517 // 1. Assert: IsPropertyKey(P) is true. ("P" is |name|.)
7518 // 2. If P is "length", then:
7519 // TODO(jkummerow): Check if we need slow string comparison.
7520 if (*name == ReadOnlyRoots(isolate).length_string()) {
7521 // 2a. Return ArraySetLength(A, Desc).
7522 return ArraySetLength(isolate, o, desc, should_throw);
7523 }
7524 // 3. Else if P is an array index, then:
7525 uint32_t index = 0;
7526 if (PropertyKeyToArrayIndex(name, &index)) {
7527 // 3a. Let oldLenDesc be OrdinaryGetOwnProperty(A, "length").
7528 PropertyDescriptor old_len_desc;
7529 Maybe<bool> success = GetOwnPropertyDescriptor(
7530 isolate, o, isolate->factory()->length_string(), &old_len_desc);
7531 // 3b. (Assert)
7532 DCHECK(success.FromJust());
7533 USE(success);
7534 // 3c. Let oldLen be oldLenDesc.[[Value]].
7535 uint32_t old_len = 0;
7536 CHECK(old_len_desc.value()->ToArrayLength(&old_len));
7537 // 3d. Let index be ToUint32(P).
7538 // (Already done above.)
7539 // 3e. (Assert)
7540 // 3f. If index >= oldLen and oldLenDesc.[[Writable]] is false,
7541 // return false.
7542 if (index >= old_len && old_len_desc.has_writable() &&
7543 !old_len_desc.writable()) {
7544 RETURN_FAILURE(isolate, should_throw,
7545 NewTypeError(MessageTemplate::kDefineDisallowed, name));
7546 }
7547 // 3g. Let succeeded be OrdinaryDefineOwnProperty(A, P, Desc).
7548 Maybe<bool> succeeded =
7549 OrdinaryDefineOwnProperty(isolate, o, name, desc, should_throw);
7550 // 3h. Assert: succeeded is not an abrupt completion.
7551 // In our case, if should_throw == kThrowOnError, it can be!
7552 // 3i. If succeeded is false, return false.
7553 if (succeeded.IsNothing() || !succeeded.FromJust()) return succeeded;
7554 // 3j. If index >= oldLen, then:
7555 if (index >= old_len) {
7556 // 3j i. Set oldLenDesc.[[Value]] to index + 1.
7557 old_len_desc.set_value(isolate->factory()->NewNumberFromUint(index + 1));
7558 // 3j ii. Let succeeded be
7559 // OrdinaryDefineOwnProperty(A, "length", oldLenDesc).
7560 succeeded = OrdinaryDefineOwnProperty(isolate, o,
7561 isolate->factory()->length_string(),
7562 &old_len_desc, should_throw);
7563 // 3j iii. Assert: succeeded is true.
7564 DCHECK(succeeded.FromJust());
7565 USE(succeeded);
7566 }
7567 // 3k. Return true.
7568 return Just(true);
7569 }
7570
7571 // 4. Return OrdinaryDefineOwnProperty(A, P, Desc).
7572 return OrdinaryDefineOwnProperty(isolate, o, name, desc, should_throw);
7573 }
7574
7575
7576 // Part of ES6 9.4.2.4 ArraySetLength.
7577 // static
AnythingToArrayLength(Isolate * isolate,Handle<Object> length_object,uint32_t * output)7578 bool JSArray::AnythingToArrayLength(Isolate* isolate,
7579 Handle<Object> length_object,
7580 uint32_t* output) {
7581 // Fast path: check numbers and strings that can be converted directly
7582 // and unobservably.
7583 if (length_object->ToArrayLength(output)) return true;
7584 if (length_object->IsString() &&
7585 Handle<String>::cast(length_object)->AsArrayIndex(output)) {
7586 return true;
7587 }
7588 // Slow path: follow steps in ES6 9.4.2.4 "ArraySetLength".
7589 // 3. Let newLen be ToUint32(Desc.[[Value]]).
7590 Handle<Object> uint32_v;
7591 if (!Object::ToUint32(isolate, length_object).ToHandle(&uint32_v)) {
7592 // 4. ReturnIfAbrupt(newLen).
7593 return false;
7594 }
7595 // 5. Let numberLen be ToNumber(Desc.[[Value]]).
7596 Handle<Object> number_v;
7597 if (!Object::ToNumber(isolate, length_object).ToHandle(&number_v)) {
7598 // 6. ReturnIfAbrupt(newLen).
7599 return false;
7600 }
7601 // 7. If newLen != numberLen, throw a RangeError exception.
7602 if (uint32_v->Number() != number_v->Number()) {
7603 Handle<Object> exception =
7604 isolate->factory()->NewRangeError(MessageTemplate::kInvalidArrayLength);
7605 isolate->Throw(*exception);
7606 return false;
7607 }
7608 CHECK(uint32_v->ToArrayLength(output));
7609 return true;
7610 }
7611
7612
7613 // ES6 9.4.2.4
7614 // static
ArraySetLength(Isolate * isolate,Handle<JSArray> a,PropertyDescriptor * desc,ShouldThrow should_throw)7615 Maybe<bool> JSArray::ArraySetLength(Isolate* isolate, Handle<JSArray> a,
7616 PropertyDescriptor* desc,
7617 ShouldThrow should_throw) {
7618 // 1. If the [[Value]] field of Desc is absent, then
7619 if (!desc->has_value()) {
7620 // 1a. Return OrdinaryDefineOwnProperty(A, "length", Desc).
7621 return OrdinaryDefineOwnProperty(
7622 isolate, a, isolate->factory()->length_string(), desc, should_throw);
7623 }
7624 // 2. Let newLenDesc be a copy of Desc.
7625 // (Actual copying is not necessary.)
7626 PropertyDescriptor* new_len_desc = desc;
7627 // 3. - 7. Convert Desc.[[Value]] to newLen.
7628 uint32_t new_len = 0;
7629 if (!AnythingToArrayLength(isolate, desc->value(), &new_len)) {
7630 DCHECK(isolate->has_pending_exception());
7631 return Nothing<bool>();
7632 }
7633 // 8. Set newLenDesc.[[Value]] to newLen.
7634 // (Done below, if needed.)
7635 // 9. Let oldLenDesc be OrdinaryGetOwnProperty(A, "length").
7636 PropertyDescriptor old_len_desc;
7637 Maybe<bool> success = GetOwnPropertyDescriptor(
7638 isolate, a, isolate->factory()->length_string(), &old_len_desc);
7639 // 10. (Assert)
7640 DCHECK(success.FromJust());
7641 USE(success);
7642 // 11. Let oldLen be oldLenDesc.[[Value]].
7643 uint32_t old_len = 0;
7644 CHECK(old_len_desc.value()->ToArrayLength(&old_len));
7645 // 12. If newLen >= oldLen, then
7646 if (new_len >= old_len) {
7647 // 8. Set newLenDesc.[[Value]] to newLen.
7648 // 12a. Return OrdinaryDefineOwnProperty(A, "length", newLenDesc).
7649 new_len_desc->set_value(isolate->factory()->NewNumberFromUint(new_len));
7650 return OrdinaryDefineOwnProperty(isolate, a,
7651 isolate->factory()->length_string(),
7652 new_len_desc, should_throw);
7653 }
7654 // 13. If oldLenDesc.[[Writable]] is false, return false.
7655 if (!old_len_desc.writable()) {
7656 RETURN_FAILURE(isolate, should_throw,
7657 NewTypeError(MessageTemplate::kRedefineDisallowed,
7658 isolate->factory()->length_string()));
7659 }
7660 // 14. If newLenDesc.[[Writable]] is absent or has the value true,
7661 // let newWritable be true.
7662 bool new_writable = false;
7663 if (!new_len_desc->has_writable() || new_len_desc->writable()) {
7664 new_writable = true;
7665 } else {
7666 // 15. Else,
7667 // 15a. Need to defer setting the [[Writable]] attribute to false in case
7668 // any elements cannot be deleted.
7669 // 15b. Let newWritable be false. (It's initialized as "false" anyway.)
7670 // 15c. Set newLenDesc.[[Writable]] to true.
7671 // (Not needed.)
7672 }
7673 // Most of steps 16 through 19 is implemented by JSArray::SetLength.
7674 JSArray::SetLength(a, new_len);
7675 // Steps 19d-ii, 20.
7676 if (!new_writable) {
7677 PropertyDescriptor readonly;
7678 readonly.set_writable(false);
7679 Maybe<bool> success = OrdinaryDefineOwnProperty(
7680 isolate, a, isolate->factory()->length_string(), &readonly,
7681 should_throw);
7682 DCHECK(success.FromJust());
7683 USE(success);
7684 }
7685 uint32_t actual_new_len = 0;
7686 CHECK(a->length()->ToArrayLength(&actual_new_len));
7687 // Steps 19d-v, 21. Return false if there were non-deletable elements.
7688 bool result = actual_new_len == new_len;
7689 if (!result) {
7690 RETURN_FAILURE(
7691 isolate, should_throw,
7692 NewTypeError(MessageTemplate::kStrictDeleteProperty,
7693 isolate->factory()->NewNumberFromUint(actual_new_len - 1),
7694 a));
7695 }
7696 return Just(result);
7697 }
7698
7699
7700 // ES6 9.5.6
7701 // static
DefineOwnProperty(Isolate * isolate,Handle<JSProxy> proxy,Handle<Object> key,PropertyDescriptor * desc,ShouldThrow should_throw)7702 Maybe<bool> JSProxy::DefineOwnProperty(Isolate* isolate, Handle<JSProxy> proxy,
7703 Handle<Object> key,
7704 PropertyDescriptor* desc,
7705 ShouldThrow should_throw) {
7706 STACK_CHECK(isolate, Nothing<bool>());
7707 if (key->IsSymbol() && Handle<Symbol>::cast(key)->IsPrivate()) {
7708 DCHECK(!Handle<Symbol>::cast(key)->IsPrivateField());
7709 return JSProxy::SetPrivateSymbol(isolate, proxy, Handle<Symbol>::cast(key),
7710 desc, should_throw);
7711 }
7712 Handle<String> trap_name = isolate->factory()->defineProperty_string();
7713 // 1. Assert: IsPropertyKey(P) is true.
7714 DCHECK(key->IsName() || key->IsNumber());
7715 // 2. Let handler be the value of the [[ProxyHandler]] internal slot of O.
7716 Handle<Object> handler(proxy->handler(), isolate);
7717 // 3. If handler is null, throw a TypeError exception.
7718 // 4. Assert: Type(handler) is Object.
7719 if (proxy->IsRevoked()) {
7720 isolate->Throw(*isolate->factory()->NewTypeError(
7721 MessageTemplate::kProxyRevoked, trap_name));
7722 return Nothing<bool>();
7723 }
7724 // 5. Let target be the value of the [[ProxyTarget]] internal slot of O.
7725 Handle<JSReceiver> target(JSReceiver::cast(proxy->target()), isolate);
7726 // 6. Let trap be ? GetMethod(handler, "defineProperty").
7727 Handle<Object> trap;
7728 ASSIGN_RETURN_ON_EXCEPTION_VALUE(
7729 isolate, trap,
7730 Object::GetMethod(Handle<JSReceiver>::cast(handler), trap_name),
7731 Nothing<bool>());
7732 // 7. If trap is undefined, then:
7733 if (trap->IsUndefined(isolate)) {
7734 // 7a. Return target.[[DefineOwnProperty]](P, Desc).
7735 return JSReceiver::DefineOwnProperty(isolate, target, key, desc,
7736 should_throw);
7737 }
7738 // 8. Let descObj be FromPropertyDescriptor(Desc).
7739 Handle<Object> desc_obj = desc->ToObject(isolate);
7740 // 9. Let booleanTrapResult be
7741 // ToBoolean(? Call(trap, handler, «target, P, descObj»)).
7742 Handle<Name> property_name =
7743 key->IsName()
7744 ? Handle<Name>::cast(key)
7745 : Handle<Name>::cast(isolate->factory()->NumberToString(key));
7746 // Do not leak private property names.
7747 DCHECK(!property_name->IsPrivate());
7748 Handle<Object> trap_result_obj;
7749 Handle<Object> args[] = {target, property_name, desc_obj};
7750 ASSIGN_RETURN_ON_EXCEPTION_VALUE(
7751 isolate, trap_result_obj,
7752 Execution::Call(isolate, trap, handler, arraysize(args), args),
7753 Nothing<bool>());
7754 // 10. If booleanTrapResult is false, return false.
7755 if (!trap_result_obj->BooleanValue(isolate)) {
7756 RETURN_FAILURE(isolate, should_throw,
7757 NewTypeError(MessageTemplate::kProxyTrapReturnedFalsishFor,
7758 trap_name, property_name));
7759 }
7760 // 11. Let targetDesc be ? target.[[GetOwnProperty]](P).
7761 PropertyDescriptor target_desc;
7762 Maybe<bool> target_found =
7763 JSReceiver::GetOwnPropertyDescriptor(isolate, target, key, &target_desc);
7764 MAYBE_RETURN(target_found, Nothing<bool>());
7765 // 12. Let extensibleTarget be ? IsExtensible(target).
7766 Maybe<bool> maybe_extensible = JSReceiver::IsExtensible(target);
7767 MAYBE_RETURN(maybe_extensible, Nothing<bool>());
7768 bool extensible_target = maybe_extensible.FromJust();
7769 // 13. If Desc has a [[Configurable]] field and if Desc.[[Configurable]]
7770 // is false, then:
7771 // 13a. Let settingConfigFalse be true.
7772 // 14. Else let settingConfigFalse be false.
7773 bool setting_config_false = desc->has_configurable() && !desc->configurable();
7774 // 15. If targetDesc is undefined, then
7775 if (!target_found.FromJust()) {
7776 // 15a. If extensibleTarget is false, throw a TypeError exception.
7777 if (!extensible_target) {
7778 isolate->Throw(*isolate->factory()->NewTypeError(
7779 MessageTemplate::kProxyDefinePropertyNonExtensible, property_name));
7780 return Nothing<bool>();
7781 }
7782 // 15b. If settingConfigFalse is true, throw a TypeError exception.
7783 if (setting_config_false) {
7784 isolate->Throw(*isolate->factory()->NewTypeError(
7785 MessageTemplate::kProxyDefinePropertyNonConfigurable, property_name));
7786 return Nothing<bool>();
7787 }
7788 } else {
7789 // 16. Else targetDesc is not undefined,
7790 // 16a. If IsCompatiblePropertyDescriptor(extensibleTarget, Desc,
7791 // targetDesc) is false, throw a TypeError exception.
7792 Maybe<bool> valid =
7793 IsCompatiblePropertyDescriptor(isolate, extensible_target, desc,
7794 &target_desc, property_name, kDontThrow);
7795 MAYBE_RETURN(valid, Nothing<bool>());
7796 if (!valid.FromJust()) {
7797 isolate->Throw(*isolate->factory()->NewTypeError(
7798 MessageTemplate::kProxyDefinePropertyIncompatible, property_name));
7799 return Nothing<bool>();
7800 }
7801 // 16b. If settingConfigFalse is true and targetDesc.[[Configurable]] is
7802 // true, throw a TypeError exception.
7803 if (setting_config_false && target_desc.configurable()) {
7804 isolate->Throw(*isolate->factory()->NewTypeError(
7805 MessageTemplate::kProxyDefinePropertyNonConfigurable, property_name));
7806 return Nothing<bool>();
7807 }
7808 }
7809 // 17. Return true.
7810 return Just(true);
7811 }
7812
7813 // static
SetPrivateSymbol(Isolate * isolate,Handle<JSProxy> proxy,Handle<Symbol> private_name,PropertyDescriptor * desc,ShouldThrow should_throw)7814 Maybe<bool> JSProxy::SetPrivateSymbol(Isolate* isolate, Handle<JSProxy> proxy,
7815 Handle<Symbol> private_name,
7816 PropertyDescriptor* desc,
7817 ShouldThrow should_throw) {
7818 DCHECK(!private_name->IsPrivateField());
7819 // Despite the generic name, this can only add private data properties.
7820 if (!PropertyDescriptor::IsDataDescriptor(desc) ||
7821 desc->ToAttributes() != DONT_ENUM) {
7822 RETURN_FAILURE(isolate, should_throw,
7823 NewTypeError(MessageTemplate::kProxyPrivate));
7824 }
7825 DCHECK(proxy->map()->is_dictionary_map());
7826 Handle<Object> value =
7827 desc->has_value()
7828 ? desc->value()
7829 : Handle<Object>::cast(isolate->factory()->undefined_value());
7830
7831 LookupIterator it(proxy, private_name, proxy);
7832
7833 if (it.IsFound()) {
7834 DCHECK_EQ(LookupIterator::DATA, it.state());
7835 DCHECK_EQ(DONT_ENUM, it.property_attributes());
7836 it.WriteDataValue(value, false);
7837 return Just(true);
7838 }
7839
7840 Handle<NameDictionary> dict(proxy->property_dictionary(), isolate);
7841 PropertyDetails details(kData, DONT_ENUM, PropertyCellType::kNoCell);
7842 Handle<NameDictionary> result =
7843 NameDictionary::Add(isolate, dict, private_name, value, details);
7844 if (!dict.is_identical_to(result)) proxy->SetProperties(*result);
7845 return Just(true);
7846 }
7847
7848 // static
GetOwnPropertyDescriptor(Isolate * isolate,Handle<JSReceiver> object,Handle<Object> key,PropertyDescriptor * desc)7849 Maybe<bool> JSReceiver::GetOwnPropertyDescriptor(Isolate* isolate,
7850 Handle<JSReceiver> object,
7851 Handle<Object> key,
7852 PropertyDescriptor* desc) {
7853 bool success = false;
7854 DCHECK(key->IsName() || key->IsNumber()); // |key| is a PropertyKey...
7855 LookupIterator it = LookupIterator::PropertyOrElement(
7856 isolate, object, key, &success, LookupIterator::OWN);
7857 DCHECK(success); // ...so creating a LookupIterator can't fail.
7858 return GetOwnPropertyDescriptor(&it, desc);
7859 }
7860
7861 namespace {
7862
GetPropertyDescriptorWithInterceptor(LookupIterator * it,PropertyDescriptor * desc)7863 Maybe<bool> GetPropertyDescriptorWithInterceptor(LookupIterator* it,
7864 PropertyDescriptor* desc) {
7865 if (it->state() == LookupIterator::ACCESS_CHECK) {
7866 if (it->HasAccess()) {
7867 it->Next();
7868 } else if (!JSObject::AllCanRead(it) ||
7869 it->state() != LookupIterator::INTERCEPTOR) {
7870 it->Restart();
7871 return Just(false);
7872 }
7873 }
7874
7875 if (it->state() != LookupIterator::INTERCEPTOR) return Just(false);
7876
7877 Isolate* isolate = it->isolate();
7878 Handle<InterceptorInfo> interceptor = it->GetInterceptor();
7879 if (interceptor->descriptor()->IsUndefined(isolate)) return Just(false);
7880
7881 Handle<Object> result;
7882 Handle<JSObject> holder = it->GetHolder<JSObject>();
7883
7884 Handle<Object> receiver = it->GetReceiver();
7885 if (!receiver->IsJSReceiver()) {
7886 ASSIGN_RETURN_ON_EXCEPTION_VALUE(isolate, receiver,
7887 Object::ConvertReceiver(isolate, receiver),
7888 Nothing<bool>());
7889 }
7890
7891 PropertyCallbackArguments args(isolate, interceptor->data(), *receiver,
7892 *holder, kDontThrow);
7893 if (it->IsElement()) {
7894 result = args.CallIndexedDescriptor(interceptor, it->index());
7895 } else {
7896 result = args.CallNamedDescriptor(interceptor, it->name());
7897 }
7898 if (!result.is_null()) {
7899 // Request successfully intercepted, try to set the property
7900 // descriptor.
7901 Utils::ApiCheck(
7902 PropertyDescriptor::ToPropertyDescriptor(isolate, result, desc),
7903 it->IsElement() ? "v8::IndexedPropertyDescriptorCallback"
7904 : "v8::NamedPropertyDescriptorCallback",
7905 "Invalid property descriptor.");
7906
7907 return Just(true);
7908 }
7909
7910 it->Next();
7911 return Just(false);
7912 }
7913 } // namespace
7914
7915 // ES6 9.1.5.1
7916 // Returns true on success, false if the property didn't exist, nothing if
7917 // an exception was thrown.
7918 // static
GetOwnPropertyDescriptor(LookupIterator * it,PropertyDescriptor * desc)7919 Maybe<bool> JSReceiver::GetOwnPropertyDescriptor(LookupIterator* it,
7920 PropertyDescriptor* desc) {
7921 Isolate* isolate = it->isolate();
7922 // "Virtual" dispatch.
7923 if (it->IsFound() && it->GetHolder<JSReceiver>()->IsJSProxy()) {
7924 return JSProxy::GetOwnPropertyDescriptor(isolate, it->GetHolder<JSProxy>(),
7925 it->GetName(), desc);
7926 }
7927
7928 Maybe<bool> intercepted = GetPropertyDescriptorWithInterceptor(it, desc);
7929 MAYBE_RETURN(intercepted, Nothing<bool>());
7930 if (intercepted.FromJust()) {
7931 return Just(true);
7932 }
7933
7934 // Request was not intercepted, continue as normal.
7935 // 1. (Assert)
7936 // 2. If O does not have an own property with key P, return undefined.
7937 Maybe<PropertyAttributes> maybe = JSObject::GetPropertyAttributes(it);
7938 MAYBE_RETURN(maybe, Nothing<bool>());
7939 PropertyAttributes attrs = maybe.FromJust();
7940 if (attrs == ABSENT) return Just(false);
7941 DCHECK(!isolate->has_pending_exception());
7942
7943 // 3. Let D be a newly created Property Descriptor with no fields.
7944 DCHECK(desc->is_empty());
7945 // 4. Let X be O's own property whose key is P.
7946 // 5. If X is a data property, then
7947 bool is_accessor_pair = it->state() == LookupIterator::ACCESSOR &&
7948 it->GetAccessors()->IsAccessorPair();
7949 if (!is_accessor_pair) {
7950 // 5a. Set D.[[Value]] to the value of X's [[Value]] attribute.
7951 Handle<Object> value;
7952 if (!Object::GetProperty(it).ToHandle(&value)) {
7953 DCHECK(isolate->has_pending_exception());
7954 return Nothing<bool>();
7955 }
7956 desc->set_value(value);
7957 // 5b. Set D.[[Writable]] to the value of X's [[Writable]] attribute
7958 desc->set_writable((attrs & READ_ONLY) == 0);
7959 } else {
7960 // 6. Else X is an accessor property, so
7961 Handle<AccessorPair> accessors =
7962 Handle<AccessorPair>::cast(it->GetAccessors());
7963 // 6a. Set D.[[Get]] to the value of X's [[Get]] attribute.
7964 desc->set_get(
7965 AccessorPair::GetComponent(isolate, accessors, ACCESSOR_GETTER));
7966 // 6b. Set D.[[Set]] to the value of X's [[Set]] attribute.
7967 desc->set_set(
7968 AccessorPair::GetComponent(isolate, accessors, ACCESSOR_SETTER));
7969 }
7970
7971 // 7. Set D.[[Enumerable]] to the value of X's [[Enumerable]] attribute.
7972 desc->set_enumerable((attrs & DONT_ENUM) == 0);
7973 // 8. Set D.[[Configurable]] to the value of X's [[Configurable]] attribute.
7974 desc->set_configurable((attrs & DONT_DELETE) == 0);
7975 // 9. Return D.
7976 DCHECK(PropertyDescriptor::IsAccessorDescriptor(desc) !=
7977 PropertyDescriptor::IsDataDescriptor(desc));
7978 return Just(true);
7979 }
7980
7981
7982 // ES6 9.5.5
7983 // static
GetOwnPropertyDescriptor(Isolate * isolate,Handle<JSProxy> proxy,Handle<Name> name,PropertyDescriptor * desc)7984 Maybe<bool> JSProxy::GetOwnPropertyDescriptor(Isolate* isolate,
7985 Handle<JSProxy> proxy,
7986 Handle<Name> name,
7987 PropertyDescriptor* desc) {
7988 DCHECK(!name->IsPrivate());
7989 STACK_CHECK(isolate, Nothing<bool>());
7990
7991 Handle<String> trap_name =
7992 isolate->factory()->getOwnPropertyDescriptor_string();
7993 // 1. (Assert)
7994 // 2. Let handler be the value of the [[ProxyHandler]] internal slot of O.
7995 Handle<Object> handler(proxy->handler(), isolate);
7996 // 3. If handler is null, throw a TypeError exception.
7997 // 4. Assert: Type(handler) is Object.
7998 if (proxy->IsRevoked()) {
7999 isolate->Throw(*isolate->factory()->NewTypeError(
8000 MessageTemplate::kProxyRevoked, trap_name));
8001 return Nothing<bool>();
8002 }
8003 // 5. Let target be the value of the [[ProxyTarget]] internal slot of O.
8004 Handle<JSReceiver> target(JSReceiver::cast(proxy->target()), isolate);
8005 // 6. Let trap be ? GetMethod(handler, "getOwnPropertyDescriptor").
8006 Handle<Object> trap;
8007 ASSIGN_RETURN_ON_EXCEPTION_VALUE(
8008 isolate, trap,
8009 Object::GetMethod(Handle<JSReceiver>::cast(handler), trap_name),
8010 Nothing<bool>());
8011 // 7. If trap is undefined, then
8012 if (trap->IsUndefined(isolate)) {
8013 // 7a. Return target.[[GetOwnProperty]](P).
8014 return JSReceiver::GetOwnPropertyDescriptor(isolate, target, name, desc);
8015 }
8016 // 8. Let trapResultObj be ? Call(trap, handler, «target, P»).
8017 Handle<Object> trap_result_obj;
8018 Handle<Object> args[] = {target, name};
8019 ASSIGN_RETURN_ON_EXCEPTION_VALUE(
8020 isolate, trap_result_obj,
8021 Execution::Call(isolate, trap, handler, arraysize(args), args),
8022 Nothing<bool>());
8023 // 9. If Type(trapResultObj) is neither Object nor Undefined, throw a
8024 // TypeError exception.
8025 if (!trap_result_obj->IsJSReceiver() &&
8026 !trap_result_obj->IsUndefined(isolate)) {
8027 isolate->Throw(*isolate->factory()->NewTypeError(
8028 MessageTemplate::kProxyGetOwnPropertyDescriptorInvalid, name));
8029 return Nothing<bool>();
8030 }
8031 // 10. Let targetDesc be ? target.[[GetOwnProperty]](P).
8032 PropertyDescriptor target_desc;
8033 Maybe<bool> found =
8034 JSReceiver::GetOwnPropertyDescriptor(isolate, target, name, &target_desc);
8035 MAYBE_RETURN(found, Nothing<bool>());
8036 // 11. If trapResultObj is undefined, then
8037 if (trap_result_obj->IsUndefined(isolate)) {
8038 // 11a. If targetDesc is undefined, return undefined.
8039 if (!found.FromJust()) return Just(false);
8040 // 11b. If targetDesc.[[Configurable]] is false, throw a TypeError
8041 // exception.
8042 if (!target_desc.configurable()) {
8043 isolate->Throw(*isolate->factory()->NewTypeError(
8044 MessageTemplate::kProxyGetOwnPropertyDescriptorUndefined, name));
8045 return Nothing<bool>();
8046 }
8047 // 11c. Let extensibleTarget be ? IsExtensible(target).
8048 Maybe<bool> extensible_target = JSReceiver::IsExtensible(target);
8049 MAYBE_RETURN(extensible_target, Nothing<bool>());
8050 // 11d. (Assert)
8051 // 11e. If extensibleTarget is false, throw a TypeError exception.
8052 if (!extensible_target.FromJust()) {
8053 isolate->Throw(*isolate->factory()->NewTypeError(
8054 MessageTemplate::kProxyGetOwnPropertyDescriptorNonExtensible, name));
8055 return Nothing<bool>();
8056 }
8057 // 11f. Return undefined.
8058 return Just(false);
8059 }
8060 // 12. Let extensibleTarget be ? IsExtensible(target).
8061 Maybe<bool> extensible_target = JSReceiver::IsExtensible(target);
8062 MAYBE_RETURN(extensible_target, Nothing<bool>());
8063 // 13. Let resultDesc be ? ToPropertyDescriptor(trapResultObj).
8064 if (!PropertyDescriptor::ToPropertyDescriptor(isolate, trap_result_obj,
8065 desc)) {
8066 DCHECK(isolate->has_pending_exception());
8067 return Nothing<bool>();
8068 }
8069 // 14. Call CompletePropertyDescriptor(resultDesc).
8070 PropertyDescriptor::CompletePropertyDescriptor(isolate, desc);
8071 // 15. Let valid be IsCompatiblePropertyDescriptor (extensibleTarget,
8072 // resultDesc, targetDesc).
8073 Maybe<bool> valid =
8074 IsCompatiblePropertyDescriptor(isolate, extensible_target.FromJust(),
8075 desc, &target_desc, name, kDontThrow);
8076 MAYBE_RETURN(valid, Nothing<bool>());
8077 // 16. If valid is false, throw a TypeError exception.
8078 if (!valid.FromJust()) {
8079 isolate->Throw(*isolate->factory()->NewTypeError(
8080 MessageTemplate::kProxyGetOwnPropertyDescriptorIncompatible, name));
8081 return Nothing<bool>();
8082 }
8083 // 17. If resultDesc.[[Configurable]] is false, then
8084 if (!desc->configurable()) {
8085 // 17a. If targetDesc is undefined or targetDesc.[[Configurable]] is true:
8086 if (target_desc.is_empty() || target_desc.configurable()) {
8087 // 17a i. Throw a TypeError exception.
8088 isolate->Throw(*isolate->factory()->NewTypeError(
8089 MessageTemplate::kProxyGetOwnPropertyDescriptorNonConfigurable,
8090 name));
8091 return Nothing<bool>();
8092 }
8093 }
8094 // 18. Return resultDesc.
8095 return Just(true);
8096 }
8097
8098
ReferencesObjectFromElements(FixedArray * elements,ElementsKind kind,Object * object)8099 bool JSObject::ReferencesObjectFromElements(FixedArray* elements,
8100 ElementsKind kind,
8101 Object* object) {
8102 Isolate* isolate = GetIsolate();
8103 if (IsObjectElementsKind(kind) || kind == FAST_STRING_WRAPPER_ELEMENTS) {
8104 int length = IsJSArray() ? Smi::ToInt(JSArray::cast(this)->length())
8105 : elements->length();
8106 for (int i = 0; i < length; ++i) {
8107 Object* element = elements->get(i);
8108 if (!element->IsTheHole(isolate) && element == object) return true;
8109 }
8110 } else {
8111 DCHECK(kind == DICTIONARY_ELEMENTS || kind == SLOW_STRING_WRAPPER_ELEMENTS);
8112 Object* key = NumberDictionary::cast(elements)->SlowReverseLookup(object);
8113 if (!key->IsUndefined(isolate)) return true;
8114 }
8115 return false;
8116 }
8117
8118
8119 // Check whether this object references another object.
ReferencesObject(Object * obj)8120 bool JSObject::ReferencesObject(Object* obj) {
8121 Map* map_of_this = map();
8122 Heap* heap = GetHeap();
8123 DisallowHeapAllocation no_allocation;
8124
8125 // Is the object the constructor for this object?
8126 if (map_of_this->GetConstructor() == obj) {
8127 return true;
8128 }
8129
8130 // Is the object the prototype for this object?
8131 if (map_of_this->prototype() == obj) {
8132 return true;
8133 }
8134
8135 // Check if the object is among the named properties.
8136 Object* key = SlowReverseLookup(obj);
8137 if (!key->IsUndefined(heap->isolate())) {
8138 return true;
8139 }
8140
8141 // Check if the object is among the indexed properties.
8142 ElementsKind kind = GetElementsKind();
8143 switch (kind) {
8144 // Raw pixels and external arrays do not reference other
8145 // objects.
8146 #define TYPED_ARRAY_CASE(Type, type, TYPE, ctype) \
8147 case TYPE##_ELEMENTS: \
8148 break;
8149
8150 TYPED_ARRAYS(TYPED_ARRAY_CASE)
8151 #undef TYPED_ARRAY_CASE
8152
8153 case PACKED_DOUBLE_ELEMENTS:
8154 case HOLEY_DOUBLE_ELEMENTS:
8155 break;
8156 case PACKED_SMI_ELEMENTS:
8157 case HOLEY_SMI_ELEMENTS:
8158 break;
8159 case PACKED_ELEMENTS:
8160 case HOLEY_ELEMENTS:
8161 case DICTIONARY_ELEMENTS:
8162 case FAST_STRING_WRAPPER_ELEMENTS:
8163 case SLOW_STRING_WRAPPER_ELEMENTS: {
8164 FixedArray* elements = FixedArray::cast(this->elements());
8165 if (ReferencesObjectFromElements(elements, kind, obj)) return true;
8166 break;
8167 }
8168 case FAST_SLOPPY_ARGUMENTS_ELEMENTS:
8169 case SLOW_SLOPPY_ARGUMENTS_ELEMENTS: {
8170 SloppyArgumentsElements* elements =
8171 SloppyArgumentsElements::cast(this->elements());
8172 // Check the mapped parameters.
8173 for (uint32_t i = 0; i < elements->parameter_map_length(); ++i) {
8174 Object* value = elements->get_mapped_entry(i);
8175 if (!value->IsTheHole(heap->isolate()) && value == obj) return true;
8176 }
8177 // Check the arguments.
8178 FixedArray* arguments = elements->arguments();
8179 kind = arguments->IsNumberDictionary() ? DICTIONARY_ELEMENTS
8180 : HOLEY_ELEMENTS;
8181 if (ReferencesObjectFromElements(arguments, kind, obj)) return true;
8182 break;
8183 }
8184 case NO_ELEMENTS:
8185 break;
8186 }
8187
8188 // For functions check the context.
8189 if (IsJSFunction()) {
8190 // Get the constructor function for arguments array.
8191 Map* arguments_map =
8192 heap->isolate()->context()->native_context()->sloppy_arguments_map();
8193 JSFunction* arguments_function =
8194 JSFunction::cast(arguments_map->GetConstructor());
8195
8196 // Get the context and don't check if it is the native context.
8197 JSFunction* f = JSFunction::cast(this);
8198 Context* context = f->context();
8199 if (context->IsNativeContext()) {
8200 return false;
8201 }
8202
8203 // Check the non-special context slots.
8204 for (int i = Context::MIN_CONTEXT_SLOTS; i < context->length(); i++) {
8205 // Only check JS objects.
8206 if (context->get(i)->IsJSObject()) {
8207 JSObject* ctxobj = JSObject::cast(context->get(i));
8208 // If it is an arguments array check the content.
8209 if (ctxobj->map()->GetConstructor() == arguments_function) {
8210 if (ctxobj->ReferencesObject(obj)) {
8211 return true;
8212 }
8213 } else if (ctxobj == obj) {
8214 return true;
8215 }
8216 }
8217 }
8218
8219 // Check the context extension (if any) if it can have references.
8220 if (context->has_extension() && !context->IsCatchContext() &&
8221 !context->IsModuleContext()) {
8222 // With harmony scoping, a JSFunction may have a script context.
8223 // TODO(mvstanton): walk into the ScopeInfo.
8224 if (context->IsScriptContext()) {
8225 return false;
8226 }
8227
8228 return context->extension_object()->ReferencesObject(obj);
8229 }
8230 }
8231
8232 // No references to object.
8233 return false;
8234 }
8235
8236
SetIntegrityLevel(Handle<JSReceiver> receiver,IntegrityLevel level,ShouldThrow should_throw)8237 Maybe<bool> JSReceiver::SetIntegrityLevel(Handle<JSReceiver> receiver,
8238 IntegrityLevel level,
8239 ShouldThrow should_throw) {
8240 DCHECK(level == SEALED || level == FROZEN);
8241
8242 if (receiver->IsJSObject()) {
8243 Handle<JSObject> object = Handle<JSObject>::cast(receiver);
8244
8245 if (!object->HasSloppyArgumentsElements() &&
8246 !object->IsJSModuleNamespace()) { // Fast path.
8247 // Prevent memory leaks by not adding unnecessary transitions.
8248 Maybe<bool> test = JSObject::TestIntegrityLevel(object, level);
8249 MAYBE_RETURN(test, Nothing<bool>());
8250 if (test.FromJust()) return test;
8251
8252 if (level == SEALED) {
8253 return JSObject::PreventExtensionsWithTransition<SEALED>(object,
8254 should_throw);
8255 } else {
8256 return JSObject::PreventExtensionsWithTransition<FROZEN>(object,
8257 should_throw);
8258 }
8259 }
8260 }
8261
8262 Isolate* isolate = receiver->GetIsolate();
8263
8264 MAYBE_RETURN(JSReceiver::PreventExtensions(receiver, should_throw),
8265 Nothing<bool>());
8266
8267 Handle<FixedArray> keys;
8268 ASSIGN_RETURN_ON_EXCEPTION_VALUE(
8269 isolate, keys, JSReceiver::OwnPropertyKeys(receiver), Nothing<bool>());
8270
8271 PropertyDescriptor no_conf;
8272 no_conf.set_configurable(false);
8273
8274 PropertyDescriptor no_conf_no_write;
8275 no_conf_no_write.set_configurable(false);
8276 no_conf_no_write.set_writable(false);
8277
8278 if (level == SEALED) {
8279 for (int i = 0; i < keys->length(); ++i) {
8280 Handle<Object> key(keys->get(i), isolate);
8281 MAYBE_RETURN(
8282 DefineOwnProperty(isolate, receiver, key, &no_conf, kThrowOnError),
8283 Nothing<bool>());
8284 }
8285 return Just(true);
8286 }
8287
8288 for (int i = 0; i < keys->length(); ++i) {
8289 Handle<Object> key(keys->get(i), isolate);
8290 PropertyDescriptor current_desc;
8291 Maybe<bool> owned = JSReceiver::GetOwnPropertyDescriptor(
8292 isolate, receiver, key, ¤t_desc);
8293 MAYBE_RETURN(owned, Nothing<bool>());
8294 if (owned.FromJust()) {
8295 PropertyDescriptor desc =
8296 PropertyDescriptor::IsAccessorDescriptor(¤t_desc)
8297 ? no_conf
8298 : no_conf_no_write;
8299 MAYBE_RETURN(
8300 DefineOwnProperty(isolate, receiver, key, &desc, kThrowOnError),
8301 Nothing<bool>());
8302 }
8303 }
8304 return Just(true);
8305 }
8306
8307 namespace {
8308
8309 template <typename Dictionary>
TestDictionaryPropertiesIntegrityLevel(Dictionary * dict,ReadOnlyRoots roots,PropertyAttributes level)8310 bool TestDictionaryPropertiesIntegrityLevel(Dictionary* dict,
8311 ReadOnlyRoots roots,
8312 PropertyAttributes level) {
8313 DCHECK(level == SEALED || level == FROZEN);
8314
8315 uint32_t capacity = dict->Capacity();
8316 for (uint32_t i = 0; i < capacity; i++) {
8317 Object* key;
8318 if (!dict->ToKey(roots, i, &key)) continue;
8319 if (key->FilterKey(ALL_PROPERTIES)) continue;
8320 PropertyDetails details = dict->DetailsAt(i);
8321 if (details.IsConfigurable()) return false;
8322 if (level == FROZEN && details.kind() == kData && !details.IsReadOnly()) {
8323 return false;
8324 }
8325 }
8326 return true;
8327 }
8328
TestFastPropertiesIntegrityLevel(Map * map,PropertyAttributes level)8329 bool TestFastPropertiesIntegrityLevel(Map* map, PropertyAttributes level) {
8330 DCHECK(level == SEALED || level == FROZEN);
8331 DCHECK(!map->IsCustomElementsReceiverMap());
8332 DCHECK(!map->is_dictionary_map());
8333
8334 DescriptorArray* descriptors = map->instance_descriptors();
8335 int number_of_own_descriptors = map->NumberOfOwnDescriptors();
8336 for (int i = 0; i < number_of_own_descriptors; i++) {
8337 if (descriptors->GetKey(i)->IsPrivate()) continue;
8338 PropertyDetails details = descriptors->GetDetails(i);
8339 if (details.IsConfigurable()) return false;
8340 if (level == FROZEN && details.kind() == kData && !details.IsReadOnly()) {
8341 return false;
8342 }
8343 }
8344 return true;
8345 }
8346
TestPropertiesIntegrityLevel(JSObject * object,PropertyAttributes level)8347 bool TestPropertiesIntegrityLevel(JSObject* object, PropertyAttributes level) {
8348 DCHECK(!object->map()->IsCustomElementsReceiverMap());
8349
8350 if (object->HasFastProperties()) {
8351 return TestFastPropertiesIntegrityLevel(object->map(), level);
8352 }
8353
8354 return TestDictionaryPropertiesIntegrityLevel(
8355 object->property_dictionary(), object->GetReadOnlyRoots(), level);
8356 }
8357
TestElementsIntegrityLevel(JSObject * object,PropertyAttributes level)8358 bool TestElementsIntegrityLevel(JSObject* object, PropertyAttributes level) {
8359 DCHECK(!object->HasSloppyArgumentsElements());
8360
8361 ElementsKind kind = object->GetElementsKind();
8362
8363 if (IsDictionaryElementsKind(kind)) {
8364 return TestDictionaryPropertiesIntegrityLevel(
8365 NumberDictionary::cast(object->elements()), object->GetReadOnlyRoots(),
8366 level);
8367 }
8368
8369 ElementsAccessor* accessor = ElementsAccessor::ForKind(kind);
8370 // Only DICTIONARY_ELEMENTS and SLOW_SLOPPY_ARGUMENTS_ELEMENTS have
8371 // PropertyAttributes so just test if empty
8372 return accessor->NumberOfElements(object) == 0;
8373 }
8374
FastTestIntegrityLevel(JSObject * object,PropertyAttributes level)8375 bool FastTestIntegrityLevel(JSObject* object, PropertyAttributes level) {
8376 DCHECK(!object->map()->IsCustomElementsReceiverMap());
8377
8378 return !object->map()->is_extensible() &&
8379 TestElementsIntegrityLevel(object, level) &&
8380 TestPropertiesIntegrityLevel(object, level);
8381 }
8382
GenericTestIntegrityLevel(Handle<JSReceiver> receiver,PropertyAttributes level)8383 Maybe<bool> GenericTestIntegrityLevel(Handle<JSReceiver> receiver,
8384 PropertyAttributes level) {
8385 DCHECK(level == SEALED || level == FROZEN);
8386
8387 Maybe<bool> extensible = JSReceiver::IsExtensible(receiver);
8388 MAYBE_RETURN(extensible, Nothing<bool>());
8389 if (extensible.FromJust()) return Just(false);
8390
8391 Isolate* isolate = receiver->GetIsolate();
8392
8393 Handle<FixedArray> keys;
8394 ASSIGN_RETURN_ON_EXCEPTION_VALUE(
8395 isolate, keys, JSReceiver::OwnPropertyKeys(receiver), Nothing<bool>());
8396
8397 for (int i = 0; i < keys->length(); ++i) {
8398 Handle<Object> key(keys->get(i), isolate);
8399 PropertyDescriptor current_desc;
8400 Maybe<bool> owned = JSReceiver::GetOwnPropertyDescriptor(
8401 isolate, receiver, key, ¤t_desc);
8402 MAYBE_RETURN(owned, Nothing<bool>());
8403 if (owned.FromJust()) {
8404 if (current_desc.configurable()) return Just(false);
8405 if (level == FROZEN &&
8406 PropertyDescriptor::IsDataDescriptor(¤t_desc) &&
8407 current_desc.writable()) {
8408 return Just(false);
8409 }
8410 }
8411 }
8412 return Just(true);
8413 }
8414
8415 } // namespace
8416
TestIntegrityLevel(Handle<JSReceiver> receiver,IntegrityLevel level)8417 Maybe<bool> JSReceiver::TestIntegrityLevel(Handle<JSReceiver> receiver,
8418 IntegrityLevel level) {
8419 if (!receiver->map()->IsCustomElementsReceiverMap()) {
8420 return JSObject::TestIntegrityLevel(Handle<JSObject>::cast(receiver),
8421 level);
8422 }
8423 return GenericTestIntegrityLevel(receiver, level);
8424 }
8425
TestIntegrityLevel(Handle<JSObject> object,IntegrityLevel level)8426 Maybe<bool> JSObject::TestIntegrityLevel(Handle<JSObject> object,
8427 IntegrityLevel level) {
8428 if (!object->map()->IsCustomElementsReceiverMap() &&
8429 !object->HasSloppyArgumentsElements()) {
8430 return Just(FastTestIntegrityLevel(*object, level));
8431 }
8432 return GenericTestIntegrityLevel(Handle<JSReceiver>::cast(object), level);
8433 }
8434
PreventExtensions(Handle<JSReceiver> object,ShouldThrow should_throw)8435 Maybe<bool> JSReceiver::PreventExtensions(Handle<JSReceiver> object,
8436 ShouldThrow should_throw) {
8437 if (object->IsJSProxy()) {
8438 return JSProxy::PreventExtensions(Handle<JSProxy>::cast(object),
8439 should_throw);
8440 }
8441 DCHECK(object->IsJSObject());
8442 return JSObject::PreventExtensions(Handle<JSObject>::cast(object),
8443 should_throw);
8444 }
8445
8446
PreventExtensions(Handle<JSProxy> proxy,ShouldThrow should_throw)8447 Maybe<bool> JSProxy::PreventExtensions(Handle<JSProxy> proxy,
8448 ShouldThrow should_throw) {
8449 Isolate* isolate = proxy->GetIsolate();
8450 STACK_CHECK(isolate, Nothing<bool>());
8451 Factory* factory = isolate->factory();
8452 Handle<String> trap_name = factory->preventExtensions_string();
8453
8454 if (proxy->IsRevoked()) {
8455 isolate->Throw(
8456 *factory->NewTypeError(MessageTemplate::kProxyRevoked, trap_name));
8457 return Nothing<bool>();
8458 }
8459 Handle<JSReceiver> target(JSReceiver::cast(proxy->target()), isolate);
8460 Handle<JSReceiver> handler(JSReceiver::cast(proxy->handler()), isolate);
8461
8462 Handle<Object> trap;
8463 ASSIGN_RETURN_ON_EXCEPTION_VALUE(
8464 isolate, trap, Object::GetMethod(handler, trap_name), Nothing<bool>());
8465 if (trap->IsUndefined(isolate)) {
8466 return JSReceiver::PreventExtensions(target, should_throw);
8467 }
8468
8469 Handle<Object> trap_result;
8470 Handle<Object> args[] = {target};
8471 ASSIGN_RETURN_ON_EXCEPTION_VALUE(
8472 isolate, trap_result,
8473 Execution::Call(isolate, trap, handler, arraysize(args), args),
8474 Nothing<bool>());
8475 if (!trap_result->BooleanValue(isolate)) {
8476 RETURN_FAILURE(
8477 isolate, should_throw,
8478 NewTypeError(MessageTemplate::kProxyTrapReturnedFalsish, trap_name));
8479 }
8480
8481 // Enforce the invariant.
8482 Maybe<bool> target_result = JSReceiver::IsExtensible(target);
8483 MAYBE_RETURN(target_result, Nothing<bool>());
8484 if (target_result.FromJust()) {
8485 isolate->Throw(*factory->NewTypeError(
8486 MessageTemplate::kProxyPreventExtensionsExtensible));
8487 return Nothing<bool>();
8488 }
8489 return Just(true);
8490 }
8491
8492
PreventExtensions(Handle<JSObject> object,ShouldThrow should_throw)8493 Maybe<bool> JSObject::PreventExtensions(Handle<JSObject> object,
8494 ShouldThrow should_throw) {
8495 Isolate* isolate = object->GetIsolate();
8496
8497 if (!object->HasSloppyArgumentsElements()) {
8498 return PreventExtensionsWithTransition<NONE>(object, should_throw);
8499 }
8500
8501 if (object->IsAccessCheckNeeded() &&
8502 !isolate->MayAccess(handle(isolate->context(), isolate), object)) {
8503 isolate->ReportFailedAccessCheck(object);
8504 RETURN_VALUE_IF_SCHEDULED_EXCEPTION(isolate, Nothing<bool>());
8505 RETURN_FAILURE(isolate, should_throw,
8506 NewTypeError(MessageTemplate::kNoAccess));
8507 }
8508
8509 if (!object->map()->is_extensible()) return Just(true);
8510
8511 if (object->IsJSGlobalProxy()) {
8512 PrototypeIterator iter(isolate, object);
8513 if (iter.IsAtEnd()) return Just(true);
8514 DCHECK(PrototypeIterator::GetCurrent(iter)->IsJSGlobalObject());
8515 return PreventExtensions(PrototypeIterator::GetCurrent<JSObject>(iter),
8516 should_throw);
8517 }
8518
8519 if (object->map()->has_named_interceptor() ||
8520 object->map()->has_indexed_interceptor()) {
8521 RETURN_FAILURE(isolate, should_throw,
8522 NewTypeError(MessageTemplate::kCannotPreventExt));
8523 }
8524
8525 if (!object->HasFixedTypedArrayElements()) {
8526 // If there are fast elements we normalize.
8527 Handle<NumberDictionary> dictionary = NormalizeElements(object);
8528 DCHECK(object->HasDictionaryElements() ||
8529 object->HasSlowArgumentsElements());
8530
8531 // Make sure that we never go back to fast case.
8532 object->RequireSlowElements(*dictionary);
8533 }
8534
8535 // Do a map transition, other objects with this map may still
8536 // be extensible.
8537 // TODO(adamk): Extend the NormalizedMapCache to handle non-extensible maps.
8538 Handle<Map> new_map =
8539 Map::Copy(isolate, handle(object->map(), isolate), "PreventExtensions");
8540
8541 new_map->set_is_extensible(false);
8542 JSObject::MigrateToMap(object, new_map);
8543 DCHECK(!object->map()->is_extensible());
8544
8545 return Just(true);
8546 }
8547
8548
IsExtensible(Handle<JSReceiver> object)8549 Maybe<bool> JSReceiver::IsExtensible(Handle<JSReceiver> object) {
8550 if (object->IsJSProxy()) {
8551 return JSProxy::IsExtensible(Handle<JSProxy>::cast(object));
8552 }
8553 return Just(JSObject::IsExtensible(Handle<JSObject>::cast(object)));
8554 }
8555
8556
IsExtensible(Handle<JSProxy> proxy)8557 Maybe<bool> JSProxy::IsExtensible(Handle<JSProxy> proxy) {
8558 Isolate* isolate = proxy->GetIsolate();
8559 STACK_CHECK(isolate, Nothing<bool>());
8560 Factory* factory = isolate->factory();
8561 Handle<String> trap_name = factory->isExtensible_string();
8562
8563 if (proxy->IsRevoked()) {
8564 isolate->Throw(
8565 *factory->NewTypeError(MessageTemplate::kProxyRevoked, trap_name));
8566 return Nothing<bool>();
8567 }
8568 Handle<JSReceiver> target(JSReceiver::cast(proxy->target()), isolate);
8569 Handle<JSReceiver> handler(JSReceiver::cast(proxy->handler()), isolate);
8570
8571 Handle<Object> trap;
8572 ASSIGN_RETURN_ON_EXCEPTION_VALUE(
8573 isolate, trap, Object::GetMethod(handler, trap_name), Nothing<bool>());
8574 if (trap->IsUndefined(isolate)) {
8575 return JSReceiver::IsExtensible(target);
8576 }
8577
8578 Handle<Object> trap_result;
8579 Handle<Object> args[] = {target};
8580 ASSIGN_RETURN_ON_EXCEPTION_VALUE(
8581 isolate, trap_result,
8582 Execution::Call(isolate, trap, handler, arraysize(args), args),
8583 Nothing<bool>());
8584
8585 // Enforce the invariant.
8586 Maybe<bool> target_result = JSReceiver::IsExtensible(target);
8587 MAYBE_RETURN(target_result, Nothing<bool>());
8588 if (target_result.FromJust() != trap_result->BooleanValue(isolate)) {
8589 isolate->Throw(
8590 *factory->NewTypeError(MessageTemplate::kProxyIsExtensibleInconsistent,
8591 factory->ToBoolean(target_result.FromJust())));
8592 return Nothing<bool>();
8593 }
8594 return target_result;
8595 }
8596
8597
IsExtensible(Handle<JSObject> object)8598 bool JSObject::IsExtensible(Handle<JSObject> object) {
8599 Isolate* isolate = object->GetIsolate();
8600 if (object->IsAccessCheckNeeded() &&
8601 !isolate->MayAccess(handle(isolate->context(), isolate), object)) {
8602 return true;
8603 }
8604 if (object->IsJSGlobalProxy()) {
8605 PrototypeIterator iter(isolate, *object);
8606 if (iter.IsAtEnd()) return false;
8607 DCHECK(iter.GetCurrent()->IsJSGlobalObject());
8608 return iter.GetCurrent<JSObject>()->map()->is_extensible();
8609 }
8610 return object->map()->is_extensible();
8611 }
8612
8613 namespace {
8614
8615 template <typename Dictionary>
ApplyAttributesToDictionary(Isolate * isolate,ReadOnlyRoots roots,Handle<Dictionary> dictionary,const PropertyAttributes attributes)8616 void ApplyAttributesToDictionary(Isolate* isolate, ReadOnlyRoots roots,
8617 Handle<Dictionary> dictionary,
8618 const PropertyAttributes attributes) {
8619 int capacity = dictionary->Capacity();
8620 for (int i = 0; i < capacity; i++) {
8621 Object* k;
8622 if (!dictionary->ToKey(roots, i, &k)) continue;
8623 if (k->FilterKey(ALL_PROPERTIES)) continue;
8624 PropertyDetails details = dictionary->DetailsAt(i);
8625 int attrs = attributes;
8626 // READ_ONLY is an invalid attribute for JS setters/getters.
8627 if ((attributes & READ_ONLY) && details.kind() == kAccessor) {
8628 Object* v = dictionary->ValueAt(i);
8629 if (v->IsAccessorPair()) attrs &= ~READ_ONLY;
8630 }
8631 details = details.CopyAddAttributes(static_cast<PropertyAttributes>(attrs));
8632 dictionary->DetailsAtPut(isolate, i, details);
8633 }
8634 }
8635
8636 } // namespace
8637
8638 template <PropertyAttributes attrs>
PreventExtensionsWithTransition(Handle<JSObject> object,ShouldThrow should_throw)8639 Maybe<bool> JSObject::PreventExtensionsWithTransition(
8640 Handle<JSObject> object, ShouldThrow should_throw) {
8641 STATIC_ASSERT(attrs == NONE || attrs == SEALED || attrs == FROZEN);
8642
8643 // Sealing/freezing sloppy arguments or namespace objects should be handled
8644 // elsewhere.
8645 DCHECK(!object->HasSloppyArgumentsElements());
8646 DCHECK_IMPLIES(object->IsJSModuleNamespace(), attrs == NONE);
8647
8648 Isolate* isolate = object->GetIsolate();
8649 if (object->IsAccessCheckNeeded() &&
8650 !isolate->MayAccess(handle(isolate->context(), isolate), object)) {
8651 isolate->ReportFailedAccessCheck(object);
8652 RETURN_VALUE_IF_SCHEDULED_EXCEPTION(isolate, Nothing<bool>());
8653 RETURN_FAILURE(isolate, should_throw,
8654 NewTypeError(MessageTemplate::kNoAccess));
8655 }
8656
8657 if (attrs == NONE && !object->map()->is_extensible()) return Just(true);
8658
8659 if (object->IsJSGlobalProxy()) {
8660 PrototypeIterator iter(isolate, object);
8661 if (iter.IsAtEnd()) return Just(true);
8662 DCHECK(PrototypeIterator::GetCurrent(iter)->IsJSGlobalObject());
8663 return PreventExtensionsWithTransition<attrs>(
8664 PrototypeIterator::GetCurrent<JSObject>(iter), should_throw);
8665 }
8666
8667 if (object->map()->has_named_interceptor() ||
8668 object->map()->has_indexed_interceptor()) {
8669 MessageTemplate::Template message = MessageTemplate::kNone;
8670 switch (attrs) {
8671 case NONE:
8672 message = MessageTemplate::kCannotPreventExt;
8673 break;
8674
8675 case SEALED:
8676 message = MessageTemplate::kCannotSeal;
8677 break;
8678
8679 case FROZEN:
8680 message = MessageTemplate::kCannotFreeze;
8681 break;
8682 }
8683 RETURN_FAILURE(isolate, should_throw, NewTypeError(message));
8684 }
8685
8686 Handle<NumberDictionary> new_element_dictionary;
8687 if (!object->HasFixedTypedArrayElements() &&
8688 !object->HasDictionaryElements() &&
8689 !object->HasSlowStringWrapperElements()) {
8690 int length = object->IsJSArray()
8691 ? Smi::ToInt(Handle<JSArray>::cast(object)->length())
8692 : object->elements()->length();
8693 new_element_dictionary =
8694 length == 0 ? isolate->factory()->empty_slow_element_dictionary()
8695 : object->GetElementsAccessor()->Normalize(object);
8696 }
8697
8698 Handle<Symbol> transition_marker;
8699 if (attrs == NONE) {
8700 transition_marker = isolate->factory()->nonextensible_symbol();
8701 } else if (attrs == SEALED) {
8702 transition_marker = isolate->factory()->sealed_symbol();
8703 } else {
8704 DCHECK(attrs == FROZEN);
8705 transition_marker = isolate->factory()->frozen_symbol();
8706 }
8707
8708 Handle<Map> old_map(object->map(), isolate);
8709 TransitionsAccessor transitions(isolate, old_map);
8710 Map* transition = transitions.SearchSpecial(*transition_marker);
8711 if (transition != nullptr) {
8712 Handle<Map> transition_map(transition, isolate);
8713 DCHECK(transition_map->has_dictionary_elements() ||
8714 transition_map->has_fixed_typed_array_elements() ||
8715 transition_map->elements_kind() == SLOW_STRING_WRAPPER_ELEMENTS);
8716 DCHECK(!transition_map->is_extensible());
8717 JSObject::MigrateToMap(object, transition_map);
8718 } else if (transitions.CanHaveMoreTransitions()) {
8719 // Create a new descriptor array with the appropriate property attributes
8720 Handle<Map> new_map = Map::CopyForPreventExtensions(
8721 isolate, old_map, attrs, transition_marker, "CopyForPreventExtensions");
8722 JSObject::MigrateToMap(object, new_map);
8723 } else {
8724 DCHECK(old_map->is_dictionary_map() || !old_map->is_prototype_map());
8725 // Slow path: need to normalize properties for safety
8726 NormalizeProperties(object, CLEAR_INOBJECT_PROPERTIES, 0,
8727 "SlowPreventExtensions");
8728
8729 // Create a new map, since other objects with this map may be extensible.
8730 // TODO(adamk): Extend the NormalizedMapCache to handle non-extensible maps.
8731 Handle<Map> new_map = Map::Copy(isolate, handle(object->map(), isolate),
8732 "SlowCopyForPreventExtensions");
8733 new_map->set_is_extensible(false);
8734 if (!new_element_dictionary.is_null()) {
8735 ElementsKind new_kind =
8736 IsStringWrapperElementsKind(old_map->elements_kind())
8737 ? SLOW_STRING_WRAPPER_ELEMENTS
8738 : DICTIONARY_ELEMENTS;
8739 new_map->set_elements_kind(new_kind);
8740 }
8741 JSObject::MigrateToMap(object, new_map);
8742
8743 if (attrs != NONE) {
8744 ReadOnlyRoots roots(isolate);
8745 if (object->IsJSGlobalObject()) {
8746 Handle<GlobalDictionary> dictionary(
8747 JSGlobalObject::cast(*object)->global_dictionary(), isolate);
8748 ApplyAttributesToDictionary(isolate, roots, dictionary, attrs);
8749 } else {
8750 Handle<NameDictionary> dictionary(object->property_dictionary(),
8751 isolate);
8752 ApplyAttributesToDictionary(isolate, roots, dictionary, attrs);
8753 }
8754 }
8755 }
8756
8757 // Both seal and preventExtensions always go through without modifications to
8758 // typed array elements. Freeze works only if there are no actual elements.
8759 if (object->HasFixedTypedArrayElements()) {
8760 if (attrs == FROZEN &&
8761 JSArrayBufferView::cast(*object)->byte_length()->Number() > 0) {
8762 isolate->Throw(*isolate->factory()->NewTypeError(
8763 MessageTemplate::kCannotFreezeArrayBufferView));
8764 return Nothing<bool>();
8765 }
8766 return Just(true);
8767 }
8768
8769 DCHECK(object->map()->has_dictionary_elements() ||
8770 object->map()->elements_kind() == SLOW_STRING_WRAPPER_ELEMENTS);
8771 if (!new_element_dictionary.is_null()) {
8772 object->set_elements(*new_element_dictionary);
8773 }
8774
8775 if (object->elements() !=
8776 ReadOnlyRoots(isolate).empty_slow_element_dictionary()) {
8777 Handle<NumberDictionary> dictionary(object->element_dictionary(), isolate);
8778 // Make sure we never go back to the fast case
8779 object->RequireSlowElements(*dictionary);
8780 if (attrs != NONE) {
8781 ApplyAttributesToDictionary(isolate, ReadOnlyRoots(isolate), dictionary,
8782 attrs);
8783 }
8784 }
8785
8786 return Just(true);
8787 }
8788
8789
FastPropertyAt(Handle<JSObject> object,Representation representation,FieldIndex index)8790 Handle<Object> JSObject::FastPropertyAt(Handle<JSObject> object,
8791 Representation representation,
8792 FieldIndex index) {
8793 Isolate* isolate = object->GetIsolate();
8794 if (object->IsUnboxedDoubleField(index)) {
8795 double value = object->RawFastDoublePropertyAt(index);
8796 return isolate->factory()->NewHeapNumber(value);
8797 }
8798 Handle<Object> raw_value(object->RawFastPropertyAt(index), isolate);
8799 return Object::WrapForRead(isolate, raw_value, representation);
8800 }
8801
8802 // static
ToPrimitive(Handle<JSReceiver> receiver,ToPrimitiveHint hint)8803 MaybeHandle<Object> JSReceiver::ToPrimitive(Handle<JSReceiver> receiver,
8804 ToPrimitiveHint hint) {
8805 Isolate* const isolate = receiver->GetIsolate();
8806 Handle<Object> exotic_to_prim;
8807 ASSIGN_RETURN_ON_EXCEPTION(
8808 isolate, exotic_to_prim,
8809 GetMethod(receiver, isolate->factory()->to_primitive_symbol()), Object);
8810 if (!exotic_to_prim->IsUndefined(isolate)) {
8811 Handle<Object> hint_string =
8812 isolate->factory()->ToPrimitiveHintString(hint);
8813 Handle<Object> result;
8814 ASSIGN_RETURN_ON_EXCEPTION(
8815 isolate, result,
8816 Execution::Call(isolate, exotic_to_prim, receiver, 1, &hint_string),
8817 Object);
8818 if (result->IsPrimitive()) return result;
8819 THROW_NEW_ERROR(isolate,
8820 NewTypeError(MessageTemplate::kCannotConvertToPrimitive),
8821 Object);
8822 }
8823 return OrdinaryToPrimitive(receiver, (hint == ToPrimitiveHint::kString)
8824 ? OrdinaryToPrimitiveHint::kString
8825 : OrdinaryToPrimitiveHint::kNumber);
8826 }
8827
8828
8829 // static
OrdinaryToPrimitive(Handle<JSReceiver> receiver,OrdinaryToPrimitiveHint hint)8830 MaybeHandle<Object> JSReceiver::OrdinaryToPrimitive(
8831 Handle<JSReceiver> receiver, OrdinaryToPrimitiveHint hint) {
8832 Isolate* const isolate = receiver->GetIsolate();
8833 Handle<String> method_names[2];
8834 switch (hint) {
8835 case OrdinaryToPrimitiveHint::kNumber:
8836 method_names[0] = isolate->factory()->valueOf_string();
8837 method_names[1] = isolate->factory()->toString_string();
8838 break;
8839 case OrdinaryToPrimitiveHint::kString:
8840 method_names[0] = isolate->factory()->toString_string();
8841 method_names[1] = isolate->factory()->valueOf_string();
8842 break;
8843 }
8844 for (Handle<String> name : method_names) {
8845 Handle<Object> method;
8846 ASSIGN_RETURN_ON_EXCEPTION(isolate, method,
8847 JSReceiver::GetProperty(isolate, receiver, name),
8848 Object);
8849 if (method->IsCallable()) {
8850 Handle<Object> result;
8851 ASSIGN_RETURN_ON_EXCEPTION(
8852 isolate, result,
8853 Execution::Call(isolate, method, receiver, 0, nullptr), Object);
8854 if (result->IsPrimitive()) return result;
8855 }
8856 }
8857 THROW_NEW_ERROR(isolate,
8858 NewTypeError(MessageTemplate::kCannotConvertToPrimitive),
8859 Object);
8860 }
8861
8862
8863 // TODO(cbruni/jkummerow): Consider moving this into elements.cc.
HasEnumerableElements()8864 bool JSObject::HasEnumerableElements() {
8865 // TODO(cbruni): cleanup
8866 JSObject* object = this;
8867 switch (object->GetElementsKind()) {
8868 case PACKED_SMI_ELEMENTS:
8869 case PACKED_ELEMENTS:
8870 case PACKED_DOUBLE_ELEMENTS: {
8871 int length = object->IsJSArray()
8872 ? Smi::ToInt(JSArray::cast(object)->length())
8873 : object->elements()->length();
8874 return length > 0;
8875 }
8876 case HOLEY_SMI_ELEMENTS:
8877 case HOLEY_ELEMENTS: {
8878 FixedArray* elements = FixedArray::cast(object->elements());
8879 int length = object->IsJSArray()
8880 ? Smi::ToInt(JSArray::cast(object)->length())
8881 : elements->length();
8882 Isolate* isolate = GetIsolate();
8883 for (int i = 0; i < length; i++) {
8884 if (!elements->is_the_hole(isolate, i)) return true;
8885 }
8886 return false;
8887 }
8888 case HOLEY_DOUBLE_ELEMENTS: {
8889 int length = object->IsJSArray()
8890 ? Smi::ToInt(JSArray::cast(object)->length())
8891 : object->elements()->length();
8892 // Zero-length arrays would use the empty FixedArray...
8893 if (length == 0) return false;
8894 // ...so only cast to FixedDoubleArray otherwise.
8895 FixedDoubleArray* elements = FixedDoubleArray::cast(object->elements());
8896 for (int i = 0; i < length; i++) {
8897 if (!elements->is_the_hole(i)) return true;
8898 }
8899 return false;
8900 }
8901 #define TYPED_ARRAY_CASE(Type, type, TYPE, ctype) case TYPE##_ELEMENTS:
8902
8903 TYPED_ARRAYS(TYPED_ARRAY_CASE)
8904 #undef TYPED_ARRAY_CASE
8905 {
8906 int length = object->elements()->length();
8907 return length > 0;
8908 }
8909 case DICTIONARY_ELEMENTS: {
8910 NumberDictionary* elements = NumberDictionary::cast(object->elements());
8911 return elements->NumberOfEnumerableProperties() > 0;
8912 }
8913 case FAST_SLOPPY_ARGUMENTS_ELEMENTS:
8914 case SLOW_SLOPPY_ARGUMENTS_ELEMENTS:
8915 // We're approximating non-empty arguments objects here.
8916 return true;
8917 case FAST_STRING_WRAPPER_ELEMENTS:
8918 case SLOW_STRING_WRAPPER_ELEMENTS:
8919 if (String::cast(JSValue::cast(object)->value())->length() > 0) {
8920 return true;
8921 }
8922 return object->elements()->length() > 0;
8923 case NO_ELEMENTS:
8924 return false;
8925 }
8926 UNREACHABLE();
8927 }
8928
NumberOfEnumerableProperties() const8929 int Map::NumberOfEnumerableProperties() const {
8930 int result = 0;
8931 DescriptorArray* descs = instance_descriptors();
8932 int limit = NumberOfOwnDescriptors();
8933 for (int i = 0; i < limit; i++) {
8934 if ((descs->GetDetails(i).attributes() & ONLY_ENUMERABLE) == 0 &&
8935 !descs->GetKey(i)->FilterKey(ENUMERABLE_STRINGS)) {
8936 result++;
8937 }
8938 }
8939 return result;
8940 }
8941
NextFreePropertyIndex() const8942 int Map::NextFreePropertyIndex() const {
8943 int free_index = 0;
8944 int number_of_own_descriptors = NumberOfOwnDescriptors();
8945 DescriptorArray* descs = instance_descriptors();
8946 for (int i = 0; i < number_of_own_descriptors; i++) {
8947 PropertyDetails details = descs->GetDetails(i);
8948 if (details.location() == kField) {
8949 int candidate = details.field_index() + details.field_width_in_words();
8950 if (candidate > free_index) free_index = candidate;
8951 }
8952 }
8953 return free_index;
8954 }
8955
OnlyHasSimpleProperties() const8956 bool Map::OnlyHasSimpleProperties() const {
8957 // Wrapped string elements aren't explicitly stored in the elements backing
8958 // store, but are loaded indirectly from the underlying string.
8959 return !IsStringWrapperElementsKind(elements_kind()) &&
8960 !IsSpecialReceiverMap() && !has_hidden_prototype() &&
8961 !is_dictionary_map();
8962 }
8963
FastGetOwnValuesOrEntries(Isolate * isolate,Handle<JSReceiver> receiver,bool get_entries,Handle<FixedArray> * result)8964 V8_WARN_UNUSED_RESULT Maybe<bool> FastGetOwnValuesOrEntries(
8965 Isolate* isolate, Handle<JSReceiver> receiver, bool get_entries,
8966 Handle<FixedArray>* result) {
8967 Handle<Map> map(JSReceiver::cast(*receiver)->map(), isolate);
8968
8969 if (!map->IsJSObjectMap()) return Just(false);
8970 if (!map->OnlyHasSimpleProperties()) return Just(false);
8971
8972 Handle<JSObject> object(JSObject::cast(*receiver), isolate);
8973
8974 Handle<DescriptorArray> descriptors(map->instance_descriptors(), isolate);
8975 int number_of_own_descriptors = map->NumberOfOwnDescriptors();
8976 int number_of_own_elements =
8977 object->GetElementsAccessor()->GetCapacity(*object, object->elements());
8978 Handle<FixedArray> values_or_entries = isolate->factory()->NewFixedArray(
8979 number_of_own_descriptors + number_of_own_elements);
8980 int count = 0;
8981
8982 if (object->elements() != ReadOnlyRoots(isolate).empty_fixed_array()) {
8983 MAYBE_RETURN(object->GetElementsAccessor()->CollectValuesOrEntries(
8984 isolate, object, values_or_entries, get_entries, &count,
8985 ENUMERABLE_STRINGS),
8986 Nothing<bool>());
8987 }
8988
8989 bool stable = object->map() == *map;
8990
8991 for (int index = 0; index < number_of_own_descriptors; index++) {
8992 Handle<Name> next_key(descriptors->GetKey(index), isolate);
8993 if (!next_key->IsString()) continue;
8994 Handle<Object> prop_value;
8995
8996 // Directly decode from the descriptor array if |from| did not change shape.
8997 if (stable) {
8998 PropertyDetails details = descriptors->GetDetails(index);
8999 if (!details.IsEnumerable()) continue;
9000 if (details.kind() == kData) {
9001 if (details.location() == kDescriptor) {
9002 prop_value = handle(descriptors->GetStrongValue(index), isolate);
9003 } else {
9004 Representation representation = details.representation();
9005 FieldIndex field_index = FieldIndex::ForDescriptor(*map, index);
9006 prop_value =
9007 JSObject::FastPropertyAt(object, representation, field_index);
9008 }
9009 } else {
9010 ASSIGN_RETURN_ON_EXCEPTION_VALUE(
9011 isolate, prop_value,
9012 JSReceiver::GetProperty(isolate, object, next_key),
9013 Nothing<bool>());
9014 stable = object->map() == *map;
9015 }
9016 } else {
9017 // If the map did change, do a slower lookup. We are still guaranteed that
9018 // the object has a simple shape, and that the key is a name.
9019 LookupIterator it(isolate, object, next_key,
9020 LookupIterator::OWN_SKIP_INTERCEPTOR);
9021 if (!it.IsFound()) continue;
9022 DCHECK(it.state() == LookupIterator::DATA ||
9023 it.state() == LookupIterator::ACCESSOR);
9024 if (!it.IsEnumerable()) continue;
9025 ASSIGN_RETURN_ON_EXCEPTION_VALUE(
9026 isolate, prop_value, Object::GetProperty(&it), Nothing<bool>());
9027 }
9028
9029 if (get_entries) {
9030 prop_value = MakeEntryPair(isolate, next_key, prop_value);
9031 }
9032
9033 values_or_entries->set(count, *prop_value);
9034 count++;
9035 }
9036
9037 DCHECK_LE(count, values_or_entries->length());
9038 *result = FixedArray::ShrinkOrEmpty(isolate, values_or_entries, count);
9039 return Just(true);
9040 }
9041
GetOwnValuesOrEntries(Isolate * isolate,Handle<JSReceiver> object,PropertyFilter filter,bool try_fast_path,bool get_entries)9042 MaybeHandle<FixedArray> GetOwnValuesOrEntries(Isolate* isolate,
9043 Handle<JSReceiver> object,
9044 PropertyFilter filter,
9045 bool try_fast_path,
9046 bool get_entries) {
9047 Handle<FixedArray> values_or_entries;
9048 if (try_fast_path && filter == ENUMERABLE_STRINGS) {
9049 Maybe<bool> fast_values_or_entries = FastGetOwnValuesOrEntries(
9050 isolate, object, get_entries, &values_or_entries);
9051 if (fast_values_or_entries.IsNothing()) return MaybeHandle<FixedArray>();
9052 if (fast_values_or_entries.FromJust()) return values_or_entries;
9053 }
9054
9055 PropertyFilter key_filter =
9056 static_cast<PropertyFilter>(filter & ~ONLY_ENUMERABLE);
9057
9058 Handle<FixedArray> keys;
9059 ASSIGN_RETURN_ON_EXCEPTION_VALUE(
9060 isolate, keys,
9061 KeyAccumulator::GetKeys(object, KeyCollectionMode::kOwnOnly, key_filter,
9062 GetKeysConversion::kConvertToString),
9063 MaybeHandle<FixedArray>());
9064
9065 values_or_entries = isolate->factory()->NewFixedArray(keys->length());
9066 int length = 0;
9067
9068 for (int i = 0; i < keys->length(); ++i) {
9069 Handle<Name> key = Handle<Name>::cast(handle(keys->get(i), isolate));
9070
9071 if (filter & ONLY_ENUMERABLE) {
9072 PropertyDescriptor descriptor;
9073 Maybe<bool> did_get_descriptor = JSReceiver::GetOwnPropertyDescriptor(
9074 isolate, object, key, &descriptor);
9075 MAYBE_RETURN(did_get_descriptor, MaybeHandle<FixedArray>());
9076 if (!did_get_descriptor.FromJust() || !descriptor.enumerable()) continue;
9077 }
9078
9079 Handle<Object> value;
9080 ASSIGN_RETURN_ON_EXCEPTION_VALUE(
9081 isolate, value, JSReceiver::GetPropertyOrElement(isolate, object, key),
9082 MaybeHandle<FixedArray>());
9083
9084 if (get_entries) {
9085 Handle<FixedArray> entry_storage =
9086 isolate->factory()->NewUninitializedFixedArray(2);
9087 entry_storage->set(0, *key);
9088 entry_storage->set(1, *value);
9089 value = isolate->factory()->NewJSArrayWithElements(entry_storage,
9090 PACKED_ELEMENTS, 2);
9091 }
9092
9093 values_or_entries->set(length, *value);
9094 length++;
9095 }
9096 DCHECK_LE(length, values_or_entries->length());
9097 return FixedArray::ShrinkOrEmpty(isolate, values_or_entries, length);
9098 }
9099
GetOwnValues(Handle<JSReceiver> object,PropertyFilter filter,bool try_fast_path)9100 MaybeHandle<FixedArray> JSReceiver::GetOwnValues(Handle<JSReceiver> object,
9101 PropertyFilter filter,
9102 bool try_fast_path) {
9103 return GetOwnValuesOrEntries(object->GetIsolate(), object, filter,
9104 try_fast_path, false);
9105 }
9106
GetOwnEntries(Handle<JSReceiver> object,PropertyFilter filter,bool try_fast_path)9107 MaybeHandle<FixedArray> JSReceiver::GetOwnEntries(Handle<JSReceiver> object,
9108 PropertyFilter filter,
9109 bool try_fast_path) {
9110 return GetOwnValuesOrEntries(object->GetIsolate(), object, filter,
9111 try_fast_path, true);
9112 }
9113
GetOwnElementIndices(Isolate * isolate,Handle<JSReceiver> receiver,Handle<JSObject> object)9114 Handle<FixedArray> JSReceiver::GetOwnElementIndices(Isolate* isolate,
9115 Handle<JSReceiver> receiver,
9116 Handle<JSObject> object) {
9117 KeyAccumulator accumulator(isolate, KeyCollectionMode::kOwnOnly,
9118 ALL_PROPERTIES);
9119 accumulator.CollectOwnElementIndices(receiver, object);
9120 Handle<FixedArray> keys =
9121 accumulator.GetKeys(GetKeysConversion::kKeepNumbers);
9122 DCHECK(keys->ContainsSortedNumbers());
9123 return keys;
9124 }
9125
DictionaryElementsInPrototypeChainOnly(Isolate * isolate)9126 bool Map::DictionaryElementsInPrototypeChainOnly(Isolate* isolate) {
9127 if (IsDictionaryElementsKind(elements_kind())) {
9128 return false;
9129 }
9130
9131 for (PrototypeIterator iter(isolate, this); !iter.IsAtEnd(); iter.Advance()) {
9132 // Be conservative, don't walk into proxies.
9133 if (iter.GetCurrent()->IsJSProxy()) return true;
9134 // String wrappers have non-configurable, non-writable elements.
9135 if (iter.GetCurrent()->IsStringWrapper()) return true;
9136 JSObject* current = iter.GetCurrent<JSObject>();
9137
9138 if (current->HasDictionaryElements() &&
9139 current->element_dictionary()->requires_slow_elements()) {
9140 return true;
9141 }
9142
9143 if (current->HasSlowArgumentsElements()) {
9144 FixedArray* parameter_map = FixedArray::cast(current->elements());
9145 Object* arguments = parameter_map->get(1);
9146 if (NumberDictionary::cast(arguments)->requires_slow_elements()) {
9147 return true;
9148 }
9149 }
9150 }
9151
9152 return false;
9153 }
9154
9155
DefineAccessor(Handle<JSObject> object,Handle<Name> name,Handle<Object> getter,Handle<Object> setter,PropertyAttributes attributes)9156 MaybeHandle<Object> JSObject::DefineAccessor(Handle<JSObject> object,
9157 Handle<Name> name,
9158 Handle<Object> getter,
9159 Handle<Object> setter,
9160 PropertyAttributes attributes) {
9161 Isolate* isolate = object->GetIsolate();
9162
9163 LookupIterator it = LookupIterator::PropertyOrElement(
9164 isolate, object, name, LookupIterator::OWN_SKIP_INTERCEPTOR);
9165 return DefineAccessor(&it, getter, setter, attributes);
9166 }
9167
9168
DefineAccessor(LookupIterator * it,Handle<Object> getter,Handle<Object> setter,PropertyAttributes attributes)9169 MaybeHandle<Object> JSObject::DefineAccessor(LookupIterator* it,
9170 Handle<Object> getter,
9171 Handle<Object> setter,
9172 PropertyAttributes attributes) {
9173 Isolate* isolate = it->isolate();
9174
9175 it->UpdateProtector();
9176
9177 if (it->state() == LookupIterator::ACCESS_CHECK) {
9178 if (!it->HasAccess()) {
9179 isolate->ReportFailedAccessCheck(it->GetHolder<JSObject>());
9180 RETURN_EXCEPTION_IF_SCHEDULED_EXCEPTION(isolate, Object);
9181 return isolate->factory()->undefined_value();
9182 }
9183 it->Next();
9184 }
9185
9186 Handle<JSObject> object = Handle<JSObject>::cast(it->GetReceiver());
9187 // Ignore accessors on typed arrays.
9188 if (it->IsElement() && object->HasFixedTypedArrayElements()) {
9189 return it->factory()->undefined_value();
9190 }
9191
9192 DCHECK(getter->IsCallable() || getter->IsUndefined(isolate) ||
9193 getter->IsNull(isolate) || getter->IsFunctionTemplateInfo());
9194 DCHECK(setter->IsCallable() || setter->IsUndefined(isolate) ||
9195 setter->IsNull(isolate) || setter->IsFunctionTemplateInfo());
9196 it->TransitionToAccessorProperty(getter, setter, attributes);
9197
9198 return isolate->factory()->undefined_value();
9199 }
9200
SetAccessor(Handle<JSObject> object,Handle<Name> name,Handle<AccessorInfo> info,PropertyAttributes attributes)9201 MaybeHandle<Object> JSObject::SetAccessor(Handle<JSObject> object,
9202 Handle<Name> name,
9203 Handle<AccessorInfo> info,
9204 PropertyAttributes attributes) {
9205 Isolate* isolate = object->GetIsolate();
9206
9207 LookupIterator it = LookupIterator::PropertyOrElement(
9208 isolate, object, name, LookupIterator::OWN_SKIP_INTERCEPTOR);
9209
9210 // Duplicate ACCESS_CHECK outside of GetPropertyAttributes for the case that
9211 // the FailedAccessCheckCallbackFunction doesn't throw an exception.
9212 //
9213 // TODO(verwaest): Force throw an exception if the callback doesn't, so we can
9214 // remove reliance on default return values.
9215 if (it.state() == LookupIterator::ACCESS_CHECK) {
9216 if (!it.HasAccess()) {
9217 isolate->ReportFailedAccessCheck(object);
9218 RETURN_EXCEPTION_IF_SCHEDULED_EXCEPTION(isolate, Object);
9219 return it.factory()->undefined_value();
9220 }
9221 it.Next();
9222 }
9223
9224 // Ignore accessors on typed arrays.
9225 if (it.IsElement() && object->HasFixedTypedArrayElements()) {
9226 return it.factory()->undefined_value();
9227 }
9228
9229 CHECK(GetPropertyAttributes(&it).IsJust());
9230
9231 // ES5 forbids turning a property into an accessor if it's not
9232 // configurable. See 8.6.1 (Table 5).
9233 if (it.IsFound() && !it.IsConfigurable()) {
9234 return it.factory()->undefined_value();
9235 }
9236
9237 it.TransitionToAccessorPair(info, attributes);
9238
9239 return object;
9240 }
9241
SlowReverseLookup(Object * value)9242 Object* JSObject::SlowReverseLookup(Object* value) {
9243 if (HasFastProperties()) {
9244 int number_of_own_descriptors = map()->NumberOfOwnDescriptors();
9245 DescriptorArray* descs = map()->instance_descriptors();
9246 bool value_is_number = value->IsNumber();
9247 for (int i = 0; i < number_of_own_descriptors; i++) {
9248 PropertyDetails details = descs->GetDetails(i);
9249 if (details.location() == kField) {
9250 DCHECK_EQ(kData, details.kind());
9251 FieldIndex field_index = FieldIndex::ForDescriptor(map(), i);
9252 if (IsUnboxedDoubleField(field_index)) {
9253 if (value_is_number) {
9254 double property = RawFastDoublePropertyAt(field_index);
9255 if (property == value->Number()) {
9256 return descs->GetKey(i);
9257 }
9258 }
9259 } else {
9260 Object* property = RawFastPropertyAt(field_index);
9261 if (field_index.is_double()) {
9262 DCHECK(property->IsMutableHeapNumber());
9263 if (value_is_number && property->Number() == value->Number()) {
9264 return descs->GetKey(i);
9265 }
9266 } else if (property == value) {
9267 return descs->GetKey(i);
9268 }
9269 }
9270 } else {
9271 DCHECK_EQ(kDescriptor, details.location());
9272 if (details.kind() == kData) {
9273 if (descs->GetStrongValue(i) == value) {
9274 return descs->GetKey(i);
9275 }
9276 }
9277 }
9278 }
9279 return GetReadOnlyRoots().undefined_value();
9280 } else if (IsJSGlobalObject()) {
9281 return JSGlobalObject::cast(this)->global_dictionary()->SlowReverseLookup(
9282 value);
9283 } else {
9284 return property_dictionary()->SlowReverseLookup(value);
9285 }
9286 }
9287
RawCopy(Isolate * isolate,Handle<Map> map,int instance_size,int inobject_properties)9288 Handle<Map> Map::RawCopy(Isolate* isolate, Handle<Map> map, int instance_size,
9289 int inobject_properties) {
9290 Handle<Map> result = isolate->factory()->NewMap(
9291 map->instance_type(), instance_size, TERMINAL_FAST_ELEMENTS_KIND,
9292 inobject_properties);
9293 Handle<Object> prototype(map->prototype(), isolate);
9294 Map::SetPrototype(isolate, result, prototype);
9295 result->set_constructor_or_backpointer(map->GetConstructor());
9296 result->set_bit_field(map->bit_field());
9297 result->set_bit_field2(map->bit_field2());
9298 int new_bit_field3 = map->bit_field3();
9299 new_bit_field3 = OwnsDescriptorsBit::update(new_bit_field3, true);
9300 new_bit_field3 = NumberOfOwnDescriptorsBits::update(new_bit_field3, 0);
9301 new_bit_field3 = EnumLengthBits::update(new_bit_field3,
9302 kInvalidEnumCacheSentinel);
9303 new_bit_field3 = IsDeprecatedBit::update(new_bit_field3, false);
9304 if (!map->is_dictionary_map()) {
9305 new_bit_field3 = IsUnstableBit::update(new_bit_field3, false);
9306 }
9307 result->set_bit_field3(new_bit_field3);
9308 return result;
9309 }
9310
Normalize(Isolate * isolate,Handle<Map> fast_map,PropertyNormalizationMode mode,const char * reason)9311 Handle<Map> Map::Normalize(Isolate* isolate, Handle<Map> fast_map,
9312 PropertyNormalizationMode mode, const char* reason) {
9313 DCHECK(!fast_map->is_dictionary_map());
9314
9315 Handle<Object> maybe_cache(isolate->native_context()->normalized_map_cache(),
9316 isolate);
9317 bool use_cache =
9318 !fast_map->is_prototype_map() && !maybe_cache->IsUndefined(isolate);
9319 Handle<NormalizedMapCache> cache;
9320 if (use_cache) cache = Handle<NormalizedMapCache>::cast(maybe_cache);
9321
9322 Handle<Map> new_map;
9323 if (use_cache && cache->Get(fast_map, mode).ToHandle(&new_map)) {
9324 #ifdef VERIFY_HEAP
9325 if (FLAG_verify_heap) new_map->DictionaryMapVerify(isolate);
9326 #endif
9327 #ifdef ENABLE_SLOW_DCHECKS
9328 if (FLAG_enable_slow_asserts) {
9329 // The cached map should match newly created normalized map bit-by-bit,
9330 // except for the code cache, which can contain some ICs which can be
9331 // applied to the shared map, dependent code and weak cell cache.
9332 Handle<Map> fresh = Map::CopyNormalized(isolate, fast_map, mode);
9333
9334 if (new_map->is_prototype_map()) {
9335 // For prototype maps, the PrototypeInfo is not copied.
9336 DCHECK_EQ(0, memcmp(reinterpret_cast<void*>(fresh->address()),
9337 reinterpret_cast<void*>(new_map->address()),
9338 kTransitionsOrPrototypeInfoOffset));
9339 DCHECK_EQ(fresh->raw_transitions(),
9340 MaybeObject::FromObject(Smi::kZero));
9341 STATIC_ASSERT(kDescriptorsOffset ==
9342 kTransitionsOrPrototypeInfoOffset + kPointerSize);
9343 DCHECK_EQ(0, memcmp(HeapObject::RawField(*fresh, kDescriptorsOffset),
9344 HeapObject::RawField(*new_map, kDescriptorsOffset),
9345 kDependentCodeOffset - kDescriptorsOffset));
9346 } else {
9347 DCHECK_EQ(0, memcmp(reinterpret_cast<void*>(fresh->address()),
9348 reinterpret_cast<void*>(new_map->address()),
9349 Map::kDependentCodeOffset));
9350 }
9351 STATIC_ASSERT(Map::kPrototypeValidityCellOffset ==
9352 Map::kDependentCodeOffset + kPointerSize);
9353 int offset = Map::kPrototypeValidityCellOffset + kPointerSize;
9354 DCHECK_EQ(0, memcmp(reinterpret_cast<void*>(fresh->address() + offset),
9355 reinterpret_cast<void*>(new_map->address() + offset),
9356 Map::kSize - offset));
9357 }
9358 #endif
9359 } else {
9360 new_map = Map::CopyNormalized(isolate, fast_map, mode);
9361 if (use_cache) {
9362 cache->Set(fast_map, new_map);
9363 isolate->counters()->maps_normalized()->Increment();
9364 }
9365 if (FLAG_trace_maps) {
9366 LOG(isolate, MapEvent("Normalize", *fast_map, *new_map, reason));
9367 }
9368 }
9369 fast_map->NotifyLeafMapLayoutChange(isolate);
9370 return new_map;
9371 }
9372
CopyNormalized(Isolate * isolate,Handle<Map> map,PropertyNormalizationMode mode)9373 Handle<Map> Map::CopyNormalized(Isolate* isolate, Handle<Map> map,
9374 PropertyNormalizationMode mode) {
9375 int new_instance_size = map->instance_size();
9376 if (mode == CLEAR_INOBJECT_PROPERTIES) {
9377 new_instance_size -= map->GetInObjectProperties() * kPointerSize;
9378 }
9379
9380 Handle<Map> result = RawCopy(
9381 isolate, map, new_instance_size,
9382 mode == CLEAR_INOBJECT_PROPERTIES ? 0 : map->GetInObjectProperties());
9383 // Clear the unused_property_fields explicitly as this field should not
9384 // be accessed for normalized maps.
9385 result->SetInObjectUnusedPropertyFields(0);
9386 result->set_is_dictionary_map(true);
9387 result->set_is_migration_target(false);
9388 result->set_may_have_interesting_symbols(true);
9389 result->set_construction_counter(kNoSlackTracking);
9390
9391 #ifdef VERIFY_HEAP
9392 if (FLAG_verify_heap) result->DictionaryMapVerify(isolate);
9393 #endif
9394
9395 return result;
9396 }
9397
9398 // Return an immutable prototype exotic object version of the input map.
9399 // Never even try to cache it in the transition tree, as it is intended
9400 // for the global object and its prototype chain, and excluding it saves
9401 // memory on the map transition tree.
9402
9403 // static
TransitionToImmutableProto(Isolate * isolate,Handle<Map> map)9404 Handle<Map> Map::TransitionToImmutableProto(Isolate* isolate, Handle<Map> map) {
9405 Handle<Map> new_map = Map::Copy(isolate, map, "ImmutablePrototype");
9406 new_map->set_is_immutable_proto(true);
9407 return new_map;
9408 }
9409
9410 namespace {
EnsureInitialMap(Isolate * isolate,Handle<Map> map)9411 void EnsureInitialMap(Isolate* isolate, Handle<Map> map) {
9412 #ifdef DEBUG
9413 // Strict function maps have Function as a constructor but the
9414 // Function's initial map is a sloppy function map. Same holds for
9415 // GeneratorFunction / AsyncFunction and its initial map.
9416 Object* constructor = map->GetConstructor();
9417 DCHECK(constructor->IsJSFunction());
9418 DCHECK(*map == JSFunction::cast(constructor)->initial_map() ||
9419 *map == *isolate->strict_function_map() ||
9420 *map == *isolate->strict_function_with_name_map() ||
9421 *map == *isolate->generator_function_map() ||
9422 *map == *isolate->generator_function_with_name_map() ||
9423 *map == *isolate->generator_function_with_home_object_map() ||
9424 *map == *isolate->generator_function_with_name_and_home_object_map() ||
9425 *map == *isolate->async_function_map() ||
9426 *map == *isolate->async_function_with_name_map() ||
9427 *map == *isolate->async_function_with_home_object_map() ||
9428 *map == *isolate->async_function_with_name_and_home_object_map());
9429 #endif
9430 // Initial maps must always own their descriptors and it's descriptor array
9431 // does not contain descriptors that do not belong to the map.
9432 DCHECK(map->owns_descriptors());
9433 DCHECK_EQ(map->NumberOfOwnDescriptors(),
9434 map->instance_descriptors()->number_of_descriptors());
9435 }
9436 } // namespace
9437
9438 // static
CopyInitialMapNormalized(Isolate * isolate,Handle<Map> map,PropertyNormalizationMode mode)9439 Handle<Map> Map::CopyInitialMapNormalized(Isolate* isolate, Handle<Map> map,
9440 PropertyNormalizationMode mode) {
9441 EnsureInitialMap(isolate, map);
9442 return CopyNormalized(isolate, map, mode);
9443 }
9444
9445 // static
CopyInitialMap(Isolate * isolate,Handle<Map> map,int instance_size,int inobject_properties,int unused_property_fields)9446 Handle<Map> Map::CopyInitialMap(Isolate* isolate, Handle<Map> map,
9447 int instance_size, int inobject_properties,
9448 int unused_property_fields) {
9449 EnsureInitialMap(isolate, map);
9450 Handle<Map> result =
9451 RawCopy(isolate, map, instance_size, inobject_properties);
9452
9453 // Please note instance_type and instance_size are set when allocated.
9454 result->SetInObjectUnusedPropertyFields(unused_property_fields);
9455
9456 int number_of_own_descriptors = map->NumberOfOwnDescriptors();
9457 if (number_of_own_descriptors > 0) {
9458 // The copy will use the same descriptors array.
9459 result->UpdateDescriptors(map->instance_descriptors(),
9460 map->GetLayoutDescriptor());
9461 result->SetNumberOfOwnDescriptors(number_of_own_descriptors);
9462
9463 DCHECK_EQ(result->NumberOfFields(),
9464 result->GetInObjectProperties() - result->UnusedPropertyFields());
9465 }
9466
9467 return result;
9468 }
9469
CopyDropDescriptors(Isolate * isolate,Handle<Map> map)9470 Handle<Map> Map::CopyDropDescriptors(Isolate* isolate, Handle<Map> map) {
9471 Handle<Map> result =
9472 RawCopy(isolate, map, map->instance_size(),
9473 map->IsJSObjectMap() ? map->GetInObjectProperties() : 0);
9474
9475 // Please note instance_type and instance_size are set when allocated.
9476 if (map->IsJSObjectMap()) {
9477 result->CopyUnusedPropertyFields(*map);
9478 }
9479 map->NotifyLeafMapLayoutChange(isolate);
9480 return result;
9481 }
9482
ShareDescriptor(Isolate * isolate,Handle<Map> map,Handle<DescriptorArray> descriptors,Descriptor * descriptor)9483 Handle<Map> Map::ShareDescriptor(Isolate* isolate, Handle<Map> map,
9484 Handle<DescriptorArray> descriptors,
9485 Descriptor* descriptor) {
9486 // Sanity check. This path is only to be taken if the map owns its descriptor
9487 // array, implying that its NumberOfOwnDescriptors equals the number of
9488 // descriptors in the descriptor array.
9489 DCHECK_EQ(map->NumberOfOwnDescriptors(),
9490 map->instance_descriptors()->number_of_descriptors());
9491
9492 Handle<Map> result = CopyDropDescriptors(isolate, map);
9493 Handle<Name> name = descriptor->GetKey();
9494
9495 // Properly mark the {result} if the {name} is an "interesting symbol".
9496 if (name->IsInterestingSymbol()) {
9497 result->set_may_have_interesting_symbols(true);
9498 }
9499
9500 // Ensure there's space for the new descriptor in the shared descriptor array.
9501 if (descriptors->NumberOfSlackDescriptors() == 0) {
9502 int old_size = descriptors->number_of_descriptors();
9503 if (old_size == 0) {
9504 descriptors = DescriptorArray::Allocate(isolate, 0, 1);
9505 } else {
9506 int slack = SlackForArraySize(old_size, kMaxNumberOfDescriptors);
9507 EnsureDescriptorSlack(isolate, map, slack);
9508 descriptors = handle(map->instance_descriptors(), isolate);
9509 }
9510 }
9511
9512 Handle<LayoutDescriptor> layout_descriptor =
9513 FLAG_unbox_double_fields
9514 ? LayoutDescriptor::ShareAppend(isolate, map,
9515 descriptor->GetDetails())
9516 : handle(LayoutDescriptor::FastPointerLayout(), isolate);
9517
9518 {
9519 DisallowHeapAllocation no_gc;
9520 descriptors->Append(descriptor);
9521 result->InitializeDescriptors(*descriptors, *layout_descriptor);
9522 }
9523
9524 DCHECK(result->NumberOfOwnDescriptors() == map->NumberOfOwnDescriptors() + 1);
9525 ConnectTransition(isolate, map, result, name, SIMPLE_PROPERTY_TRANSITION);
9526
9527 return result;
9528 }
9529
ConnectTransition(Isolate * isolate,Handle<Map> parent,Handle<Map> child,Handle<Name> name,SimpleTransitionFlag flag)9530 void Map::ConnectTransition(Isolate* isolate, Handle<Map> parent,
9531 Handle<Map> child, Handle<Name> name,
9532 SimpleTransitionFlag flag) {
9533 DCHECK_IMPLIES(name->IsInterestingSymbol(),
9534 child->may_have_interesting_symbols());
9535 DCHECK_IMPLIES(parent->may_have_interesting_symbols(),
9536 child->may_have_interesting_symbols());
9537 // Do not track transitions during bootstrap except for element transitions.
9538 if (isolate->bootstrapper()->IsActive() &&
9539 !name.is_identical_to(isolate->factory()->elements_transition_symbol())) {
9540 if (FLAG_trace_maps) {
9541 LOG(isolate,
9542 MapEvent("Transition", *parent, *child,
9543 child->is_prototype_map() ? "prototype" : "", *name));
9544 }
9545 return;
9546 }
9547 if (!parent->GetBackPointer()->IsUndefined(isolate)) {
9548 parent->set_owns_descriptors(false);
9549 } else {
9550 // |parent| is initial map and it must keep the ownership, there must be no
9551 // descriptors in the descriptors array that do not belong to the map.
9552 DCHECK(parent->owns_descriptors());
9553 DCHECK_EQ(parent->NumberOfOwnDescriptors(),
9554 parent->instance_descriptors()->number_of_descriptors());
9555 }
9556 if (parent->is_prototype_map()) {
9557 DCHECK(child->is_prototype_map());
9558 if (FLAG_trace_maps) {
9559 LOG(isolate, MapEvent("Transition", *parent, *child, "prototype", *name));
9560 }
9561 } else {
9562 TransitionsAccessor(isolate, parent).Insert(name, child, flag);
9563 if (FLAG_trace_maps) {
9564 LOG(isolate, MapEvent("Transition", *parent, *child, "", *name));
9565 }
9566 }
9567 }
9568
CopyReplaceDescriptors(Isolate * isolate,Handle<Map> map,Handle<DescriptorArray> descriptors,Handle<LayoutDescriptor> layout_descriptor,TransitionFlag flag,MaybeHandle<Name> maybe_name,const char * reason,SimpleTransitionFlag simple_flag)9569 Handle<Map> Map::CopyReplaceDescriptors(
9570 Isolate* isolate, Handle<Map> map, Handle<DescriptorArray> descriptors,
9571 Handle<LayoutDescriptor> layout_descriptor, TransitionFlag flag,
9572 MaybeHandle<Name> maybe_name, const char* reason,
9573 SimpleTransitionFlag simple_flag) {
9574 DCHECK(descriptors->IsSortedNoDuplicates());
9575
9576 Handle<Map> result = CopyDropDescriptors(isolate, map);
9577
9578 // Properly mark the {result} if the {name} is an "interesting symbol".
9579 Handle<Name> name;
9580 if (maybe_name.ToHandle(&name) && name->IsInterestingSymbol()) {
9581 result->set_may_have_interesting_symbols(true);
9582 }
9583
9584 if (!map->is_prototype_map()) {
9585 if (flag == INSERT_TRANSITION &&
9586 TransitionsAccessor(isolate, map).CanHaveMoreTransitions()) {
9587 result->InitializeDescriptors(*descriptors, *layout_descriptor);
9588
9589 DCHECK(!maybe_name.is_null());
9590 ConnectTransition(isolate, map, result, name, simple_flag);
9591 } else {
9592 descriptors->GeneralizeAllFields();
9593 result->InitializeDescriptors(*descriptors,
9594 LayoutDescriptor::FastPointerLayout());
9595 }
9596 } else {
9597 result->InitializeDescriptors(*descriptors, *layout_descriptor);
9598 }
9599 if (FLAG_trace_maps &&
9600 // Mirror conditions above that did not call ConnectTransition().
9601 (map->is_prototype_map() ||
9602 !(flag == INSERT_TRANSITION &&
9603 TransitionsAccessor(isolate, map).CanHaveMoreTransitions()))) {
9604 LOG(isolate, MapEvent("ReplaceDescriptors", *map, *result, reason,
9605 maybe_name.is_null() ? nullptr : *name));
9606 }
9607 return result;
9608 }
9609
9610
9611 // Creates transition tree starting from |split_map| and adding all descriptors
9612 // starting from descriptor with index |split_map|.NumberOfOwnDescriptors().
9613 // The way how it is done is tricky because of GC and special descriptors
9614 // marking logic.
AddMissingTransitions(Isolate * isolate,Handle<Map> split_map,Handle<DescriptorArray> descriptors,Handle<LayoutDescriptor> full_layout_descriptor)9615 Handle<Map> Map::AddMissingTransitions(
9616 Isolate* isolate, Handle<Map> split_map,
9617 Handle<DescriptorArray> descriptors,
9618 Handle<LayoutDescriptor> full_layout_descriptor) {
9619 DCHECK(descriptors->IsSortedNoDuplicates());
9620 int split_nof = split_map->NumberOfOwnDescriptors();
9621 int nof_descriptors = descriptors->number_of_descriptors();
9622 DCHECK_LT(split_nof, nof_descriptors);
9623
9624 // Start with creating last map which will own full descriptors array.
9625 // This is necessary to guarantee that GC will mark the whole descriptor
9626 // array if any of the allocations happening below fail.
9627 // Number of unused properties is temporarily incorrect and the layout
9628 // descriptor could unnecessarily be in slow mode but we will fix after
9629 // all the other intermediate maps are created.
9630 // Also the last map might have interesting symbols, we temporarily set
9631 // the flag and clear it right before the descriptors are installed. This
9632 // makes heap verification happy and ensures the flag ends up accurate.
9633 Handle<Map> last_map = CopyDropDescriptors(isolate, split_map);
9634 last_map->InitializeDescriptors(*descriptors, *full_layout_descriptor);
9635 last_map->SetInObjectUnusedPropertyFields(0);
9636 last_map->set_may_have_interesting_symbols(true);
9637
9638 // During creation of intermediate maps we violate descriptors sharing
9639 // invariant since the last map is not yet connected to the transition tree
9640 // we create here. But it is safe because GC never trims map's descriptors
9641 // if there are no dead transitions from that map and this is exactly the
9642 // case for all the intermediate maps we create here.
9643 Handle<Map> map = split_map;
9644 for (int i = split_nof; i < nof_descriptors - 1; ++i) {
9645 Handle<Map> new_map = CopyDropDescriptors(isolate, map);
9646 InstallDescriptors(isolate, map, new_map, i, descriptors,
9647 full_layout_descriptor);
9648 map = new_map;
9649 }
9650 map->NotifyLeafMapLayoutChange(isolate);
9651 last_map->set_may_have_interesting_symbols(false);
9652 InstallDescriptors(isolate, map, last_map, nof_descriptors - 1, descriptors,
9653 full_layout_descriptor);
9654 return last_map;
9655 }
9656
9657
9658 // Since this method is used to rewrite an existing transition tree, it can
9659 // always insert transitions without checking.
InstallDescriptors(Isolate * isolate,Handle<Map> parent,Handle<Map> child,int new_descriptor,Handle<DescriptorArray> descriptors,Handle<LayoutDescriptor> full_layout_descriptor)9660 void Map::InstallDescriptors(Isolate* isolate, Handle<Map> parent,
9661 Handle<Map> child, int new_descriptor,
9662 Handle<DescriptorArray> descriptors,
9663 Handle<LayoutDescriptor> full_layout_descriptor) {
9664 DCHECK(descriptors->IsSortedNoDuplicates());
9665
9666 child->set_instance_descriptors(*descriptors);
9667 child->SetNumberOfOwnDescriptors(new_descriptor + 1);
9668 child->CopyUnusedPropertyFields(*parent);
9669 PropertyDetails details = descriptors->GetDetails(new_descriptor);
9670 if (details.location() == kField) {
9671 child->AccountAddedPropertyField();
9672 }
9673
9674 if (FLAG_unbox_double_fields) {
9675 Handle<LayoutDescriptor> layout_descriptor =
9676 LayoutDescriptor::AppendIfFastOrUseFull(isolate, parent, details,
9677 full_layout_descriptor);
9678 child->set_layout_descriptor(*layout_descriptor);
9679 #ifdef VERIFY_HEAP
9680 // TODO(ishell): remove these checks from VERIFY_HEAP mode.
9681 if (FLAG_verify_heap) {
9682 CHECK(child->layout_descriptor()->IsConsistentWithMap(*child));
9683 }
9684 #else
9685 SLOW_DCHECK(child->layout_descriptor()->IsConsistentWithMap(*child));
9686 #endif
9687 child->set_visitor_id(Map::GetVisitorId(*child));
9688 }
9689
9690 Handle<Name> name = handle(descriptors->GetKey(new_descriptor), isolate);
9691 if (parent->may_have_interesting_symbols() || name->IsInterestingSymbol()) {
9692 child->set_may_have_interesting_symbols(true);
9693 }
9694 ConnectTransition(isolate, parent, child, name, SIMPLE_PROPERTY_TRANSITION);
9695 }
9696
CopyAsElementsKind(Isolate * isolate,Handle<Map> map,ElementsKind kind,TransitionFlag flag)9697 Handle<Map> Map::CopyAsElementsKind(Isolate* isolate, Handle<Map> map,
9698 ElementsKind kind, TransitionFlag flag) {
9699 // Only certain objects are allowed to have non-terminal fast transitional
9700 // elements kinds.
9701 DCHECK(map->IsJSObjectMap());
9702 DCHECK_IMPLIES(
9703 !map->CanHaveFastTransitionableElementsKind(),
9704 IsDictionaryElementsKind(kind) || IsTerminalElementsKind(kind));
9705
9706 Map* maybe_elements_transition_map = nullptr;
9707 if (flag == INSERT_TRANSITION) {
9708 // Ensure we are requested to add elements kind transition "near the root".
9709 DCHECK_EQ(map->FindRootMap(isolate)->NumberOfOwnDescriptors(),
9710 map->NumberOfOwnDescriptors());
9711
9712 maybe_elements_transition_map = map->ElementsTransitionMap();
9713 DCHECK(maybe_elements_transition_map == nullptr ||
9714 (maybe_elements_transition_map->elements_kind() ==
9715 DICTIONARY_ELEMENTS &&
9716 kind == DICTIONARY_ELEMENTS));
9717 DCHECK(!IsFastElementsKind(kind) ||
9718 IsMoreGeneralElementsKindTransition(map->elements_kind(), kind));
9719 DCHECK(kind != map->elements_kind());
9720 }
9721
9722 bool insert_transition =
9723 flag == INSERT_TRANSITION &&
9724 TransitionsAccessor(isolate, map).CanHaveMoreTransitions() &&
9725 maybe_elements_transition_map == nullptr;
9726
9727 if (insert_transition) {
9728 Handle<Map> new_map = CopyForTransition(isolate, map, "CopyAsElementsKind");
9729 new_map->set_elements_kind(kind);
9730
9731 Handle<Name> name = isolate->factory()->elements_transition_symbol();
9732 ConnectTransition(isolate, map, new_map, name, SPECIAL_TRANSITION);
9733 return new_map;
9734 }
9735
9736 // Create a new free-floating map only if we are not allowed to store it.
9737 Handle<Map> new_map = Copy(isolate, map, "CopyAsElementsKind");
9738 new_map->set_elements_kind(kind);
9739 return new_map;
9740 }
9741
AsLanguageMode(Isolate * isolate,Handle<Map> initial_map,Handle<SharedFunctionInfo> shared_info)9742 Handle<Map> Map::AsLanguageMode(Isolate* isolate, Handle<Map> initial_map,
9743 Handle<SharedFunctionInfo> shared_info) {
9744 DCHECK_EQ(JS_FUNCTION_TYPE, initial_map->instance_type());
9745 // Initial map for sloppy mode function is stored in the function
9746 // constructor. Initial maps for strict mode are cached as special transitions
9747 // using |strict_function_transition_symbol| as a key.
9748 if (is_sloppy(shared_info->language_mode())) return initial_map;
9749
9750 Handle<Map> function_map(Map::cast(isolate->native_context()->get(
9751 shared_info->function_map_index())),
9752 isolate);
9753
9754 STATIC_ASSERT(LanguageModeSize == 2);
9755 DCHECK_EQ(LanguageMode::kStrict, shared_info->language_mode());
9756 Handle<Symbol> transition_symbol =
9757 isolate->factory()->strict_function_transition_symbol();
9758 Map* maybe_transition = TransitionsAccessor(isolate, initial_map)
9759 .SearchSpecial(*transition_symbol);
9760 if (maybe_transition != nullptr) {
9761 return handle(maybe_transition, isolate);
9762 }
9763 initial_map->NotifyLeafMapLayoutChange(isolate);
9764
9765 // Create new map taking descriptors from the |function_map| and all
9766 // the other details from the |initial_map|.
9767 Handle<Map> map =
9768 Map::CopyInitialMap(isolate, function_map, initial_map->instance_size(),
9769 initial_map->GetInObjectProperties(),
9770 initial_map->UnusedPropertyFields());
9771 map->SetConstructor(initial_map->GetConstructor());
9772 map->set_prototype(initial_map->prototype());
9773 map->set_construction_counter(initial_map->construction_counter());
9774
9775 if (TransitionsAccessor(isolate, initial_map).CanHaveMoreTransitions()) {
9776 Map::ConnectTransition(isolate, initial_map, map, transition_symbol,
9777 SPECIAL_TRANSITION);
9778 }
9779 return map;
9780 }
9781
CopyForTransition(Isolate * isolate,Handle<Map> map,const char * reason)9782 Handle<Map> Map::CopyForTransition(Isolate* isolate, Handle<Map> map,
9783 const char* reason) {
9784 DCHECK(!map->is_prototype_map());
9785 Handle<Map> new_map = CopyDropDescriptors(isolate, map);
9786
9787 if (map->owns_descriptors()) {
9788 // In case the map owned its own descriptors, share the descriptors and
9789 // transfer ownership to the new map.
9790 // The properties did not change, so reuse descriptors.
9791 new_map->InitializeDescriptors(map->instance_descriptors(),
9792 map->GetLayoutDescriptor());
9793 } else {
9794 // In case the map did not own its own descriptors, a split is forced by
9795 // copying the map; creating a new descriptor array cell.
9796 Handle<DescriptorArray> descriptors(map->instance_descriptors(), isolate);
9797 int number_of_own_descriptors = map->NumberOfOwnDescriptors();
9798 Handle<DescriptorArray> new_descriptors = DescriptorArray::CopyUpTo(
9799 isolate, descriptors, number_of_own_descriptors);
9800 Handle<LayoutDescriptor> new_layout_descriptor(map->GetLayoutDescriptor(),
9801 isolate);
9802 new_map->InitializeDescriptors(*new_descriptors, *new_layout_descriptor);
9803 }
9804
9805 if (FLAG_trace_maps) {
9806 LOG(isolate, MapEvent("CopyForTransition", *map, *new_map, reason));
9807 }
9808 return new_map;
9809 }
9810
Copy(Isolate * isolate,Handle<Map> map,const char * reason)9811 Handle<Map> Map::Copy(Isolate* isolate, Handle<Map> map, const char* reason) {
9812 Handle<DescriptorArray> descriptors(map->instance_descriptors(), isolate);
9813 int number_of_own_descriptors = map->NumberOfOwnDescriptors();
9814 Handle<DescriptorArray> new_descriptors = DescriptorArray::CopyUpTo(
9815 isolate, descriptors, number_of_own_descriptors);
9816 Handle<LayoutDescriptor> new_layout_descriptor(map->GetLayoutDescriptor(),
9817 isolate);
9818 return CopyReplaceDescriptors(
9819 isolate, map, new_descriptors, new_layout_descriptor, OMIT_TRANSITION,
9820 MaybeHandle<Name>(), reason, SPECIAL_TRANSITION);
9821 }
9822
9823
Create(Isolate * isolate,int inobject_properties)9824 Handle<Map> Map::Create(Isolate* isolate, int inobject_properties) {
9825 Handle<Map> copy =
9826 Copy(isolate, handle(isolate->object_function()->initial_map(), isolate),
9827 "MapCreate");
9828
9829 // Check that we do not overflow the instance size when adding the extra
9830 // inobject properties. If the instance size overflows, we allocate as many
9831 // properties as we can as inobject properties.
9832 if (inobject_properties > JSObject::kMaxInObjectProperties) {
9833 inobject_properties = JSObject::kMaxInObjectProperties;
9834 }
9835
9836 int new_instance_size =
9837 JSObject::kHeaderSize + kPointerSize * inobject_properties;
9838
9839 // Adjust the map with the extra inobject properties.
9840 copy->set_instance_size(new_instance_size);
9841 copy->SetInObjectPropertiesStartInWords(JSObject::kHeaderSize / kPointerSize);
9842 DCHECK_EQ(copy->GetInObjectProperties(), inobject_properties);
9843 copy->SetInObjectUnusedPropertyFields(inobject_properties);
9844 copy->set_visitor_id(Map::GetVisitorId(*copy));
9845 return copy;
9846 }
9847
CopyForPreventExtensions(Isolate * isolate,Handle<Map> map,PropertyAttributes attrs_to_add,Handle<Symbol> transition_marker,const char * reason)9848 Handle<Map> Map::CopyForPreventExtensions(Isolate* isolate, Handle<Map> map,
9849 PropertyAttributes attrs_to_add,
9850 Handle<Symbol> transition_marker,
9851 const char* reason) {
9852 int num_descriptors = map->NumberOfOwnDescriptors();
9853 Handle<DescriptorArray> new_desc = DescriptorArray::CopyUpToAddAttributes(
9854 isolate, handle(map->instance_descriptors(), isolate), num_descriptors,
9855 attrs_to_add);
9856 Handle<LayoutDescriptor> new_layout_descriptor(map->GetLayoutDescriptor(),
9857 isolate);
9858 Handle<Map> new_map = CopyReplaceDescriptors(
9859 isolate, map, new_desc, new_layout_descriptor, INSERT_TRANSITION,
9860 transition_marker, reason, SPECIAL_TRANSITION);
9861 new_map->set_is_extensible(false);
9862 if (!IsFixedTypedArrayElementsKind(map->elements_kind())) {
9863 ElementsKind new_kind = IsStringWrapperElementsKind(map->elements_kind())
9864 ? SLOW_STRING_WRAPPER_ELEMENTS
9865 : DICTIONARY_ELEMENTS;
9866 new_map->set_elements_kind(new_kind);
9867 }
9868 return new_map;
9869 }
9870
9871 namespace {
9872
CanHoldValue(DescriptorArray * descriptors,int descriptor,PropertyConstness constness,Object * value)9873 bool CanHoldValue(DescriptorArray* descriptors, int descriptor,
9874 PropertyConstness constness, Object* value) {
9875 PropertyDetails details = descriptors->GetDetails(descriptor);
9876 if (details.location() == kField) {
9877 if (details.kind() == kData) {
9878 return IsGeneralizableTo(constness, details.constness()) &&
9879 value->FitsRepresentation(details.representation()) &&
9880 descriptors->GetFieldType(descriptor)->NowContains(value);
9881 } else {
9882 DCHECK_EQ(kAccessor, details.kind());
9883 return false;
9884 }
9885
9886 } else {
9887 DCHECK_EQ(kDescriptor, details.location());
9888 DCHECK_EQ(PropertyConstness::kConst, details.constness());
9889 if (details.kind() == kData) {
9890 DCHECK(!FLAG_track_constant_fields);
9891 DCHECK(descriptors->GetStrongValue(descriptor) != value ||
9892 value->FitsRepresentation(details.representation()));
9893 return descriptors->GetStrongValue(descriptor) == value;
9894 } else {
9895 DCHECK_EQ(kAccessor, details.kind());
9896 return false;
9897 }
9898 }
9899 UNREACHABLE();
9900 }
9901
UpdateDescriptorForValue(Isolate * isolate,Handle<Map> map,int descriptor,PropertyConstness constness,Handle<Object> value)9902 Handle<Map> UpdateDescriptorForValue(Isolate* isolate, Handle<Map> map,
9903 int descriptor,
9904 PropertyConstness constness,
9905 Handle<Object> value) {
9906 if (CanHoldValue(map->instance_descriptors(), descriptor, constness,
9907 *value)) {
9908 return map;
9909 }
9910
9911 PropertyAttributes attributes =
9912 map->instance_descriptors()->GetDetails(descriptor).attributes();
9913 Representation representation = value->OptimalRepresentation();
9914 Handle<FieldType> type = value->OptimalType(isolate, representation);
9915
9916 MapUpdater mu(isolate, map);
9917 return mu.ReconfigureToDataField(descriptor, attributes, constness,
9918 representation, type);
9919 }
9920
9921 } // namespace
9922
9923 // static
PrepareForDataProperty(Isolate * isolate,Handle<Map> map,int descriptor,PropertyConstness constness,Handle<Object> value)9924 Handle<Map> Map::PrepareForDataProperty(Isolate* isolate, Handle<Map> map,
9925 int descriptor,
9926 PropertyConstness constness,
9927 Handle<Object> value) {
9928 // Dictionaries can store any property value.
9929 DCHECK(!map->is_dictionary_map());
9930 // Update to the newest map before storing the property.
9931 return UpdateDescriptorForValue(isolate, Update(isolate, map), descriptor,
9932 constness, value);
9933 }
9934
TransitionToDataProperty(Isolate * isolate,Handle<Map> map,Handle<Name> name,Handle<Object> value,PropertyAttributes attributes,PropertyConstness constness,StoreFromKeyed store_mode)9935 Handle<Map> Map::TransitionToDataProperty(Isolate* isolate, Handle<Map> map,
9936 Handle<Name> name,
9937 Handle<Object> value,
9938 PropertyAttributes attributes,
9939 PropertyConstness constness,
9940 StoreFromKeyed store_mode) {
9941 RuntimeCallTimerScope stats_scope(
9942 isolate, *map,
9943 map->is_prototype_map()
9944 ? RuntimeCallCounterId::kPrototypeMap_TransitionToDataProperty
9945 : RuntimeCallCounterId::kMap_TransitionToDataProperty);
9946
9947 DCHECK(name->IsUniqueName());
9948 DCHECK(!map->is_dictionary_map());
9949
9950 // Migrate to the newest map before storing the property.
9951 map = Update(isolate, map);
9952
9953 Map* maybe_transition = TransitionsAccessor(isolate, map)
9954 .SearchTransition(*name, kData, attributes);
9955 if (maybe_transition != nullptr) {
9956 Handle<Map> transition(maybe_transition, isolate);
9957 int descriptor = transition->LastAdded();
9958
9959 DCHECK_EQ(attributes, transition->instance_descriptors()
9960 ->GetDetails(descriptor)
9961 .attributes());
9962
9963 return UpdateDescriptorForValue(isolate, transition, descriptor, constness,
9964 value);
9965 }
9966
9967 TransitionFlag flag = INSERT_TRANSITION;
9968 MaybeHandle<Map> maybe_map;
9969 if (!map->TooManyFastProperties(store_mode)) {
9970 if (!FLAG_track_constant_fields && value->IsJSFunction()) {
9971 maybe_map =
9972 Map::CopyWithConstant(isolate, map, name, value, attributes, flag);
9973 } else {
9974 Representation representation = value->OptimalRepresentation();
9975 Handle<FieldType> type = value->OptimalType(isolate, representation);
9976 maybe_map = Map::CopyWithField(isolate, map, name, type, attributes,
9977 constness, representation, flag);
9978 }
9979 }
9980
9981 Handle<Map> result;
9982 if (!maybe_map.ToHandle(&result)) {
9983 const char* reason = "TooManyFastProperties";
9984 #if V8_TRACE_MAPS
9985 std::unique_ptr<ScopedVector<char>> buffer;
9986 if (FLAG_trace_maps) {
9987 ScopedVector<char> name_buffer(100);
9988 name->NameShortPrint(name_buffer);
9989 buffer.reset(new ScopedVector<char>(128));
9990 SNPrintF(*buffer, "TooManyFastProperties %s", name_buffer.start());
9991 reason = buffer->start();
9992 }
9993 #endif
9994 Handle<Object> maybe_constructor(map->GetConstructor(), isolate);
9995 if (FLAG_feedback_normalization && map->new_target_is_base() &&
9996 maybe_constructor->IsJSFunction() &&
9997 !JSFunction::cast(*maybe_constructor)->shared()->native()) {
9998 Handle<JSFunction> constructor =
9999 Handle<JSFunction>::cast(maybe_constructor);
10000 DCHECK_NE(*constructor,
10001 constructor->context()->native_context()->object_function());
10002 Handle<Map> initial_map(constructor->initial_map(), isolate);
10003 result = Map::Normalize(isolate, initial_map, CLEAR_INOBJECT_PROPERTIES,
10004 reason);
10005 initial_map->DeprecateTransitionTree(isolate);
10006 Handle<Object> prototype(result->prototype(), isolate);
10007 JSFunction::SetInitialMap(constructor, result, prototype);
10008
10009 // Deoptimize all code that embeds the previous initial map.
10010 initial_map->dependent_code()->DeoptimizeDependentCodeGroup(
10011 isolate, DependentCode::kInitialMapChangedGroup);
10012 if (!result->EquivalentToForNormalization(*map,
10013 CLEAR_INOBJECT_PROPERTIES)) {
10014 result =
10015 Map::Normalize(isolate, map, CLEAR_INOBJECT_PROPERTIES, reason);
10016 }
10017 } else {
10018 result = Map::Normalize(isolate, map, CLEAR_INOBJECT_PROPERTIES, reason);
10019 }
10020 }
10021
10022 return result;
10023 }
10024
ReconfigureExistingProperty(Isolate * isolate,Handle<Map> map,int descriptor,PropertyKind kind,PropertyAttributes attributes)10025 Handle<Map> Map::ReconfigureExistingProperty(Isolate* isolate, Handle<Map> map,
10026 int descriptor, PropertyKind kind,
10027 PropertyAttributes attributes) {
10028 // Dictionaries have to be reconfigured in-place.
10029 DCHECK(!map->is_dictionary_map());
10030
10031 if (!map->GetBackPointer()->IsMap()) {
10032 // There is no benefit from reconstructing transition tree for maps without
10033 // back pointers.
10034 return CopyGeneralizeAllFields(isolate, map, map->elements_kind(),
10035 descriptor, kind, attributes,
10036 "GenAll_AttributesMismatchProtoMap");
10037 }
10038
10039 if (FLAG_trace_generalization) {
10040 map->PrintReconfiguration(isolate, stdout, descriptor, kind, attributes);
10041 }
10042
10043 MapUpdater mu(isolate, map);
10044 DCHECK_EQ(kData, kind); // Only kData case is supported so far.
10045 Handle<Map> new_map = mu.ReconfigureToDataField(
10046 descriptor, attributes, kDefaultFieldConstness, Representation::None(),
10047 FieldType::None(isolate));
10048 return new_map;
10049 }
10050
TransitionToAccessorProperty(Isolate * isolate,Handle<Map> map,Handle<Name> name,int descriptor,Handle<Object> getter,Handle<Object> setter,PropertyAttributes attributes)10051 Handle<Map> Map::TransitionToAccessorProperty(Isolate* isolate, Handle<Map> map,
10052 Handle<Name> name, int descriptor,
10053 Handle<Object> getter,
10054 Handle<Object> setter,
10055 PropertyAttributes attributes) {
10056 RuntimeCallTimerScope stats_scope(
10057 isolate,
10058 map->is_prototype_map()
10059 ? RuntimeCallCounterId::kPrototypeMap_TransitionToAccessorProperty
10060 : RuntimeCallCounterId::kMap_TransitionToAccessorProperty);
10061
10062 // At least one of the accessors needs to be a new value.
10063 DCHECK(!getter->IsNull(isolate) || !setter->IsNull(isolate));
10064 DCHECK(name->IsUniqueName());
10065
10066 // Dictionary maps can always have additional data properties.
10067 if (map->is_dictionary_map()) return map;
10068
10069 // Migrate to the newest map before transitioning to the new property.
10070 map = Update(isolate, map);
10071
10072 PropertyNormalizationMode mode = map->is_prototype_map()
10073 ? KEEP_INOBJECT_PROPERTIES
10074 : CLEAR_INOBJECT_PROPERTIES;
10075
10076 Map* maybe_transition = TransitionsAccessor(isolate, map)
10077 .SearchTransition(*name, kAccessor, attributes);
10078 if (maybe_transition != nullptr) {
10079 Handle<Map> transition(maybe_transition, isolate);
10080 DescriptorArray* descriptors = transition->instance_descriptors();
10081 int descriptor = transition->LastAdded();
10082 DCHECK(descriptors->GetKey(descriptor)->Equals(*name));
10083
10084 DCHECK_EQ(kAccessor, descriptors->GetDetails(descriptor).kind());
10085 DCHECK_EQ(attributes, descriptors->GetDetails(descriptor).attributes());
10086
10087 Handle<Object> maybe_pair(descriptors->GetStrongValue(descriptor), isolate);
10088 if (!maybe_pair->IsAccessorPair()) {
10089 return Map::Normalize(isolate, map, mode,
10090 "TransitionToAccessorFromNonPair");
10091 }
10092
10093 Handle<AccessorPair> pair = Handle<AccessorPair>::cast(maybe_pair);
10094 if (!pair->Equals(*getter, *setter)) {
10095 return Map::Normalize(isolate, map, mode,
10096 "TransitionToDifferentAccessor");
10097 }
10098
10099 return transition;
10100 }
10101
10102 Handle<AccessorPair> pair;
10103 DescriptorArray* old_descriptors = map->instance_descriptors();
10104 if (descriptor != DescriptorArray::kNotFound) {
10105 if (descriptor != map->LastAdded()) {
10106 return Map::Normalize(isolate, map, mode, "AccessorsOverwritingNonLast");
10107 }
10108 PropertyDetails old_details = old_descriptors->GetDetails(descriptor);
10109 if (old_details.kind() != kAccessor) {
10110 return Map::Normalize(isolate, map, mode,
10111 "AccessorsOverwritingNonAccessors");
10112 }
10113
10114 if (old_details.attributes() != attributes) {
10115 return Map::Normalize(isolate, map, mode, "AccessorsWithAttributes");
10116 }
10117
10118 Handle<Object> maybe_pair(old_descriptors->GetStrongValue(descriptor),
10119 isolate);
10120 if (!maybe_pair->IsAccessorPair()) {
10121 return Map::Normalize(isolate, map, mode, "AccessorsOverwritingNonPair");
10122 }
10123
10124 Handle<AccessorPair> current_pair = Handle<AccessorPair>::cast(maybe_pair);
10125 if (current_pair->Equals(*getter, *setter)) return map;
10126
10127 bool overwriting_accessor = false;
10128 if (!getter->IsNull(isolate) &&
10129 !current_pair->get(ACCESSOR_GETTER)->IsNull(isolate) &&
10130 current_pair->get(ACCESSOR_GETTER) != *getter) {
10131 overwriting_accessor = true;
10132 }
10133 if (!setter->IsNull(isolate) &&
10134 !current_pair->get(ACCESSOR_SETTER)->IsNull(isolate) &&
10135 current_pair->get(ACCESSOR_SETTER) != *setter) {
10136 overwriting_accessor = true;
10137 }
10138 if (overwriting_accessor) {
10139 return Map::Normalize(isolate, map, mode,
10140 "AccessorsOverwritingAccessors");
10141 }
10142
10143 pair = AccessorPair::Copy(isolate, Handle<AccessorPair>::cast(maybe_pair));
10144 } else if (map->NumberOfOwnDescriptors() >= kMaxNumberOfDescriptors ||
10145 map->TooManyFastProperties(CERTAINLY_NOT_STORE_FROM_KEYED)) {
10146 return Map::Normalize(isolate, map, CLEAR_INOBJECT_PROPERTIES,
10147 "TooManyAccessors");
10148 } else {
10149 pair = isolate->factory()->NewAccessorPair();
10150 }
10151
10152 pair->SetComponents(*getter, *setter);
10153
10154 TransitionFlag flag = INSERT_TRANSITION;
10155 Descriptor d = Descriptor::AccessorConstant(name, pair, attributes);
10156 return Map::CopyInsertDescriptor(isolate, map, &d, flag);
10157 }
10158
CopyAddDescriptor(Isolate * isolate,Handle<Map> map,Descriptor * descriptor,TransitionFlag flag)10159 Handle<Map> Map::CopyAddDescriptor(Isolate* isolate, Handle<Map> map,
10160 Descriptor* descriptor,
10161 TransitionFlag flag) {
10162 Handle<DescriptorArray> descriptors(map->instance_descriptors(), isolate);
10163
10164 // Share descriptors only if map owns descriptors and it not an initial map.
10165 if (flag == INSERT_TRANSITION && map->owns_descriptors() &&
10166 !map->GetBackPointer()->IsUndefined(isolate) &&
10167 TransitionsAccessor(isolate, map).CanHaveMoreTransitions()) {
10168 return ShareDescriptor(isolate, map, descriptors, descriptor);
10169 }
10170
10171 int nof = map->NumberOfOwnDescriptors();
10172 Handle<DescriptorArray> new_descriptors =
10173 DescriptorArray::CopyUpTo(isolate, descriptors, nof, 1);
10174 new_descriptors->Append(descriptor);
10175
10176 Handle<LayoutDescriptor> new_layout_descriptor =
10177 FLAG_unbox_double_fields
10178 ? LayoutDescriptor::New(isolate, map, new_descriptors, nof + 1)
10179 : handle(LayoutDescriptor::FastPointerLayout(), isolate);
10180
10181 return CopyReplaceDescriptors(
10182 isolate, map, new_descriptors, new_layout_descriptor, flag,
10183 descriptor->GetKey(), "CopyAddDescriptor", SIMPLE_PROPERTY_TRANSITION);
10184 }
10185
CopyInsertDescriptor(Isolate * isolate,Handle<Map> map,Descriptor * descriptor,TransitionFlag flag)10186 Handle<Map> Map::CopyInsertDescriptor(Isolate* isolate, Handle<Map> map,
10187 Descriptor* descriptor,
10188 TransitionFlag flag) {
10189 Handle<DescriptorArray> old_descriptors(map->instance_descriptors(), isolate);
10190
10191 // We replace the key if it is already present.
10192 int index =
10193 old_descriptors->SearchWithCache(isolate, *descriptor->GetKey(), *map);
10194 if (index != DescriptorArray::kNotFound) {
10195 return CopyReplaceDescriptor(isolate, map, old_descriptors, descriptor,
10196 index, flag);
10197 }
10198 return CopyAddDescriptor(isolate, map, descriptor, flag);
10199 }
10200
CopyUpTo(Isolate * isolate,Handle<DescriptorArray> desc,int enumeration_index,int slack)10201 Handle<DescriptorArray> DescriptorArray::CopyUpTo(Isolate* isolate,
10202 Handle<DescriptorArray> desc,
10203 int enumeration_index,
10204 int slack) {
10205 return DescriptorArray::CopyUpToAddAttributes(isolate, desc,
10206 enumeration_index, NONE, slack);
10207 }
10208
CopyUpToAddAttributes(Isolate * isolate,Handle<DescriptorArray> desc,int enumeration_index,PropertyAttributes attributes,int slack)10209 Handle<DescriptorArray> DescriptorArray::CopyUpToAddAttributes(
10210 Isolate* isolate, Handle<DescriptorArray> desc, int enumeration_index,
10211 PropertyAttributes attributes, int slack) {
10212 if (enumeration_index + slack == 0) {
10213 return isolate->factory()->empty_descriptor_array();
10214 }
10215
10216 int size = enumeration_index;
10217
10218 Handle<DescriptorArray> descriptors =
10219 DescriptorArray::Allocate(isolate, size, slack);
10220
10221 if (attributes != NONE) {
10222 for (int i = 0; i < size; ++i) {
10223 MaybeObject* value_or_field_type = desc->GetValue(i);
10224 Name* key = desc->GetKey(i);
10225 PropertyDetails details = desc->GetDetails(i);
10226 // Bulk attribute changes never affect private properties.
10227 if (!key->IsPrivate()) {
10228 int mask = DONT_DELETE | DONT_ENUM;
10229 // READ_ONLY is an invalid attribute for JS setters/getters.
10230 HeapObject* heap_object;
10231 if (details.kind() != kAccessor ||
10232 !(value_or_field_type->ToStrongHeapObject(&heap_object) &&
10233 heap_object->IsAccessorPair())) {
10234 mask |= READ_ONLY;
10235 }
10236 details = details.CopyAddAttributes(
10237 static_cast<PropertyAttributes>(attributes & mask));
10238 }
10239 descriptors->Set(i, key, value_or_field_type, details);
10240 }
10241 } else {
10242 for (int i = 0; i < size; ++i) {
10243 descriptors->CopyFrom(i, *desc);
10244 }
10245 }
10246
10247 if (desc->number_of_descriptors() != enumeration_index) descriptors->Sort();
10248
10249 return descriptors;
10250 }
10251
10252 // Create a new descriptor array with only enumerable, configurable, writeable
10253 // data properties, but identical field locations.
CopyForFastObjectClone(Isolate * isolate,Handle<DescriptorArray> src,int enumeration_index,int slack)10254 Handle<DescriptorArray> DescriptorArray::CopyForFastObjectClone(
10255 Isolate* isolate, Handle<DescriptorArray> src, int enumeration_index,
10256 int slack) {
10257 if (enumeration_index + slack == 0) {
10258 return isolate->factory()->empty_descriptor_array();
10259 }
10260
10261 int size = enumeration_index;
10262 Handle<DescriptorArray> descriptors =
10263 DescriptorArray::Allocate(isolate, size, slack);
10264
10265 for (int i = 0; i < size; ++i) {
10266 Name* key = src->GetKey(i);
10267 PropertyDetails details = src->GetDetails(i);
10268
10269 DCHECK(!key->IsPrivateField());
10270 DCHECK(details.IsEnumerable());
10271 DCHECK_EQ(details.kind(), kData);
10272
10273 // Ensure the ObjectClone property details are NONE, and that all source
10274 // details did not contain DONT_ENUM.
10275 PropertyDetails new_details(kData, NONE, details.location(),
10276 details.constness(), details.representation(),
10277 details.field_index());
10278 // Do not propagate the field type of normal object fields from the
10279 // original descriptors since FieldType changes don't create new maps.
10280 MaybeObject* type = src->GetValue(i);
10281 if (details.location() == PropertyLocation::kField) {
10282 type = MaybeObject::FromObject(FieldType::Any());
10283 }
10284 descriptors->Set(i, key, type, new_details);
10285 }
10286
10287 descriptors->Sort();
10288
10289 return descriptors;
10290 }
10291
IsEqualUpTo(DescriptorArray * desc,int nof_descriptors)10292 bool DescriptorArray::IsEqualUpTo(DescriptorArray* desc, int nof_descriptors) {
10293 for (int i = 0; i < nof_descriptors; i++) {
10294 if (GetKey(i) != desc->GetKey(i) || GetValue(i) != desc->GetValue(i)) {
10295 return false;
10296 }
10297 PropertyDetails details = GetDetails(i);
10298 PropertyDetails other_details = desc->GetDetails(i);
10299 if (details.kind() != other_details.kind() ||
10300 details.location() != other_details.location() ||
10301 !details.representation().Equals(other_details.representation())) {
10302 return false;
10303 }
10304 }
10305 return true;
10306 }
10307
CopyReplaceDescriptor(Isolate * isolate,Handle<Map> map,Handle<DescriptorArray> descriptors,Descriptor * descriptor,int insertion_index,TransitionFlag flag)10308 Handle<Map> Map::CopyReplaceDescriptor(Isolate* isolate, Handle<Map> map,
10309 Handle<DescriptorArray> descriptors,
10310 Descriptor* descriptor,
10311 int insertion_index,
10312 TransitionFlag flag) {
10313 Handle<Name> key = descriptor->GetKey();
10314 DCHECK_EQ(*key, descriptors->GetKey(insertion_index));
10315 // This function does not support replacing property fields as
10316 // that would break property field counters.
10317 DCHECK_NE(kField, descriptor->GetDetails().location());
10318 DCHECK_NE(kField, descriptors->GetDetails(insertion_index).location());
10319
10320 Handle<DescriptorArray> new_descriptors = DescriptorArray::CopyUpTo(
10321 isolate, descriptors, map->NumberOfOwnDescriptors());
10322
10323 new_descriptors->Replace(insertion_index, descriptor);
10324 Handle<LayoutDescriptor> new_layout_descriptor = LayoutDescriptor::New(
10325 isolate, map, new_descriptors, new_descriptors->number_of_descriptors());
10326
10327 SimpleTransitionFlag simple_flag =
10328 (insertion_index == descriptors->number_of_descriptors() - 1)
10329 ? SIMPLE_PROPERTY_TRANSITION
10330 : PROPERTY_TRANSITION;
10331 return CopyReplaceDescriptors(isolate, map, new_descriptors,
10332 new_layout_descriptor, flag, key,
10333 "CopyReplaceDescriptor", simple_flag);
10334 }
10335
SetAndGrow(Isolate * isolate,Handle<FixedArray> array,int index,Handle<Object> value,PretenureFlag pretenure)10336 Handle<FixedArray> FixedArray::SetAndGrow(Isolate* isolate,
10337 Handle<FixedArray> array, int index,
10338 Handle<Object> value,
10339 PretenureFlag pretenure) {
10340 if (index < array->length()) {
10341 array->set(index, *value);
10342 return array;
10343 }
10344 int capacity = array->length();
10345 do {
10346 capacity = JSObject::NewElementsCapacity(capacity);
10347 } while (capacity <= index);
10348 Handle<FixedArray> new_array =
10349 isolate->factory()->NewUninitializedFixedArray(capacity, pretenure);
10350 array->CopyTo(0, *new_array, 0, array->length());
10351 new_array->FillWithHoles(array->length(), new_array->length());
10352 new_array->set(index, *value);
10353 return new_array;
10354 }
10355
ContainsSortedNumbers()10356 bool FixedArray::ContainsSortedNumbers() {
10357 for (int i = 1; i < length(); ++i) {
10358 Object* a_obj = get(i - 1);
10359 Object* b_obj = get(i);
10360 if (!a_obj->IsNumber() || !b_obj->IsNumber()) return false;
10361
10362 uint32_t a = NumberToUint32(a_obj);
10363 uint32_t b = NumberToUint32(b_obj);
10364
10365 if (a > b) return false;
10366 }
10367 return true;
10368 }
10369
ShrinkOrEmpty(Isolate * isolate,Handle<FixedArray> array,int new_length)10370 Handle<FixedArray> FixedArray::ShrinkOrEmpty(Isolate* isolate,
10371 Handle<FixedArray> array,
10372 int new_length) {
10373 if (new_length == 0) {
10374 return array->GetReadOnlyRoots().empty_fixed_array_handle();
10375 } else {
10376 array->Shrink(isolate, new_length);
10377 return array;
10378 }
10379 }
10380
Shrink(Isolate * isolate,int new_length)10381 void FixedArray::Shrink(Isolate* isolate, int new_length) {
10382 DCHECK(0 < new_length && new_length <= length());
10383 if (new_length < length()) {
10384 isolate->heap()->RightTrimFixedArray(this, length() - new_length);
10385 }
10386 }
10387
CopyTo(int pos,FixedArray * dest,int dest_pos,int len) const10388 void FixedArray::CopyTo(int pos, FixedArray* dest, int dest_pos,
10389 int len) const {
10390 DisallowHeapAllocation no_gc;
10391 // Return early if len == 0 so that we don't try to read the write barrier off
10392 // a canonical read-only empty fixed array.
10393 if (len == 0) return;
10394 WriteBarrierMode mode = dest->GetWriteBarrierMode(no_gc);
10395 for (int index = 0; index < len; index++) {
10396 dest->set(dest_pos+index, get(pos+index), mode);
10397 }
10398 }
10399
10400 #ifdef DEBUG
IsEqualTo(FixedArray * other)10401 bool FixedArray::IsEqualTo(FixedArray* other) {
10402 if (length() != other->length()) return false;
10403 for (int i = 0 ; i < length(); ++i) {
10404 if (get(i) != other->get(i)) return false;
10405 }
10406 return true;
10407 }
10408 #endif
10409
PrototypeRegistryCompactionCallback(HeapObject * value,int old_index,int new_index)10410 void JSObject::PrototypeRegistryCompactionCallback(HeapObject* value,
10411 int old_index,
10412 int new_index) {
10413 DCHECK(value->IsMap() && Map::cast(value)->is_prototype_map());
10414 Map* map = Map::cast(value);
10415 DCHECK(map->prototype_info()->IsPrototypeInfo());
10416 PrototypeInfo* proto_info = PrototypeInfo::cast(map->prototype_info());
10417 DCHECK_EQ(old_index, proto_info->registry_slot());
10418 proto_info->set_registry_slot(new_index);
10419 }
10420
10421 // static
Add(Isolate * isolate,Handle<ArrayList> array,Handle<Object> obj)10422 Handle<ArrayList> ArrayList::Add(Isolate* isolate, Handle<ArrayList> array,
10423 Handle<Object> obj) {
10424 int length = array->Length();
10425 array = EnsureSpace(isolate, array, length + 1);
10426 // Check that GC didn't remove elements from the array.
10427 DCHECK_EQ(array->Length(), length);
10428 array->Set(length, *obj);
10429 array->SetLength(length + 1);
10430 return array;
10431 }
10432
10433 // static
Add(Isolate * isolate,Handle<ArrayList> array,Handle<Object> obj1,Handle<Object> obj2)10434 Handle<ArrayList> ArrayList::Add(Isolate* isolate, Handle<ArrayList> array,
10435 Handle<Object> obj1, Handle<Object> obj2) {
10436 int length = array->Length();
10437 array = EnsureSpace(isolate, array, length + 2);
10438 // Check that GC didn't remove elements from the array.
10439 DCHECK_EQ(array->Length(), length);
10440 array->Set(length, *obj1);
10441 array->Set(length + 1, *obj2);
10442 array->SetLength(length + 2);
10443 return array;
10444 }
10445
10446 // static
New(Isolate * isolate,int size)10447 Handle<ArrayList> ArrayList::New(Isolate* isolate, int size) {
10448 Handle<FixedArray> fixed_array =
10449 isolate->factory()->NewFixedArray(size + kFirstIndex);
10450 fixed_array->set_map_no_write_barrier(
10451 ReadOnlyRoots(isolate).array_list_map());
10452 Handle<ArrayList> result = Handle<ArrayList>::cast(fixed_array);
10453 result->SetLength(0);
10454 return result;
10455 }
10456
Elements(Isolate * isolate,Handle<ArrayList> array)10457 Handle<FixedArray> ArrayList::Elements(Isolate* isolate,
10458 Handle<ArrayList> array) {
10459 int length = array->Length();
10460 Handle<FixedArray> result = isolate->factory()->NewFixedArray(length);
10461 // Do not copy the first entry, i.e., the length.
10462 array->CopyTo(kFirstIndex, *result, 0, length);
10463 return result;
10464 }
10465
IsFull()10466 bool ArrayList::IsFull() {
10467 int capacity = length();
10468 return kFirstIndex + Length() == capacity;
10469 }
10470
10471 namespace {
10472
EnsureSpaceInFixedArray(Isolate * isolate,Handle<FixedArray> array,int length)10473 Handle<FixedArray> EnsureSpaceInFixedArray(Isolate* isolate,
10474 Handle<FixedArray> array,
10475 int length) {
10476 int capacity = array->length();
10477 if (capacity < length) {
10478 int new_capacity = length;
10479 new_capacity = new_capacity + Max(new_capacity / 2, 2);
10480 int grow_by = new_capacity - capacity;
10481 array = isolate->factory()->CopyFixedArrayAndGrow(array, grow_by);
10482 }
10483 return array;
10484 }
10485
10486 } // namespace
10487
10488 // static
EnsureSpace(Isolate * isolate,Handle<ArrayList> array,int length)10489 Handle<ArrayList> ArrayList::EnsureSpace(Isolate* isolate,
10490 Handle<ArrayList> array, int length) {
10491 const bool empty = (array->length() == 0);
10492 auto ret = EnsureSpaceInFixedArray(isolate, array, kFirstIndex + length);
10493 if (empty) {
10494 ret->set_map_no_write_barrier(array->GetReadOnlyRoots().array_list_map());
10495
10496 Handle<ArrayList>::cast(ret)->SetLength(0);
10497 }
10498 return Handle<ArrayList>::cast(ret);
10499 }
10500
10501 // static
AddToEnd(Isolate * isolate,Handle<WeakArrayList> array,MaybeObjectHandle value)10502 Handle<WeakArrayList> WeakArrayList::AddToEnd(Isolate* isolate,
10503 Handle<WeakArrayList> array,
10504 MaybeObjectHandle value) {
10505 int length = array->length();
10506 array = EnsureSpace(isolate, array, length + 1);
10507 // Reload length; GC might have removed elements from the array.
10508 length = array->length();
10509 array->Set(length, *value);
10510 array->set_length(length + 1);
10511 return array;
10512 }
10513
IsFull()10514 bool WeakArrayList::IsFull() { return length() == capacity(); }
10515
10516 // static
EnsureSpace(Isolate * isolate,Handle<WeakArrayList> array,int length,PretenureFlag pretenure)10517 Handle<WeakArrayList> WeakArrayList::EnsureSpace(Isolate* isolate,
10518 Handle<WeakArrayList> array,
10519 int length,
10520 PretenureFlag pretenure) {
10521 int capacity = array->capacity();
10522 if (capacity < length) {
10523 int new_capacity = length;
10524 new_capacity = new_capacity + Max(new_capacity / 2, 2);
10525 int grow_by = new_capacity - capacity;
10526 array =
10527 isolate->factory()->CopyWeakArrayListAndGrow(array, grow_by, pretenure);
10528 }
10529 return array;
10530 }
10531
CountLiveWeakReferences() const10532 int WeakArrayList::CountLiveWeakReferences() const {
10533 int live_weak_references = 0;
10534 for (int i = 0; i < length(); i++) {
10535 if (Get(i)->IsWeakHeapObject()) {
10536 ++live_weak_references;
10537 }
10538 }
10539 return live_weak_references;
10540 }
10541
RemoveOne(MaybeObjectHandle value)10542 bool WeakArrayList::RemoveOne(MaybeObjectHandle value) {
10543 if (length() == 0) return false;
10544 // Optimize for the most recently added element to be removed again.
10545 int last_index = length() - 1;
10546 for (int i = last_index; i >= 0; --i) {
10547 if (Get(i) == *value) {
10548 // Move the last element into the this slot (or no-op, if this is the
10549 // last slot).
10550 Set(i, Get(last_index));
10551 Set(last_index, HeapObjectReference::ClearedValue());
10552 set_length(last_index);
10553 return true;
10554 }
10555 }
10556 return false;
10557 }
10558
10559 // static
Add(Isolate * isolate,Handle<WeakArrayList> array,Handle<Map> value,int * assigned_index)10560 Handle<WeakArrayList> PrototypeUsers::Add(Isolate* isolate,
10561 Handle<WeakArrayList> array,
10562 Handle<Map> value,
10563 int* assigned_index) {
10564 int length = array->length();
10565 if (length == 0) {
10566 // Uninitialized WeakArrayList; need to initialize empty_slot_index.
10567 array = WeakArrayList::EnsureSpace(isolate, array, kFirstIndex + 1);
10568 set_empty_slot_index(*array, kNoEmptySlotsMarker);
10569 array->Set(kFirstIndex, HeapObjectReference::Weak(*value));
10570 array->set_length(kFirstIndex + 1);
10571 if (assigned_index != nullptr) *assigned_index = kFirstIndex;
10572 return array;
10573 }
10574
10575 // If the array has unfilled space at the end, use it.
10576 if (!array->IsFull()) {
10577 array->Set(length, HeapObjectReference::Weak(*value));
10578 array->set_length(length + 1);
10579 if (assigned_index != nullptr) *assigned_index = length;
10580 return array;
10581 }
10582
10583 // If there are empty slots, use one of them.
10584 int empty_slot = Smi::ToInt(empty_slot_index(*array));
10585 if (empty_slot != kNoEmptySlotsMarker) {
10586 DCHECK_GE(empty_slot, kFirstIndex);
10587 CHECK_LT(empty_slot, array->length());
10588 int next_empty_slot = Smi::ToInt(array->Get(empty_slot)->ToSmi());
10589
10590 array->Set(empty_slot, HeapObjectReference::Weak(*value));
10591 if (assigned_index != nullptr) *assigned_index = empty_slot;
10592
10593 set_empty_slot_index(*array, next_empty_slot);
10594 return array;
10595 } else {
10596 DCHECK_EQ(empty_slot, kNoEmptySlotsMarker);
10597 }
10598
10599 // Array full and no empty slots. Grow the array.
10600 array = WeakArrayList::EnsureSpace(isolate, array, length + 1);
10601 array->Set(length, HeapObjectReference::Weak(*value));
10602 array->set_length(length + 1);
10603 if (assigned_index != nullptr) *assigned_index = length;
10604 return array;
10605 }
10606
Compact(Handle<WeakArrayList> array,Heap * heap,CompactionCallback callback,PretenureFlag pretenure)10607 WeakArrayList* PrototypeUsers::Compact(Handle<WeakArrayList> array, Heap* heap,
10608 CompactionCallback callback,
10609 PretenureFlag pretenure) {
10610 if (array->length() == 0) {
10611 return *array;
10612 }
10613 int new_length = kFirstIndex + array->CountLiveWeakReferences();
10614 if (new_length == array->length()) {
10615 return *array;
10616 }
10617
10618 Handle<WeakArrayList> new_array = WeakArrayList::EnsureSpace(
10619 heap->isolate(),
10620 handle(ReadOnlyRoots(heap).empty_weak_array_list(), heap->isolate()),
10621 new_length, pretenure);
10622 // Allocation might have caused GC and turned some of the elements into
10623 // cleared weak heap objects. Count the number of live objects again.
10624 int copy_to = kFirstIndex;
10625 for (int i = kFirstIndex; i < array->length(); i++) {
10626 MaybeObject* element = array->Get(i);
10627 if (element->IsSmi()) continue;
10628 if (element->IsClearedWeakHeapObject()) continue;
10629 HeapObject* value = element->ToWeakHeapObject();
10630 callback(value, i, copy_to);
10631 new_array->Set(copy_to++, element);
10632 }
10633 new_array->set_length(copy_to);
10634 set_empty_slot_index(*new_array, kNoEmptySlotsMarker);
10635 return *new_array;
10636 }
10637
ReserveCaptures(Isolate * isolate,Handle<RegExpMatchInfo> match_info,int capture_count)10638 Handle<RegExpMatchInfo> RegExpMatchInfo::ReserveCaptures(
10639 Isolate* isolate, Handle<RegExpMatchInfo> match_info, int capture_count) {
10640 DCHECK_GE(match_info->length(), kLastMatchOverhead);
10641 const int required_length = kFirstCaptureIndex + capture_count;
10642 Handle<FixedArray> result =
10643 EnsureSpaceInFixedArray(isolate, match_info, required_length);
10644 return Handle<RegExpMatchInfo>::cast(result);
10645 }
10646
10647 // static
AppendJSFrame(Handle<FrameArray> in,Handle<Object> receiver,Handle<JSFunction> function,Handle<AbstractCode> code,int offset,int flags)10648 Handle<FrameArray> FrameArray::AppendJSFrame(Handle<FrameArray> in,
10649 Handle<Object> receiver,
10650 Handle<JSFunction> function,
10651 Handle<AbstractCode> code,
10652 int offset, int flags) {
10653 const int frame_count = in->FrameCount();
10654 const int new_length = LengthFor(frame_count + 1);
10655 Handle<FrameArray> array =
10656 EnsureSpace(function->GetIsolate(), in, new_length);
10657 array->SetReceiver(frame_count, *receiver);
10658 array->SetFunction(frame_count, *function);
10659 array->SetCode(frame_count, *code);
10660 array->SetOffset(frame_count, Smi::FromInt(offset));
10661 array->SetFlags(frame_count, Smi::FromInt(flags));
10662 array->set(kFrameCountIndex, Smi::FromInt(frame_count + 1));
10663 return array;
10664 }
10665
10666 // static
AppendWasmFrame(Handle<FrameArray> in,Handle<WasmInstanceObject> wasm_instance,int wasm_function_index,wasm::WasmCode * code,int offset,int flags)10667 Handle<FrameArray> FrameArray::AppendWasmFrame(
10668 Handle<FrameArray> in, Handle<WasmInstanceObject> wasm_instance,
10669 int wasm_function_index, wasm::WasmCode* code, int offset, int flags) {
10670 Isolate* isolate = wasm_instance->GetIsolate();
10671 const int frame_count = in->FrameCount();
10672 const int new_length = LengthFor(frame_count + 1);
10673 Handle<FrameArray> array = EnsureSpace(isolate, in, new_length);
10674 // The {code} will be {nullptr} for interpreted wasm frames.
10675 Handle<Foreign> code_foreign =
10676 isolate->factory()->NewForeign(reinterpret_cast<Address>(code));
10677 array->SetWasmInstance(frame_count, *wasm_instance);
10678 array->SetWasmFunctionIndex(frame_count, Smi::FromInt(wasm_function_index));
10679 array->SetWasmCodeObject(frame_count, *code_foreign);
10680 array->SetOffset(frame_count, Smi::FromInt(offset));
10681 array->SetFlags(frame_count, Smi::FromInt(flags));
10682 array->set(kFrameCountIndex, Smi::FromInt(frame_count + 1));
10683 return array;
10684 }
10685
ShrinkToFit(Isolate * isolate)10686 void FrameArray::ShrinkToFit(Isolate* isolate) {
10687 Shrink(isolate, LengthFor(FrameCount()));
10688 }
10689
10690 // static
EnsureSpace(Isolate * isolate,Handle<FrameArray> array,int length)10691 Handle<FrameArray> FrameArray::EnsureSpace(Isolate* isolate,
10692 Handle<FrameArray> array,
10693 int length) {
10694 return Handle<FrameArray>::cast(
10695 EnsureSpaceInFixedArray(isolate, array, length));
10696 }
10697
Allocate(Isolate * isolate,int number_of_descriptors,int slack,PretenureFlag pretenure)10698 Handle<DescriptorArray> DescriptorArray::Allocate(Isolate* isolate,
10699 int number_of_descriptors,
10700 int slack,
10701 PretenureFlag pretenure) {
10702 DCHECK_LE(0, number_of_descriptors);
10703 Factory* factory = isolate->factory();
10704 // Do not use DescriptorArray::cast on incomplete object.
10705 int size = number_of_descriptors + slack;
10706 if (size == 0) return factory->empty_descriptor_array();
10707 // Allocate the array of keys.
10708 Handle<WeakFixedArray> result =
10709 factory->NewWeakFixedArrayWithMap<DescriptorArray>(
10710 Heap::kDescriptorArrayMapRootIndex, LengthFor(size), pretenure);
10711 result->Set(kDescriptorLengthIndex,
10712 MaybeObject::FromObject(Smi::FromInt(number_of_descriptors)));
10713 result->Set(kEnumCacheIndex, MaybeObject::FromObject(
10714 ReadOnlyRoots(isolate).empty_enum_cache()));
10715 return Handle<DescriptorArray>::cast(result);
10716 }
10717
ClearEnumCache()10718 void DescriptorArray::ClearEnumCache() {
10719 set(kEnumCacheIndex,
10720 MaybeObject::FromObject(GetReadOnlyRoots().empty_enum_cache()));
10721 }
10722
Replace(int index,Descriptor * descriptor)10723 void DescriptorArray::Replace(int index, Descriptor* descriptor) {
10724 descriptor->SetSortedKeyIndex(GetSortedKeyIndex(index));
10725 Set(index, descriptor);
10726 }
10727
10728 // static
SetEnumCache(Handle<DescriptorArray> descriptors,Isolate * isolate,Handle<FixedArray> keys,Handle<FixedArray> indices)10729 void DescriptorArray::SetEnumCache(Handle<DescriptorArray> descriptors,
10730 Isolate* isolate, Handle<FixedArray> keys,
10731 Handle<FixedArray> indices) {
10732 EnumCache* enum_cache = descriptors->GetEnumCache();
10733 if (enum_cache == ReadOnlyRoots(isolate).empty_enum_cache()) {
10734 enum_cache = *isolate->factory()->NewEnumCache(keys, indices);
10735 descriptors->set(kEnumCacheIndex, MaybeObject::FromObject(enum_cache));
10736 } else {
10737 enum_cache->set_keys(*keys);
10738 enum_cache->set_indices(*indices);
10739 }
10740 }
10741
CopyFrom(int index,DescriptorArray * src)10742 void DescriptorArray::CopyFrom(int index, DescriptorArray* src) {
10743 PropertyDetails details = src->GetDetails(index);
10744 Set(index, src->GetKey(index), src->GetValue(index), details);
10745 }
10746
Sort()10747 void DescriptorArray::Sort() {
10748 // In-place heap sort.
10749 int len = number_of_descriptors();
10750 // Reset sorting since the descriptor array might contain invalid pointers.
10751 for (int i = 0; i < len; ++i) SetSortedKey(i, i);
10752 // Bottom-up max-heap construction.
10753 // Index of the last node with children
10754 const int max_parent_index = (len / 2) - 1;
10755 for (int i = max_parent_index; i >= 0; --i) {
10756 int parent_index = i;
10757 const uint32_t parent_hash = GetSortedKey(i)->Hash();
10758 while (parent_index <= max_parent_index) {
10759 int child_index = 2 * parent_index + 1;
10760 uint32_t child_hash = GetSortedKey(child_index)->Hash();
10761 if (child_index + 1 < len) {
10762 uint32_t right_child_hash = GetSortedKey(child_index + 1)->Hash();
10763 if (right_child_hash > child_hash) {
10764 child_index++;
10765 child_hash = right_child_hash;
10766 }
10767 }
10768 if (child_hash <= parent_hash) break;
10769 SwapSortedKeys(parent_index, child_index);
10770 // Now element at child_index could be < its children.
10771 parent_index = child_index; // parent_hash remains correct.
10772 }
10773 }
10774
10775 // Extract elements and create sorted array.
10776 for (int i = len - 1; i > 0; --i) {
10777 // Put max element at the back of the array.
10778 SwapSortedKeys(0, i);
10779 // Shift down the new top element.
10780 int parent_index = 0;
10781 const uint32_t parent_hash = GetSortedKey(parent_index)->Hash();
10782 const int max_parent_index = (i / 2) - 1;
10783 while (parent_index <= max_parent_index) {
10784 int child_index = parent_index * 2 + 1;
10785 uint32_t child_hash = GetSortedKey(child_index)->Hash();
10786 if (child_index + 1 < i) {
10787 uint32_t right_child_hash = GetSortedKey(child_index + 1)->Hash();
10788 if (right_child_hash > child_hash) {
10789 child_index++;
10790 child_hash = right_child_hash;
10791 }
10792 }
10793 if (child_hash <= parent_hash) break;
10794 SwapSortedKeys(parent_index, child_index);
10795 parent_index = child_index;
10796 }
10797 }
10798 DCHECK(IsSortedNoDuplicates());
10799 }
10800
Copy(Isolate * isolate,Handle<AccessorPair> pair)10801 Handle<AccessorPair> AccessorPair::Copy(Isolate* isolate,
10802 Handle<AccessorPair> pair) {
10803 Handle<AccessorPair> copy = isolate->factory()->NewAccessorPair();
10804 copy->set_getter(pair->getter());
10805 copy->set_setter(pair->setter());
10806 return copy;
10807 }
10808
GetComponent(Isolate * isolate,Handle<AccessorPair> accessor_pair,AccessorComponent component)10809 Handle<Object> AccessorPair::GetComponent(Isolate* isolate,
10810 Handle<AccessorPair> accessor_pair,
10811 AccessorComponent component) {
10812 Object* accessor = accessor_pair->get(component);
10813 if (accessor->IsFunctionTemplateInfo()) {
10814 return ApiNatives::InstantiateFunction(
10815 handle(FunctionTemplateInfo::cast(accessor), isolate))
10816 .ToHandleChecked();
10817 }
10818 if (accessor->IsNull(isolate)) {
10819 return isolate->factory()->undefined_value();
10820 }
10821 return handle(accessor, isolate);
10822 }
10823
New(Isolate * isolate,int deopt_entry_count,PretenureFlag pretenure)10824 Handle<DeoptimizationData> DeoptimizationData::New(Isolate* isolate,
10825 int deopt_entry_count,
10826 PretenureFlag pretenure) {
10827 return Handle<DeoptimizationData>::cast(isolate->factory()->NewFixedArray(
10828 LengthFor(deopt_entry_count), pretenure));
10829 }
10830
Empty(Isolate * isolate)10831 Handle<DeoptimizationData> DeoptimizationData::Empty(Isolate* isolate) {
10832 return Handle<DeoptimizationData>::cast(
10833 isolate->factory()->empty_fixed_array());
10834 }
10835
GetInlinedFunction(int index)10836 SharedFunctionInfo* DeoptimizationData::GetInlinedFunction(int index) {
10837 if (index == -1) {
10838 return SharedFunctionInfo::cast(SharedFunctionInfo());
10839 } else {
10840 return SharedFunctionInfo::cast(LiteralArray()->get(index));
10841 }
10842 }
10843
10844 #ifdef DEBUG
IsEqualTo(DescriptorArray * other)10845 bool DescriptorArray::IsEqualTo(DescriptorArray* other) {
10846 if (length() != other->length()) return false;
10847 for (int i = 0; i < length(); ++i) {
10848 if (get(i) != other->get(i)) return false;
10849 }
10850 return true;
10851 }
10852 #endif
10853
10854 // static
Trim(Isolate * isolate,Handle<String> string,TrimMode mode)10855 Handle<String> String::Trim(Isolate* isolate, Handle<String> string,
10856 TrimMode mode) {
10857 string = String::Flatten(isolate, string);
10858 int const length = string->length();
10859
10860 // Perform left trimming if requested.
10861 int left = 0;
10862 UnicodeCache* unicode_cache = isolate->unicode_cache();
10863 if (mode == kTrim || mode == kTrimStart) {
10864 while (left < length &&
10865 unicode_cache->IsWhiteSpaceOrLineTerminator(string->Get(left))) {
10866 left++;
10867 }
10868 }
10869
10870 // Perform right trimming if requested.
10871 int right = length;
10872 if (mode == kTrim || mode == kTrimEnd) {
10873 while (
10874 right > left &&
10875 unicode_cache->IsWhiteSpaceOrLineTerminator(string->Get(right - 1))) {
10876 right--;
10877 }
10878 }
10879
10880 return isolate->factory()->NewSubString(string, left, right);
10881 }
10882
LooksValid()10883 bool String::LooksValid() {
10884 // TODO(leszeks): Maybe remove this check entirely, Heap::Contains uses
10885 // basically the same logic as the way we access the heap in the first place.
10886 MemoryChunk* chunk = MemoryChunk::FromHeapObject(this);
10887 // RO_SPACE objects should always be valid.
10888 if (chunk->owner()->identity() == RO_SPACE) return true;
10889 if (chunk->heap() == nullptr) return false;
10890 return chunk->heap()->Contains(this);
10891 }
10892
10893 // static
ToFunctionName(Isolate * isolate,Handle<Name> name)10894 MaybeHandle<String> Name::ToFunctionName(Isolate* isolate, Handle<Name> name) {
10895 if (name->IsString()) return Handle<String>::cast(name);
10896 // ES6 section 9.2.11 SetFunctionName, step 4.
10897 Handle<Object> description(Handle<Symbol>::cast(name)->name(), isolate);
10898 if (description->IsUndefined(isolate)) {
10899 return isolate->factory()->empty_string();
10900 }
10901 IncrementalStringBuilder builder(isolate);
10902 builder.AppendCharacter('[');
10903 builder.AppendString(Handle<String>::cast(description));
10904 builder.AppendCharacter(']');
10905 return builder.Finish();
10906 }
10907
10908 // static
ToFunctionName(Isolate * isolate,Handle<Name> name,Handle<String> prefix)10909 MaybeHandle<String> Name::ToFunctionName(Isolate* isolate, Handle<Name> name,
10910 Handle<String> prefix) {
10911 Handle<String> name_string;
10912 ASSIGN_RETURN_ON_EXCEPTION(isolate, name_string,
10913 ToFunctionName(isolate, name), String);
10914 IncrementalStringBuilder builder(isolate);
10915 builder.AppendString(prefix);
10916 builder.AppendCharacter(' ');
10917 builder.AppendString(name_string);
10918 return builder.Finish();
10919 }
10920
10921 namespace {
10922
AreDigits(const uint8_t * s,int from,int to)10923 bool AreDigits(const uint8_t* s, int from, int to) {
10924 for (int i = from; i < to; i++) {
10925 if (s[i] < '0' || s[i] > '9') return false;
10926 }
10927
10928 return true;
10929 }
10930
10931
ParseDecimalInteger(const uint8_t * s,int from,int to)10932 int ParseDecimalInteger(const uint8_t* s, int from, int to) {
10933 DCHECK_LT(to - from, 10); // Overflow is not possible.
10934 DCHECK(from < to);
10935 int d = s[from] - '0';
10936
10937 for (int i = from + 1; i < to; i++) {
10938 d = 10 * d + (s[i] - '0');
10939 }
10940
10941 return d;
10942 }
10943
10944 } // namespace
10945
10946 // static
ToNumber(Isolate * isolate,Handle<String> subject)10947 Handle<Object> String::ToNumber(Isolate* isolate, Handle<String> subject) {
10948 // Flatten {subject} string first.
10949 subject = String::Flatten(isolate, subject);
10950
10951 // Fast array index case.
10952 uint32_t index;
10953 if (subject->AsArrayIndex(&index)) {
10954 return isolate->factory()->NewNumberFromUint(index);
10955 }
10956
10957 // Fast case: short integer or some sorts of junk values.
10958 if (subject->IsSeqOneByteString()) {
10959 int len = subject->length();
10960 if (len == 0) return handle(Smi::kZero, isolate);
10961
10962 DisallowHeapAllocation no_gc;
10963 uint8_t const* data = Handle<SeqOneByteString>::cast(subject)->GetChars();
10964 bool minus = (data[0] == '-');
10965 int start_pos = (minus ? 1 : 0);
10966
10967 if (start_pos == len) {
10968 return isolate->factory()->nan_value();
10969 } else if (data[start_pos] > '9') {
10970 // Fast check for a junk value. A valid string may start from a
10971 // whitespace, a sign ('+' or '-'), the decimal point, a decimal digit
10972 // or the 'I' character ('Infinity'). All of that have codes not greater
10973 // than '9' except 'I' and .
10974 if (data[start_pos] != 'I' && data[start_pos] != 0xA0) {
10975 return isolate->factory()->nan_value();
10976 }
10977 } else if (len - start_pos < 10 && AreDigits(data, start_pos, len)) {
10978 // The maximal/minimal smi has 10 digits. If the string has less digits
10979 // we know it will fit into the smi-data type.
10980 int d = ParseDecimalInteger(data, start_pos, len);
10981 if (minus) {
10982 if (d == 0) return isolate->factory()->minus_zero_value();
10983 d = -d;
10984 } else if (!subject->HasHashCode() && len <= String::kMaxArrayIndexSize &&
10985 (len == 1 || data[0] != '0')) {
10986 // String hash is not calculated yet but all the data are present.
10987 // Update the hash field to speed up sequential convertions.
10988 uint32_t hash = StringHasher::MakeArrayIndexHash(d, len);
10989 #ifdef DEBUG
10990 subject->Hash(); // Force hash calculation.
10991 DCHECK_EQ(static_cast<int>(subject->hash_field()),
10992 static_cast<int>(hash));
10993 #endif
10994 subject->set_hash_field(hash);
10995 }
10996 return handle(Smi::FromInt(d), isolate);
10997 }
10998 }
10999
11000 // Slower case.
11001 int flags = ALLOW_HEX | ALLOW_OCTAL | ALLOW_BINARY;
11002 return isolate->factory()->NewNumber(
11003 StringToDouble(isolate, isolate->unicode_cache(), subject, flags));
11004 }
11005
11006
GetFlatContent()11007 String::FlatContent String::GetFlatContent() {
11008 DCHECK(!AllowHeapAllocation::IsAllowed());
11009 int length = this->length();
11010 StringShape shape(this);
11011 String* string = this;
11012 int offset = 0;
11013 if (shape.representation_tag() == kConsStringTag) {
11014 ConsString* cons = ConsString::cast(string);
11015 if (cons->second()->length() != 0) {
11016 return FlatContent();
11017 }
11018 string = cons->first();
11019 shape = StringShape(string);
11020 } else if (shape.representation_tag() == kSlicedStringTag) {
11021 SlicedString* slice = SlicedString::cast(string);
11022 offset = slice->offset();
11023 string = slice->parent();
11024 shape = StringShape(string);
11025 DCHECK(shape.representation_tag() != kConsStringTag &&
11026 shape.representation_tag() != kSlicedStringTag);
11027 }
11028 if (shape.representation_tag() == kThinStringTag) {
11029 ThinString* thin = ThinString::cast(string);
11030 string = thin->actual();
11031 shape = StringShape(string);
11032 DCHECK(!shape.IsCons());
11033 DCHECK(!shape.IsSliced());
11034 }
11035 if (shape.encoding_tag() == kOneByteStringTag) {
11036 const uint8_t* start;
11037 if (shape.representation_tag() == kSeqStringTag) {
11038 start = SeqOneByteString::cast(string)->GetChars();
11039 } else {
11040 start = ExternalOneByteString::cast(string)->GetChars();
11041 }
11042 return FlatContent(start + offset, length);
11043 } else {
11044 DCHECK_EQ(shape.encoding_tag(), kTwoByteStringTag);
11045 const uc16* start;
11046 if (shape.representation_tag() == kSeqStringTag) {
11047 start = SeqTwoByteString::cast(string)->GetChars();
11048 } else {
11049 start = ExternalTwoByteString::cast(string)->GetChars();
11050 }
11051 return FlatContent(start + offset, length);
11052 }
11053 }
11054
ToCString(AllowNullsFlag allow_nulls,RobustnessFlag robust_flag,int offset,int length,int * length_return)11055 std::unique_ptr<char[]> String::ToCString(AllowNullsFlag allow_nulls,
11056 RobustnessFlag robust_flag,
11057 int offset, int length,
11058 int* length_return) {
11059 if (robust_flag == ROBUST_STRING_TRAVERSAL && !LooksValid()) {
11060 return std::unique_ptr<char[]>();
11061 }
11062 // Negative length means the to the end of the string.
11063 if (length < 0) length = kMaxInt - offset;
11064
11065 // Compute the size of the UTF-8 string. Start at the specified offset.
11066 StringCharacterStream stream(this, offset);
11067 int character_position = offset;
11068 int utf8_bytes = 0;
11069 int last = unibrow::Utf16::kNoPreviousCharacter;
11070 while (stream.HasMore() && character_position++ < offset + length) {
11071 uint16_t character = stream.GetNext();
11072 utf8_bytes += unibrow::Utf8::Length(character, last);
11073 last = character;
11074 }
11075
11076 if (length_return) {
11077 *length_return = utf8_bytes;
11078 }
11079
11080 char* result = NewArray<char>(utf8_bytes + 1);
11081
11082 // Convert the UTF-16 string to a UTF-8 buffer. Start at the specified offset.
11083 stream.Reset(this, offset);
11084 character_position = offset;
11085 int utf8_byte_position = 0;
11086 last = unibrow::Utf16::kNoPreviousCharacter;
11087 while (stream.HasMore() && character_position++ < offset + length) {
11088 uint16_t character = stream.GetNext();
11089 if (allow_nulls == DISALLOW_NULLS && character == 0) {
11090 character = ' ';
11091 }
11092 utf8_byte_position +=
11093 unibrow::Utf8::Encode(result + utf8_byte_position, character, last);
11094 last = character;
11095 }
11096 result[utf8_byte_position] = 0;
11097 return std::unique_ptr<char[]>(result);
11098 }
11099
ToCString(AllowNullsFlag allow_nulls,RobustnessFlag robust_flag,int * length_return)11100 std::unique_ptr<char[]> String::ToCString(AllowNullsFlag allow_nulls,
11101 RobustnessFlag robust_flag,
11102 int* length_return) {
11103 return ToCString(allow_nulls, robust_flag, 0, -1, length_return);
11104 }
11105
11106
GetTwoByteData(unsigned start)11107 const uc16* String::GetTwoByteData(unsigned start) {
11108 DCHECK(!IsOneByteRepresentationUnderneath());
11109 switch (StringShape(this).representation_tag()) {
11110 case kSeqStringTag:
11111 return SeqTwoByteString::cast(this)->SeqTwoByteStringGetData(start);
11112 case kExternalStringTag:
11113 return ExternalTwoByteString::cast(this)->
11114 ExternalTwoByteStringGetData(start);
11115 case kSlicedStringTag: {
11116 SlicedString* slice = SlicedString::cast(this);
11117 return slice->parent()->GetTwoByteData(start + slice->offset());
11118 }
11119 case kConsStringTag:
11120 case kThinStringTag:
11121 UNREACHABLE();
11122 }
11123 UNREACHABLE();
11124 }
11125
11126
SeqTwoByteStringGetData(unsigned start)11127 const uc16* SeqTwoByteString::SeqTwoByteStringGetData(unsigned start) {
11128 return reinterpret_cast<uc16*>(
11129 reinterpret_cast<char*>(this) - kHeapObjectTag + kHeaderSize) + start;
11130 }
11131
11132
PostGarbageCollectionProcessing(Isolate * isolate)11133 void Relocatable::PostGarbageCollectionProcessing(Isolate* isolate) {
11134 Relocatable* current = isolate->relocatable_top();
11135 while (current != nullptr) {
11136 current->PostGarbageCollection();
11137 current = current->prev_;
11138 }
11139 }
11140
11141
11142 // Reserve space for statics needing saving and restoring.
ArchiveSpacePerThread()11143 int Relocatable::ArchiveSpacePerThread() {
11144 return sizeof(Relocatable*); // NOLINT
11145 }
11146
11147
11148 // Archive statics that are thread-local.
ArchiveState(Isolate * isolate,char * to)11149 char* Relocatable::ArchiveState(Isolate* isolate, char* to) {
11150 *reinterpret_cast<Relocatable**>(to) = isolate->relocatable_top();
11151 isolate->set_relocatable_top(nullptr);
11152 return to + ArchiveSpacePerThread();
11153 }
11154
11155
11156 // Restore statics that are thread-local.
RestoreState(Isolate * isolate,char * from)11157 char* Relocatable::RestoreState(Isolate* isolate, char* from) {
11158 isolate->set_relocatable_top(*reinterpret_cast<Relocatable**>(from));
11159 return from + ArchiveSpacePerThread();
11160 }
11161
Iterate(RootVisitor * v,char * thread_storage)11162 char* Relocatable::Iterate(RootVisitor* v, char* thread_storage) {
11163 Relocatable* top = *reinterpret_cast<Relocatable**>(thread_storage);
11164 Iterate(v, top);
11165 return thread_storage + ArchiveSpacePerThread();
11166 }
11167
Iterate(Isolate * isolate,RootVisitor * v)11168 void Relocatable::Iterate(Isolate* isolate, RootVisitor* v) {
11169 Iterate(v, isolate->relocatable_top());
11170 }
11171
Iterate(RootVisitor * v,Relocatable * top)11172 void Relocatable::Iterate(RootVisitor* v, Relocatable* top) {
11173 Relocatable* current = top;
11174 while (current != nullptr) {
11175 current->IterateInstance(v);
11176 current = current->prev_;
11177 }
11178 }
11179
11180
FlatStringReader(Isolate * isolate,Handle<String> str)11181 FlatStringReader::FlatStringReader(Isolate* isolate, Handle<String> str)
11182 : Relocatable(isolate),
11183 str_(str.location()),
11184 length_(str->length()) {
11185 PostGarbageCollection();
11186 }
11187
11188
FlatStringReader(Isolate * isolate,Vector<const char> input)11189 FlatStringReader::FlatStringReader(Isolate* isolate, Vector<const char> input)
11190 : Relocatable(isolate),
11191 str_(0),
11192 is_one_byte_(true),
11193 length_(input.length()),
11194 start_(input.start()) {}
11195
11196
PostGarbageCollection()11197 void FlatStringReader::PostGarbageCollection() {
11198 if (str_ == nullptr) return;
11199 Handle<String> str(str_);
11200 DCHECK(str->IsFlat());
11201 DisallowHeapAllocation no_gc;
11202 // This does not actually prevent the vector from being relocated later.
11203 String::FlatContent content = str->GetFlatContent();
11204 DCHECK(content.IsFlat());
11205 is_one_byte_ = content.IsOneByte();
11206 if (is_one_byte_) {
11207 start_ = content.ToOneByteVector().start();
11208 } else {
11209 start_ = content.ToUC16Vector().start();
11210 }
11211 }
11212
11213
Initialize(ConsString * cons_string,int offset)11214 void ConsStringIterator::Initialize(ConsString* cons_string, int offset) {
11215 DCHECK_NOT_NULL(cons_string);
11216 root_ = cons_string;
11217 consumed_ = offset;
11218 // Force stack blown condition to trigger restart.
11219 depth_ = 1;
11220 maximum_depth_ = kStackSize + depth_;
11221 DCHECK(StackBlown());
11222 }
11223
11224
Continue(int * offset_out)11225 String* ConsStringIterator::Continue(int* offset_out) {
11226 DCHECK_NE(depth_, 0);
11227 DCHECK_EQ(0, *offset_out);
11228 bool blew_stack = StackBlown();
11229 String* string = nullptr;
11230 // Get the next leaf if there is one.
11231 if (!blew_stack) string = NextLeaf(&blew_stack);
11232 // Restart search from root.
11233 if (blew_stack) {
11234 DCHECK_NULL(string);
11235 string = Search(offset_out);
11236 }
11237 // Ensure future calls return null immediately.
11238 if (string == nullptr) Reset(nullptr);
11239 return string;
11240 }
11241
11242
Search(int * offset_out)11243 String* ConsStringIterator::Search(int* offset_out) {
11244 ConsString* cons_string = root_;
11245 // Reset the stack, pushing the root string.
11246 depth_ = 1;
11247 maximum_depth_ = 1;
11248 frames_[0] = cons_string;
11249 const int consumed = consumed_;
11250 int offset = 0;
11251 while (true) {
11252 // Loop until the string is found which contains the target offset.
11253 String* string = cons_string->first();
11254 int length = string->length();
11255 int32_t type;
11256 if (consumed < offset + length) {
11257 // Target offset is in the left branch.
11258 // Keep going if we're still in a ConString.
11259 type = string->map()->instance_type();
11260 if ((type & kStringRepresentationMask) == kConsStringTag) {
11261 cons_string = ConsString::cast(string);
11262 PushLeft(cons_string);
11263 continue;
11264 }
11265 // Tell the stack we're done descending.
11266 AdjustMaximumDepth();
11267 } else {
11268 // Descend right.
11269 // Update progress through the string.
11270 offset += length;
11271 // Keep going if we're still in a ConString.
11272 string = cons_string->second();
11273 type = string->map()->instance_type();
11274 if ((type & kStringRepresentationMask) == kConsStringTag) {
11275 cons_string = ConsString::cast(string);
11276 PushRight(cons_string);
11277 continue;
11278 }
11279 // Need this to be updated for the current string.
11280 length = string->length();
11281 // Account for the possibility of an empty right leaf.
11282 // This happens only if we have asked for an offset outside the string.
11283 if (length == 0) {
11284 // Reset so future operations will return null immediately.
11285 Reset(nullptr);
11286 return nullptr;
11287 }
11288 // Tell the stack we're done descending.
11289 AdjustMaximumDepth();
11290 // Pop stack so next iteration is in correct place.
11291 Pop();
11292 }
11293 DCHECK_NE(length, 0);
11294 // Adjust return values and exit.
11295 consumed_ = offset + length;
11296 *offset_out = consumed - offset;
11297 return string;
11298 }
11299 UNREACHABLE();
11300 }
11301
11302
NextLeaf(bool * blew_stack)11303 String* ConsStringIterator::NextLeaf(bool* blew_stack) {
11304 while (true) {
11305 // Tree traversal complete.
11306 if (depth_ == 0) {
11307 *blew_stack = false;
11308 return nullptr;
11309 }
11310 // We've lost track of higher nodes.
11311 if (StackBlown()) {
11312 *blew_stack = true;
11313 return nullptr;
11314 }
11315 // Go right.
11316 ConsString* cons_string = frames_[OffsetForDepth(depth_ - 1)];
11317 String* string = cons_string->second();
11318 int32_t type = string->map()->instance_type();
11319 if ((type & kStringRepresentationMask) != kConsStringTag) {
11320 // Pop stack so next iteration is in correct place.
11321 Pop();
11322 int length = string->length();
11323 // Could be a flattened ConsString.
11324 if (length == 0) continue;
11325 consumed_ += length;
11326 return string;
11327 }
11328 cons_string = ConsString::cast(string);
11329 PushRight(cons_string);
11330 // Need to traverse all the way left.
11331 while (true) {
11332 // Continue left.
11333 string = cons_string->first();
11334 type = string->map()->instance_type();
11335 if ((type & kStringRepresentationMask) != kConsStringTag) {
11336 AdjustMaximumDepth();
11337 int length = string->length();
11338 if (length == 0) break; // Skip empty left-hand sides of ConsStrings.
11339 consumed_ += length;
11340 return string;
11341 }
11342 cons_string = ConsString::cast(string);
11343 PushLeft(cons_string);
11344 }
11345 }
11346 UNREACHABLE();
11347 }
11348
11349
ConsStringGet(int index)11350 uint16_t ConsString::ConsStringGet(int index) {
11351 DCHECK(index >= 0 && index < this->length());
11352
11353 // Check for a flattened cons string
11354 if (second()->length() == 0) {
11355 String* left = first();
11356 return left->Get(index);
11357 }
11358
11359 String* string = String::cast(this);
11360
11361 while (true) {
11362 if (StringShape(string).IsCons()) {
11363 ConsString* cons_string = ConsString::cast(string);
11364 String* left = cons_string->first();
11365 if (left->length() > index) {
11366 string = left;
11367 } else {
11368 index -= left->length();
11369 string = cons_string->second();
11370 }
11371 } else {
11372 return string->Get(index);
11373 }
11374 }
11375
11376 UNREACHABLE();
11377 }
11378
ThinStringGet(int index)11379 uint16_t ThinString::ThinStringGet(int index) { return actual()->Get(index); }
11380
SlicedStringGet(int index)11381 uint16_t SlicedString::SlicedStringGet(int index) {
11382 return parent()->Get(offset() + index);
11383 }
11384
11385
11386 template <typename sinkchar>
WriteToFlat(String * src,sinkchar * sink,int f,int t)11387 void String::WriteToFlat(String* src,
11388 sinkchar* sink,
11389 int f,
11390 int t) {
11391 String* source = src;
11392 int from = f;
11393 int to = t;
11394 while (true) {
11395 DCHECK(0 <= from && from <= to && to <= source->length());
11396 switch (StringShape(source).full_representation_tag()) {
11397 case kOneByteStringTag | kExternalStringTag: {
11398 CopyChars(sink, ExternalOneByteString::cast(source)->GetChars() + from,
11399 to - from);
11400 return;
11401 }
11402 case kTwoByteStringTag | kExternalStringTag: {
11403 const uc16* data =
11404 ExternalTwoByteString::cast(source)->GetChars();
11405 CopyChars(sink,
11406 data + from,
11407 to - from);
11408 return;
11409 }
11410 case kOneByteStringTag | kSeqStringTag: {
11411 CopyChars(sink,
11412 SeqOneByteString::cast(source)->GetChars() + from,
11413 to - from);
11414 return;
11415 }
11416 case kTwoByteStringTag | kSeqStringTag: {
11417 CopyChars(sink,
11418 SeqTwoByteString::cast(source)->GetChars() + from,
11419 to - from);
11420 return;
11421 }
11422 case kOneByteStringTag | kConsStringTag:
11423 case kTwoByteStringTag | kConsStringTag: {
11424 ConsString* cons_string = ConsString::cast(source);
11425 String* first = cons_string->first();
11426 int boundary = first->length();
11427 if (to - boundary >= boundary - from) {
11428 // Right hand side is longer. Recurse over left.
11429 if (from < boundary) {
11430 WriteToFlat(first, sink, from, boundary);
11431 if (from == 0 && cons_string->second() == first) {
11432 CopyChars(sink + boundary, sink, boundary);
11433 return;
11434 }
11435 sink += boundary - from;
11436 from = 0;
11437 } else {
11438 from -= boundary;
11439 }
11440 to -= boundary;
11441 source = cons_string->second();
11442 } else {
11443 // Left hand side is longer. Recurse over right.
11444 if (to > boundary) {
11445 String* second = cons_string->second();
11446 // When repeatedly appending to a string, we get a cons string that
11447 // is unbalanced to the left, a list, essentially. We inline the
11448 // common case of sequential one-byte right child.
11449 if (to - boundary == 1) {
11450 sink[boundary - from] = static_cast<sinkchar>(second->Get(0));
11451 } else if (second->IsSeqOneByteString()) {
11452 CopyChars(sink + boundary - from,
11453 SeqOneByteString::cast(second)->GetChars(),
11454 to - boundary);
11455 } else {
11456 WriteToFlat(second,
11457 sink + boundary - from,
11458 0,
11459 to - boundary);
11460 }
11461 to = boundary;
11462 }
11463 source = first;
11464 }
11465 break;
11466 }
11467 case kOneByteStringTag | kSlicedStringTag:
11468 case kTwoByteStringTag | kSlicedStringTag: {
11469 SlicedString* slice = SlicedString::cast(source);
11470 unsigned offset = slice->offset();
11471 WriteToFlat(slice->parent(), sink, from + offset, to + offset);
11472 return;
11473 }
11474 case kOneByteStringTag | kThinStringTag:
11475 case kTwoByteStringTag | kThinStringTag:
11476 source = ThinString::cast(source)->actual();
11477 break;
11478 }
11479 }
11480 }
11481
11482 template <typename SourceChar>
CalculateLineEndsImpl(Isolate * isolate,std::vector<int> * line_ends,Vector<const SourceChar> src,bool include_ending_line)11483 static void CalculateLineEndsImpl(Isolate* isolate, std::vector<int>* line_ends,
11484 Vector<const SourceChar> src,
11485 bool include_ending_line) {
11486 const int src_len = src.length();
11487 UnicodeCache* cache = isolate->unicode_cache();
11488 for (int i = 0; i < src_len - 1; i++) {
11489 SourceChar current = src[i];
11490 SourceChar next = src[i + 1];
11491 if (cache->IsLineTerminatorSequence(current, next)) line_ends->push_back(i);
11492 }
11493
11494 if (src_len > 0 && cache->IsLineTerminatorSequence(src[src_len - 1], 0)) {
11495 line_ends->push_back(src_len - 1);
11496 }
11497 if (include_ending_line) {
11498 // Include one character beyond the end of script. The rewriter uses that
11499 // position for the implicit return statement.
11500 line_ends->push_back(src_len);
11501 }
11502 }
11503
CalculateLineEnds(Isolate * isolate,Handle<String> src,bool include_ending_line)11504 Handle<FixedArray> String::CalculateLineEnds(Isolate* isolate,
11505 Handle<String> src,
11506 bool include_ending_line) {
11507 src = Flatten(isolate, src);
11508 // Rough estimate of line count based on a roughly estimated average
11509 // length of (unpacked) code.
11510 int line_count_estimate = src->length() >> 4;
11511 std::vector<int> line_ends;
11512 line_ends.reserve(line_count_estimate);
11513 { DisallowHeapAllocation no_allocation; // ensure vectors stay valid.
11514 // Dispatch on type of strings.
11515 String::FlatContent content = src->GetFlatContent();
11516 DCHECK(content.IsFlat());
11517 if (content.IsOneByte()) {
11518 CalculateLineEndsImpl(isolate,
11519 &line_ends,
11520 content.ToOneByteVector(),
11521 include_ending_line);
11522 } else {
11523 CalculateLineEndsImpl(isolate,
11524 &line_ends,
11525 content.ToUC16Vector(),
11526 include_ending_line);
11527 }
11528 }
11529 int line_count = static_cast<int>(line_ends.size());
11530 Handle<FixedArray> array = isolate->factory()->NewFixedArray(line_count);
11531 for (int i = 0; i < line_count; i++) {
11532 array->set(i, Smi::FromInt(line_ends[i]));
11533 }
11534 return array;
11535 }
11536
11537
11538 // Compares the contents of two strings by reading and comparing
11539 // int-sized blocks of characters.
11540 template <typename Char>
CompareRawStringContents(const Char * const a,const Char * const b,int length)11541 static inline bool CompareRawStringContents(const Char* const a,
11542 const Char* const b,
11543 int length) {
11544 return CompareChars(a, b, length) == 0;
11545 }
11546
11547
11548 template<typename Chars1, typename Chars2>
11549 class RawStringComparator : public AllStatic {
11550 public:
compare(const Chars1 * a,const Chars2 * b,int len)11551 static inline bool compare(const Chars1* a, const Chars2* b, int len) {
11552 DCHECK(sizeof(Chars1) != sizeof(Chars2));
11553 for (int i = 0; i < len; i++) {
11554 if (a[i] != b[i]) {
11555 return false;
11556 }
11557 }
11558 return true;
11559 }
11560 };
11561
11562
11563 template<>
11564 class RawStringComparator<uint16_t, uint16_t> {
11565 public:
compare(const uint16_t * a,const uint16_t * b,int len)11566 static inline bool compare(const uint16_t* a, const uint16_t* b, int len) {
11567 return CompareRawStringContents(a, b, len);
11568 }
11569 };
11570
11571
11572 template<>
11573 class RawStringComparator<uint8_t, uint8_t> {
11574 public:
compare(const uint8_t * a,const uint8_t * b,int len)11575 static inline bool compare(const uint8_t* a, const uint8_t* b, int len) {
11576 return CompareRawStringContents(a, b, len);
11577 }
11578 };
11579
11580
11581 class StringComparator {
11582 class State {
11583 public:
State()11584 State() : is_one_byte_(true), length_(0), buffer8_(nullptr) {}
11585
Init(String * string)11586 void Init(String* string) {
11587 ConsString* cons_string = String::VisitFlat(this, string);
11588 iter_.Reset(cons_string);
11589 if (cons_string != nullptr) {
11590 int offset;
11591 string = iter_.Next(&offset);
11592 String::VisitFlat(this, string, offset);
11593 }
11594 }
11595
VisitOneByteString(const uint8_t * chars,int length)11596 inline void VisitOneByteString(const uint8_t* chars, int length) {
11597 is_one_byte_ = true;
11598 buffer8_ = chars;
11599 length_ = length;
11600 }
11601
VisitTwoByteString(const uint16_t * chars,int length)11602 inline void VisitTwoByteString(const uint16_t* chars, int length) {
11603 is_one_byte_ = false;
11604 buffer16_ = chars;
11605 length_ = length;
11606 }
11607
Advance(int consumed)11608 void Advance(int consumed) {
11609 DCHECK(consumed <= length_);
11610 // Still in buffer.
11611 if (length_ != consumed) {
11612 if (is_one_byte_) {
11613 buffer8_ += consumed;
11614 } else {
11615 buffer16_ += consumed;
11616 }
11617 length_ -= consumed;
11618 return;
11619 }
11620 // Advance state.
11621 int offset;
11622 String* next = iter_.Next(&offset);
11623 DCHECK_EQ(0, offset);
11624 DCHECK_NOT_NULL(next);
11625 String::VisitFlat(this, next);
11626 }
11627
11628 ConsStringIterator iter_;
11629 bool is_one_byte_;
11630 int length_;
11631 union {
11632 const uint8_t* buffer8_;
11633 const uint16_t* buffer16_;
11634 };
11635
11636 private:
11637 DISALLOW_COPY_AND_ASSIGN(State);
11638 };
11639
11640 public:
StringComparator()11641 inline StringComparator() {}
11642
11643 template<typename Chars1, typename Chars2>
Equals(State * state_1,State * state_2,int to_check)11644 static inline bool Equals(State* state_1, State* state_2, int to_check) {
11645 const Chars1* a = reinterpret_cast<const Chars1*>(state_1->buffer8_);
11646 const Chars2* b = reinterpret_cast<const Chars2*>(state_2->buffer8_);
11647 return RawStringComparator<Chars1, Chars2>::compare(a, b, to_check);
11648 }
11649
Equals(String * string_1,String * string_2)11650 bool Equals(String* string_1, String* string_2) {
11651 int length = string_1->length();
11652 state_1_.Init(string_1);
11653 state_2_.Init(string_2);
11654 while (true) {
11655 int to_check = Min(state_1_.length_, state_2_.length_);
11656 DCHECK(to_check > 0 && to_check <= length);
11657 bool is_equal;
11658 if (state_1_.is_one_byte_) {
11659 if (state_2_.is_one_byte_) {
11660 is_equal = Equals<uint8_t, uint8_t>(&state_1_, &state_2_, to_check);
11661 } else {
11662 is_equal = Equals<uint8_t, uint16_t>(&state_1_, &state_2_, to_check);
11663 }
11664 } else {
11665 if (state_2_.is_one_byte_) {
11666 is_equal = Equals<uint16_t, uint8_t>(&state_1_, &state_2_, to_check);
11667 } else {
11668 is_equal = Equals<uint16_t, uint16_t>(&state_1_, &state_2_, to_check);
11669 }
11670 }
11671 // Looping done.
11672 if (!is_equal) return false;
11673 length -= to_check;
11674 // Exit condition. Strings are equal.
11675 if (length == 0) return true;
11676 state_1_.Advance(to_check);
11677 state_2_.Advance(to_check);
11678 }
11679 }
11680
11681 private:
11682 State state_1_;
11683 State state_2_;
11684
11685 DISALLOW_COPY_AND_ASSIGN(StringComparator);
11686 };
11687
11688
SlowEquals(String * other)11689 bool String::SlowEquals(String* other) {
11690 DisallowHeapAllocation no_gc;
11691 // Fast check: negative check with lengths.
11692 int len = length();
11693 if (len != other->length()) return false;
11694 if (len == 0) return true;
11695
11696 // Fast check: if at least one ThinString is involved, dereference it/them
11697 // and restart.
11698 if (this->IsThinString() || other->IsThinString()) {
11699 if (other->IsThinString()) other = ThinString::cast(other)->actual();
11700 if (this->IsThinString()) {
11701 return ThinString::cast(this)->actual()->Equals(other);
11702 } else {
11703 return this->Equals(other);
11704 }
11705 }
11706
11707 // Fast check: if hash code is computed for both strings
11708 // a fast negative check can be performed.
11709 if (HasHashCode() && other->HasHashCode()) {
11710 #ifdef ENABLE_SLOW_DCHECKS
11711 if (FLAG_enable_slow_asserts) {
11712 if (Hash() != other->Hash()) {
11713 bool found_difference = false;
11714 for (int i = 0; i < len; i++) {
11715 if (Get(i) != other->Get(i)) {
11716 found_difference = true;
11717 break;
11718 }
11719 }
11720 DCHECK(found_difference);
11721 }
11722 }
11723 #endif
11724 if (Hash() != other->Hash()) return false;
11725 }
11726
11727 // We know the strings are both non-empty. Compare the first chars
11728 // before we try to flatten the strings.
11729 if (this->Get(0) != other->Get(0)) return false;
11730
11731 if (IsSeqOneByteString() && other->IsSeqOneByteString()) {
11732 const uint8_t* str1 = SeqOneByteString::cast(this)->GetChars();
11733 const uint8_t* str2 = SeqOneByteString::cast(other)->GetChars();
11734 return CompareRawStringContents(str1, str2, len);
11735 }
11736
11737 StringComparator comparator;
11738 return comparator.Equals(this, other);
11739 }
11740
SlowEquals(Isolate * isolate,Handle<String> one,Handle<String> two)11741 bool String::SlowEquals(Isolate* isolate, Handle<String> one,
11742 Handle<String> two) {
11743 // Fast check: negative check with lengths.
11744 int one_length = one->length();
11745 if (one_length != two->length()) return false;
11746 if (one_length == 0) return true;
11747
11748 // Fast check: if at least one ThinString is involved, dereference it/them
11749 // and restart.
11750 if (one->IsThinString() || two->IsThinString()) {
11751 if (one->IsThinString())
11752 one = handle(ThinString::cast(*one)->actual(), isolate);
11753 if (two->IsThinString())
11754 two = handle(ThinString::cast(*two)->actual(), isolate);
11755 return String::Equals(isolate, one, two);
11756 }
11757
11758 // Fast check: if hash code is computed for both strings
11759 // a fast negative check can be performed.
11760 if (one->HasHashCode() && two->HasHashCode()) {
11761 #ifdef ENABLE_SLOW_DCHECKS
11762 if (FLAG_enable_slow_asserts) {
11763 if (one->Hash() != two->Hash()) {
11764 bool found_difference = false;
11765 for (int i = 0; i < one_length; i++) {
11766 if (one->Get(i) != two->Get(i)) {
11767 found_difference = true;
11768 break;
11769 }
11770 }
11771 DCHECK(found_difference);
11772 }
11773 }
11774 #endif
11775 if (one->Hash() != two->Hash()) return false;
11776 }
11777
11778 // We know the strings are both non-empty. Compare the first chars
11779 // before we try to flatten the strings.
11780 if (one->Get(0) != two->Get(0)) return false;
11781
11782 one = String::Flatten(isolate, one);
11783 two = String::Flatten(isolate, two);
11784
11785 DisallowHeapAllocation no_gc;
11786 String::FlatContent flat1 = one->GetFlatContent();
11787 String::FlatContent flat2 = two->GetFlatContent();
11788
11789 if (flat1.IsOneByte() && flat2.IsOneByte()) {
11790 return CompareRawStringContents(flat1.ToOneByteVector().start(),
11791 flat2.ToOneByteVector().start(),
11792 one_length);
11793 } else {
11794 for (int i = 0; i < one_length; i++) {
11795 if (flat1.Get(i) != flat2.Get(i)) return false;
11796 }
11797 return true;
11798 }
11799 }
11800
11801
11802 // static
Compare(Isolate * isolate,Handle<String> x,Handle<String> y)11803 ComparisonResult String::Compare(Isolate* isolate, Handle<String> x,
11804 Handle<String> y) {
11805 // A few fast case tests before we flatten.
11806 if (x.is_identical_to(y)) {
11807 return ComparisonResult::kEqual;
11808 } else if (y->length() == 0) {
11809 return x->length() == 0 ? ComparisonResult::kEqual
11810 : ComparisonResult::kGreaterThan;
11811 } else if (x->length() == 0) {
11812 return ComparisonResult::kLessThan;
11813 }
11814
11815 int const d = x->Get(0) - y->Get(0);
11816 if (d < 0) {
11817 return ComparisonResult::kLessThan;
11818 } else if (d > 0) {
11819 return ComparisonResult::kGreaterThan;
11820 }
11821
11822 // Slow case.
11823 x = String::Flatten(isolate, x);
11824 y = String::Flatten(isolate, y);
11825
11826 DisallowHeapAllocation no_gc;
11827 ComparisonResult result = ComparisonResult::kEqual;
11828 int prefix_length = x->length();
11829 if (y->length() < prefix_length) {
11830 prefix_length = y->length();
11831 result = ComparisonResult::kGreaterThan;
11832 } else if (y->length() > prefix_length) {
11833 result = ComparisonResult::kLessThan;
11834 }
11835 int r;
11836 String::FlatContent x_content = x->GetFlatContent();
11837 String::FlatContent y_content = y->GetFlatContent();
11838 if (x_content.IsOneByte()) {
11839 Vector<const uint8_t> x_chars = x_content.ToOneByteVector();
11840 if (y_content.IsOneByte()) {
11841 Vector<const uint8_t> y_chars = y_content.ToOneByteVector();
11842 r = CompareChars(x_chars.start(), y_chars.start(), prefix_length);
11843 } else {
11844 Vector<const uc16> y_chars = y_content.ToUC16Vector();
11845 r = CompareChars(x_chars.start(), y_chars.start(), prefix_length);
11846 }
11847 } else {
11848 Vector<const uc16> x_chars = x_content.ToUC16Vector();
11849 if (y_content.IsOneByte()) {
11850 Vector<const uint8_t> y_chars = y_content.ToOneByteVector();
11851 r = CompareChars(x_chars.start(), y_chars.start(), prefix_length);
11852 } else {
11853 Vector<const uc16> y_chars = y_content.ToUC16Vector();
11854 r = CompareChars(x_chars.start(), y_chars.start(), prefix_length);
11855 }
11856 }
11857 if (r < 0) {
11858 result = ComparisonResult::kLessThan;
11859 } else if (r > 0) {
11860 result = ComparisonResult::kGreaterThan;
11861 }
11862 return result;
11863 }
11864
IndexOf(Isolate * isolate,Handle<Object> receiver,Handle<Object> search,Handle<Object> position)11865 Object* String::IndexOf(Isolate* isolate, Handle<Object> receiver,
11866 Handle<Object> search, Handle<Object> position) {
11867 if (receiver->IsNullOrUndefined(isolate)) {
11868 THROW_NEW_ERROR_RETURN_FAILURE(
11869 isolate, NewTypeError(MessageTemplate::kCalledOnNullOrUndefined,
11870 isolate->factory()->NewStringFromAsciiChecked(
11871 "String.prototype.indexOf")));
11872 }
11873 Handle<String> receiver_string;
11874 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, receiver_string,
11875 Object::ToString(isolate, receiver));
11876
11877 Handle<String> search_string;
11878 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, search_string,
11879 Object::ToString(isolate, search));
11880
11881 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, position,
11882 Object::ToInteger(isolate, position));
11883
11884 uint32_t index = receiver_string->ToValidIndex(*position);
11885 return Smi::FromInt(
11886 String::IndexOf(isolate, receiver_string, search_string, index));
11887 }
11888
11889 namespace {
11890
11891 template <typename T>
SearchString(Isolate * isolate,String::FlatContent receiver_content,Vector<T> pat_vector,int start_index)11892 int SearchString(Isolate* isolate, String::FlatContent receiver_content,
11893 Vector<T> pat_vector, int start_index) {
11894 if (receiver_content.IsOneByte()) {
11895 return SearchString(isolate, receiver_content.ToOneByteVector(), pat_vector,
11896 start_index);
11897 }
11898 return SearchString(isolate, receiver_content.ToUC16Vector(), pat_vector,
11899 start_index);
11900 }
11901
11902 } // namespace
11903
IndexOf(Isolate * isolate,Handle<String> receiver,Handle<String> search,int start_index)11904 int String::IndexOf(Isolate* isolate, Handle<String> receiver,
11905 Handle<String> search, int start_index) {
11906 DCHECK_LE(0, start_index);
11907 DCHECK(start_index <= receiver->length());
11908
11909 uint32_t search_length = search->length();
11910 if (search_length == 0) return start_index;
11911
11912 uint32_t receiver_length = receiver->length();
11913 if (start_index + search_length > receiver_length) return -1;
11914
11915 receiver = String::Flatten(isolate, receiver);
11916 search = String::Flatten(isolate, search);
11917
11918 DisallowHeapAllocation no_gc; // ensure vectors stay valid
11919 // Extract flattened substrings of cons strings before getting encoding.
11920 String::FlatContent receiver_content = receiver->GetFlatContent();
11921 String::FlatContent search_content = search->GetFlatContent();
11922
11923 // dispatch on type of strings
11924 if (search_content.IsOneByte()) {
11925 Vector<const uint8_t> pat_vector = search_content.ToOneByteVector();
11926 return SearchString<const uint8_t>(isolate, receiver_content, pat_vector,
11927 start_index);
11928 }
11929 Vector<const uc16> pat_vector = search_content.ToUC16Vector();
11930 return SearchString<const uc16>(isolate, receiver_content, pat_vector,
11931 start_index);
11932 }
11933
GetSubstitution(Isolate * isolate,Match * match,Handle<String> replacement,int start_index)11934 MaybeHandle<String> String::GetSubstitution(Isolate* isolate, Match* match,
11935 Handle<String> replacement,
11936 int start_index) {
11937 DCHECK_GE(start_index, 0);
11938
11939 Factory* factory = isolate->factory();
11940
11941 const int replacement_length = replacement->length();
11942 const int captures_length = match->CaptureCount();
11943
11944 replacement = String::Flatten(isolate, replacement);
11945
11946 Handle<String> dollar_string =
11947 factory->LookupSingleCharacterStringFromCode('$');
11948 int next_dollar_ix =
11949 String::IndexOf(isolate, replacement, dollar_string, start_index);
11950 if (next_dollar_ix < 0) {
11951 return replacement;
11952 }
11953
11954 IncrementalStringBuilder builder(isolate);
11955
11956 if (next_dollar_ix > 0) {
11957 builder.AppendString(factory->NewSubString(replacement, 0, next_dollar_ix));
11958 }
11959
11960 while (true) {
11961 const int peek_ix = next_dollar_ix + 1;
11962 if (peek_ix >= replacement_length) {
11963 builder.AppendCharacter('$');
11964 return builder.Finish();
11965 }
11966
11967 int continue_from_ix = -1;
11968 const uint16_t peek = replacement->Get(peek_ix);
11969 switch (peek) {
11970 case '$': // $$
11971 builder.AppendCharacter('$');
11972 continue_from_ix = peek_ix + 1;
11973 break;
11974 case '&': // $& - match
11975 builder.AppendString(match->GetMatch());
11976 continue_from_ix = peek_ix + 1;
11977 break;
11978 case '`': // $` - prefix
11979 builder.AppendString(match->GetPrefix());
11980 continue_from_ix = peek_ix + 1;
11981 break;
11982 case '\'': // $' - suffix
11983 builder.AppendString(match->GetSuffix());
11984 continue_from_ix = peek_ix + 1;
11985 break;
11986 case '0':
11987 case '1':
11988 case '2':
11989 case '3':
11990 case '4':
11991 case '5':
11992 case '6':
11993 case '7':
11994 case '8':
11995 case '9': {
11996 // Valid indices are $1 .. $9, $01 .. $09 and $10 .. $99
11997 int scaled_index = (peek - '0');
11998 int advance = 1;
11999
12000 if (peek_ix + 1 < replacement_length) {
12001 const uint16_t next_peek = replacement->Get(peek_ix + 1);
12002 if (next_peek >= '0' && next_peek <= '9') {
12003 const int new_scaled_index = scaled_index * 10 + (next_peek - '0');
12004 if (new_scaled_index < captures_length) {
12005 scaled_index = new_scaled_index;
12006 advance = 2;
12007 }
12008 }
12009 }
12010
12011 if (scaled_index == 0 || scaled_index >= captures_length) {
12012 builder.AppendCharacter('$');
12013 continue_from_ix = peek_ix;
12014 break;
12015 }
12016
12017 bool capture_exists;
12018 Handle<String> capture;
12019 ASSIGN_RETURN_ON_EXCEPTION(
12020 isolate, capture, match->GetCapture(scaled_index, &capture_exists),
12021 String);
12022 if (capture_exists) builder.AppendString(capture);
12023 continue_from_ix = peek_ix + advance;
12024 break;
12025 }
12026 case '<': { // $<name> - named capture
12027 typedef String::Match::CaptureState CaptureState;
12028
12029 if (!match->HasNamedCaptures()) {
12030 builder.AppendCharacter('$');
12031 continue_from_ix = peek_ix;
12032 break;
12033 }
12034
12035 Handle<String> bracket_string =
12036 factory->LookupSingleCharacterStringFromCode('>');
12037 const int closing_bracket_ix =
12038 String::IndexOf(isolate, replacement, bracket_string, peek_ix + 1);
12039
12040 if (closing_bracket_ix == -1) {
12041 // No closing bracket was found, treat '$<' as a string literal.
12042 builder.AppendCharacter('$');
12043 continue_from_ix = peek_ix;
12044 break;
12045 }
12046
12047 Handle<String> capture_name =
12048 factory->NewSubString(replacement, peek_ix + 1, closing_bracket_ix);
12049 Handle<String> capture;
12050 CaptureState capture_state;
12051 ASSIGN_RETURN_ON_EXCEPTION(
12052 isolate, capture,
12053 match->GetNamedCapture(capture_name, &capture_state), String);
12054
12055 switch (capture_state) {
12056 case CaptureState::INVALID:
12057 case CaptureState::UNMATCHED:
12058 break;
12059 case CaptureState::MATCHED:
12060 builder.AppendString(capture);
12061 break;
12062 }
12063
12064 continue_from_ix = closing_bracket_ix + 1;
12065 break;
12066 }
12067 default:
12068 builder.AppendCharacter('$');
12069 continue_from_ix = peek_ix;
12070 break;
12071 }
12072
12073 // Go the the next $ in the replacement.
12074 // TODO(jgruber): Single-char lookups could be much more efficient.
12075 DCHECK_NE(continue_from_ix, -1);
12076 next_dollar_ix =
12077 String::IndexOf(isolate, replacement, dollar_string, continue_from_ix);
12078
12079 // Return if there are no more $ characters in the replacement. If we
12080 // haven't reached the end, we need to append the suffix.
12081 if (next_dollar_ix < 0) {
12082 if (continue_from_ix < replacement_length) {
12083 builder.AppendString(factory->NewSubString(
12084 replacement, continue_from_ix, replacement_length));
12085 }
12086 return builder.Finish();
12087 }
12088
12089 // Append substring between the previous and the next $ character.
12090 if (next_dollar_ix > continue_from_ix) {
12091 builder.AppendString(
12092 factory->NewSubString(replacement, continue_from_ix, next_dollar_ix));
12093 }
12094 }
12095
12096 UNREACHABLE();
12097 }
12098
12099 namespace { // for String.Prototype.lastIndexOf
12100
12101 template <typename schar, typename pchar>
StringMatchBackwards(Vector<const schar> subject,Vector<const pchar> pattern,int idx)12102 int StringMatchBackwards(Vector<const schar> subject,
12103 Vector<const pchar> pattern, int idx) {
12104 int pattern_length = pattern.length();
12105 DCHECK_GE(pattern_length, 1);
12106 DCHECK(idx + pattern_length <= subject.length());
12107
12108 if (sizeof(schar) == 1 && sizeof(pchar) > 1) {
12109 for (int i = 0; i < pattern_length; i++) {
12110 uc16 c = pattern[i];
12111 if (c > String::kMaxOneByteCharCode) {
12112 return -1;
12113 }
12114 }
12115 }
12116
12117 pchar pattern_first_char = pattern[0];
12118 for (int i = idx; i >= 0; i--) {
12119 if (subject[i] != pattern_first_char) continue;
12120 int j = 1;
12121 while (j < pattern_length) {
12122 if (pattern[j] != subject[i + j]) {
12123 break;
12124 }
12125 j++;
12126 }
12127 if (j == pattern_length) {
12128 return i;
12129 }
12130 }
12131 return -1;
12132 }
12133
12134 } // namespace
12135
LastIndexOf(Isolate * isolate,Handle<Object> receiver,Handle<Object> search,Handle<Object> position)12136 Object* String::LastIndexOf(Isolate* isolate, Handle<Object> receiver,
12137 Handle<Object> search, Handle<Object> position) {
12138 if (receiver->IsNullOrUndefined(isolate)) {
12139 THROW_NEW_ERROR_RETURN_FAILURE(
12140 isolate, NewTypeError(MessageTemplate::kCalledOnNullOrUndefined,
12141 isolate->factory()->NewStringFromAsciiChecked(
12142 "String.prototype.lastIndexOf")));
12143 }
12144 Handle<String> receiver_string;
12145 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, receiver_string,
12146 Object::ToString(isolate, receiver));
12147
12148 Handle<String> search_string;
12149 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, search_string,
12150 Object::ToString(isolate, search));
12151
12152 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, position,
12153 Object::ToNumber(isolate, position));
12154
12155 uint32_t start_index;
12156
12157 if (position->IsNaN()) {
12158 start_index = receiver_string->length();
12159 } else {
12160 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, position,
12161 Object::ToInteger(isolate, position));
12162 start_index = receiver_string->ToValidIndex(*position);
12163 }
12164
12165 uint32_t pattern_length = search_string->length();
12166 uint32_t receiver_length = receiver_string->length();
12167
12168 if (start_index + pattern_length > receiver_length) {
12169 start_index = receiver_length - pattern_length;
12170 }
12171
12172 if (pattern_length == 0) {
12173 return Smi::FromInt(start_index);
12174 }
12175
12176 receiver_string = String::Flatten(isolate, receiver_string);
12177 search_string = String::Flatten(isolate, search_string);
12178
12179 int last_index = -1;
12180 DisallowHeapAllocation no_gc; // ensure vectors stay valid
12181
12182 String::FlatContent receiver_content = receiver_string->GetFlatContent();
12183 String::FlatContent search_content = search_string->GetFlatContent();
12184
12185 if (search_content.IsOneByte()) {
12186 Vector<const uint8_t> pat_vector = search_content.ToOneByteVector();
12187 if (receiver_content.IsOneByte()) {
12188 last_index = StringMatchBackwards(receiver_content.ToOneByteVector(),
12189 pat_vector, start_index);
12190 } else {
12191 last_index = StringMatchBackwards(receiver_content.ToUC16Vector(),
12192 pat_vector, start_index);
12193 }
12194 } else {
12195 Vector<const uc16> pat_vector = search_content.ToUC16Vector();
12196 if (receiver_content.IsOneByte()) {
12197 last_index = StringMatchBackwards(receiver_content.ToOneByteVector(),
12198 pat_vector, start_index);
12199 } else {
12200 last_index = StringMatchBackwards(receiver_content.ToUC16Vector(),
12201 pat_vector, start_index);
12202 }
12203 }
12204 return Smi::FromInt(last_index);
12205 }
12206
IsUtf8EqualTo(Vector<const char> str,bool allow_prefix_match)12207 bool String::IsUtf8EqualTo(Vector<const char> str, bool allow_prefix_match) {
12208 int slen = length();
12209 // Can't check exact length equality, but we can check bounds.
12210 int str_len = str.length();
12211 if (!allow_prefix_match &&
12212 (str_len < slen ||
12213 str_len > slen*static_cast<int>(unibrow::Utf8::kMaxEncodedSize))) {
12214 return false;
12215 }
12216
12217 int i = 0;
12218 unibrow::Utf8Iterator it = unibrow::Utf8Iterator(str);
12219 while (i < slen && !it.Done()) {
12220 if (Get(i++) != *it) return false;
12221 ++it;
12222 }
12223
12224 return (allow_prefix_match || i == slen) && it.Done();
12225 }
12226
12227 template <>
IsEqualTo(Vector<const uint8_t> str)12228 bool String::IsEqualTo(Vector<const uint8_t> str) {
12229 return IsOneByteEqualTo(str);
12230 }
12231
12232 template <>
IsEqualTo(Vector<const uc16> str)12233 bool String::IsEqualTo(Vector<const uc16> str) {
12234 return IsTwoByteEqualTo(str);
12235 }
12236
IsOneByteEqualTo(Vector<const uint8_t> str)12237 bool String::IsOneByteEqualTo(Vector<const uint8_t> str) {
12238 int slen = length();
12239 if (str.length() != slen) return false;
12240 DisallowHeapAllocation no_gc;
12241 FlatContent content = GetFlatContent();
12242 if (content.IsOneByte()) {
12243 return CompareChars(content.ToOneByteVector().start(),
12244 str.start(), slen) == 0;
12245 }
12246 for (int i = 0; i < slen; i++) {
12247 if (Get(i) != static_cast<uint16_t>(str[i])) return false;
12248 }
12249 return true;
12250 }
12251
12252
IsTwoByteEqualTo(Vector<const uc16> str)12253 bool String::IsTwoByteEqualTo(Vector<const uc16> str) {
12254 int slen = length();
12255 if (str.length() != slen) return false;
12256 DisallowHeapAllocation no_gc;
12257 FlatContent content = GetFlatContent();
12258 if (content.IsTwoByte()) {
12259 return CompareChars(content.ToUC16Vector().start(), str.start(), slen) == 0;
12260 }
12261 for (int i = 0; i < slen; i++) {
12262 if (Get(i) != str[i]) return false;
12263 }
12264 return true;
12265 }
12266
ComputeAndSetHash(Isolate * isolate)12267 uint32_t String::ComputeAndSetHash(Isolate* isolate) {
12268 // Should only be called if hash code has not yet been computed.
12269 DCHECK(!HasHashCode());
12270
12271 // Store the hash code in the object.
12272 uint32_t field =
12273 IteratingStringHasher::Hash(this, isolate->heap()->HashSeed());
12274 set_hash_field(field);
12275
12276 // Check the hash code is there.
12277 DCHECK(HasHashCode());
12278 uint32_t result = field >> kHashShift;
12279 DCHECK_NE(result, 0); // Ensure that the hash value of 0 is never computed.
12280 return result;
12281 }
12282
12283
ComputeArrayIndex(uint32_t * index)12284 bool String::ComputeArrayIndex(uint32_t* index) {
12285 int length = this->length();
12286 if (length == 0 || length > kMaxArrayIndexSize) return false;
12287 StringCharacterStream stream(this);
12288 return StringToArrayIndex(&stream, index);
12289 }
12290
12291
SlowAsArrayIndex(uint32_t * index)12292 bool String::SlowAsArrayIndex(uint32_t* index) {
12293 if (length() <= kMaxCachedArrayIndexLength) {
12294 Hash(); // force computation of hash code
12295 uint32_t field = hash_field();
12296 if ((field & kIsNotArrayIndexMask) != 0) return false;
12297 // Isolate the array index form the full hash field.
12298 *index = ArrayIndexValueBits::decode(field);
12299 return true;
12300 } else {
12301 return ComputeArrayIndex(index);
12302 }
12303 }
12304
12305
Truncate(Handle<SeqString> string,int new_length)12306 Handle<String> SeqString::Truncate(Handle<SeqString> string, int new_length) {
12307 if (new_length == 0) return string->GetReadOnlyRoots().empty_string_handle();
12308
12309 int new_size, old_size;
12310 int old_length = string->length();
12311 if (old_length <= new_length) return string;
12312
12313 if (string->IsSeqOneByteString()) {
12314 old_size = SeqOneByteString::SizeFor(old_length);
12315 new_size = SeqOneByteString::SizeFor(new_length);
12316 } else {
12317 DCHECK(string->IsSeqTwoByteString());
12318 old_size = SeqTwoByteString::SizeFor(old_length);
12319 new_size = SeqTwoByteString::SizeFor(new_length);
12320 }
12321
12322 int delta = old_size - new_size;
12323
12324 Address start_of_string = string->address();
12325 DCHECK_OBJECT_ALIGNED(start_of_string);
12326 DCHECK_OBJECT_ALIGNED(start_of_string + new_size);
12327
12328 Heap* heap = Heap::FromWritableHeapObject(*string);
12329 // Sizes are pointer size aligned, so that we can use filler objects
12330 // that are a multiple of pointer size.
12331 heap->CreateFillerObjectAt(start_of_string + new_size, delta,
12332 ClearRecordedSlots::kNo);
12333 // We are storing the new length using release store after creating a filler
12334 // for the left-over space to avoid races with the sweeper thread.
12335 string->synchronized_set_length(new_length);
12336
12337 return string;
12338 }
12339
clear_padding()12340 void SeqOneByteString::clear_padding() {
12341 int data_size = SeqString::kHeaderSize + length() * kOneByteSize;
12342 memset(reinterpret_cast<void*>(address() + data_size), 0,
12343 SizeFor(length()) - data_size);
12344 }
12345
clear_padding()12346 void SeqTwoByteString::clear_padding() {
12347 int data_size = SeqString::kHeaderSize + length() * kUC16Size;
12348 memset(reinterpret_cast<void*>(address() + data_size), 0,
12349 SizeFor(length()) - data_size);
12350 }
12351
ExternalPayloadSize() const12352 int ExternalString::ExternalPayloadSize() const {
12353 int length_multiplier = IsTwoByteRepresentation() ? i::kShortSize : kCharSize;
12354 return length() * length_multiplier;
12355 }
12356
MakeArrayIndexHash(uint32_t value,int length)12357 uint32_t StringHasher::MakeArrayIndexHash(uint32_t value, int length) {
12358 // For array indexes mix the length into the hash as an array index could
12359 // be zero.
12360 DCHECK_GT(length, 0);
12361 DCHECK_LE(length, String::kMaxArrayIndexSize);
12362 DCHECK(TenToThe(String::kMaxCachedArrayIndexLength) <
12363 (1 << String::kArrayIndexValueBits));
12364
12365 value <<= String::ArrayIndexValueBits::kShift;
12366 value |= length << String::ArrayIndexLengthBits::kShift;
12367
12368 DCHECK_EQ(value & String::kIsNotArrayIndexMask, 0);
12369 DCHECK_EQ(length <= String::kMaxCachedArrayIndexLength,
12370 Name::ContainsCachedArrayIndex(value));
12371 return value;
12372 }
12373
12374
GetHashField()12375 uint32_t StringHasher::GetHashField() {
12376 if (length_ <= String::kMaxHashCalcLength) {
12377 if (is_array_index_) {
12378 return MakeArrayIndexHash(array_index_, length_);
12379 }
12380 return (GetHashCore(raw_running_hash_) << String::kHashShift) |
12381 String::kIsNotArrayIndexMask;
12382 } else {
12383 return (length_ << String::kHashShift) | String::kIsNotArrayIndexMask;
12384 }
12385 }
12386
ComputeUtf8Hash(Vector<const char> chars,uint64_t seed,int * utf16_length_out)12387 uint32_t StringHasher::ComputeUtf8Hash(Vector<const char> chars, uint64_t seed,
12388 int* utf16_length_out) {
12389 int vector_length = chars.length();
12390 // Handle some edge cases
12391 if (vector_length <= 1) {
12392 DCHECK(vector_length == 0 ||
12393 static_cast<uint8_t>(chars.start()[0]) <=
12394 unibrow::Utf8::kMaxOneByteChar);
12395 *utf16_length_out = vector_length;
12396 return HashSequentialString(chars.start(), vector_length, seed);
12397 }
12398
12399 // Start with a fake length which won't affect computation.
12400 // It will be updated later.
12401 StringHasher hasher(String::kMaxArrayIndexSize, seed);
12402 DCHECK(hasher.is_array_index_);
12403
12404 unibrow::Utf8Iterator it = unibrow::Utf8Iterator(chars);
12405 int utf16_length = 0;
12406 bool is_index = true;
12407
12408 while (utf16_length < String::kMaxHashCalcLength && !it.Done()) {
12409 utf16_length++;
12410 uint16_t c = *it;
12411 ++it;
12412 hasher.AddCharacter(c);
12413 if (is_index) is_index = hasher.UpdateIndex(c);
12414 }
12415
12416 // Now that hashing is done, we just need to calculate utf16_length
12417 while (!it.Done()) {
12418 ++it;
12419 utf16_length++;
12420 }
12421
12422 *utf16_length_out = utf16_length;
12423 // Must set length here so that hash computation is correct.
12424 hasher.length_ = utf16_length;
12425 return hasher.GetHashField();
12426 }
12427
12428
VisitConsString(ConsString * cons_string)12429 void IteratingStringHasher::VisitConsString(ConsString* cons_string) {
12430 // Run small ConsStrings through ConsStringIterator.
12431 if (cons_string->length() < 64) {
12432 ConsStringIterator iter(cons_string);
12433 int offset;
12434 String* string;
12435 while (nullptr != (string = iter.Next(&offset))) {
12436 DCHECK_EQ(0, offset);
12437 String::VisitFlat(this, string, 0);
12438 }
12439 return;
12440 }
12441 // Slow case.
12442 const int max_length = String::kMaxHashCalcLength;
12443 int length = std::min(cons_string->length(), max_length);
12444 if (cons_string->HasOnlyOneByteChars()) {
12445 uint8_t* buffer = new uint8_t[length];
12446 String::WriteToFlat(cons_string, buffer, 0, length);
12447 AddCharacters(buffer, length);
12448 delete[] buffer;
12449 } else {
12450 uint16_t* buffer = new uint16_t[length];
12451 String::WriteToFlat(cons_string, buffer, 0, length);
12452 AddCharacters(buffer, length);
12453 delete[] buffer;
12454 }
12455 }
12456
12457
PrintOn(FILE * file)12458 void String::PrintOn(FILE* file) {
12459 int length = this->length();
12460 for (int i = 0; i < length; i++) {
12461 PrintF(file, "%c", Get(i));
12462 }
12463 }
12464
12465
Hash()12466 int Map::Hash() {
12467 // For performance reasons we only hash the 3 most variable fields of a map:
12468 // constructor, prototype and bit_field2. For predictability reasons we
12469 // use objects' offsets in respective pages for hashing instead of raw
12470 // addresses.
12471
12472 // Shift away the tag.
12473 int hash = ObjectAddressForHashing(GetConstructor()) >> 2;
12474
12475 // XOR-ing the prototype and constructor directly yields too many zero bits
12476 // when the two pointers are close (which is fairly common).
12477 // To avoid this we shift the prototype bits relatively to the constructor.
12478 hash ^= ObjectAddressForHashing(prototype()) << (32 - kPageSizeBits);
12479
12480 return hash ^ (hash >> 16) ^ bit_field2();
12481 }
12482
12483
12484 namespace {
12485
CheckEquivalent(const Map * first,const Map * second)12486 bool CheckEquivalent(const Map* first, const Map* second) {
12487 return first->GetConstructor() == second->GetConstructor() &&
12488 first->prototype() == second->prototype() &&
12489 first->instance_type() == second->instance_type() &&
12490 first->bit_field() == second->bit_field() &&
12491 first->is_extensible() == second->is_extensible() &&
12492 first->new_target_is_base() == second->new_target_is_base() &&
12493 first->has_hidden_prototype() == second->has_hidden_prototype();
12494 }
12495
12496 } // namespace
12497
EquivalentToForTransition(const Map * other) const12498 bool Map::EquivalentToForTransition(const Map* other) const {
12499 if (!CheckEquivalent(this, other)) return false;
12500 if (instance_type() == JS_FUNCTION_TYPE) {
12501 // JSFunctions require more checks to ensure that sloppy function is
12502 // not equivalent to strict function.
12503 int nof = Min(NumberOfOwnDescriptors(), other->NumberOfOwnDescriptors());
12504 return instance_descriptors()->IsEqualUpTo(other->instance_descriptors(),
12505 nof);
12506 }
12507 return true;
12508 }
12509
EquivalentToForElementsKindTransition(const Map * other) const12510 bool Map::EquivalentToForElementsKindTransition(const Map* other) const {
12511 if (!EquivalentToForTransition(other)) return false;
12512 #ifdef DEBUG
12513 // Ensure that we don't try to generate elements kind transitions from maps
12514 // with fields that may be generalized in-place. This must already be handled
12515 // during addition of a new field.
12516 DescriptorArray* descriptors = instance_descriptors();
12517 int nof = NumberOfOwnDescriptors();
12518 for (int i = 0; i < nof; i++) {
12519 PropertyDetails details = descriptors->GetDetails(i);
12520 if (details.location() == kField) {
12521 DCHECK(!IsInplaceGeneralizableField(details.constness(),
12522 details.representation(),
12523 descriptors->GetFieldType(i)));
12524 }
12525 }
12526 #endif
12527 return true;
12528 }
12529
EquivalentToForNormalization(const Map * other,PropertyNormalizationMode mode) const12530 bool Map::EquivalentToForNormalization(const Map* other,
12531 PropertyNormalizationMode mode) const {
12532 int properties =
12533 mode == CLEAR_INOBJECT_PROPERTIES ? 0 : other->GetInObjectProperties();
12534 return CheckEquivalent(this, other) && bit_field2() == other->bit_field2() &&
12535 GetInObjectProperties() == properties &&
12536 JSObject::GetEmbedderFieldCount(this) ==
12537 JSObject::GetEmbedderFieldCount(other);
12538 }
12539
12540
MarkForOptimization(ConcurrencyMode mode)12541 void JSFunction::MarkForOptimization(ConcurrencyMode mode) {
12542 Isolate* isolate = GetIsolate();
12543 if (!isolate->concurrent_recompilation_enabled() ||
12544 isolate->bootstrapper()->IsActive()) {
12545 mode = ConcurrencyMode::kNotConcurrent;
12546 }
12547
12548 DCHECK(!is_compiled() || IsInterpreted());
12549 DCHECK(shared()->IsInterpreted());
12550 DCHECK(!IsOptimized());
12551 DCHECK(!HasOptimizedCode());
12552 DCHECK(shared()->allows_lazy_compilation() ||
12553 !shared()->optimization_disabled());
12554
12555 if (mode == ConcurrencyMode::kConcurrent) {
12556 if (IsInOptimizationQueue()) {
12557 if (FLAG_trace_concurrent_recompilation) {
12558 PrintF(" ** Not marking ");
12559 ShortPrint();
12560 PrintF(" -- already in optimization queue.\n");
12561 }
12562 return;
12563 }
12564 if (FLAG_trace_concurrent_recompilation) {
12565 PrintF(" ** Marking ");
12566 ShortPrint();
12567 PrintF(" for concurrent recompilation.\n");
12568 }
12569 }
12570
12571 SetOptimizationMarker(mode == ConcurrencyMode::kConcurrent
12572 ? OptimizationMarker::kCompileOptimizedConcurrent
12573 : OptimizationMarker::kCompileOptimized);
12574 }
12575
12576 // static
EnsureFeedbackVector(Handle<JSFunction> function)12577 void JSFunction::EnsureFeedbackVector(Handle<JSFunction> function) {
12578 Isolate* const isolate = function->GetIsolate();
12579 if (function->feedback_cell()->value()->IsUndefined(isolate)) {
12580 Handle<SharedFunctionInfo> shared(function->shared(), isolate);
12581 if (!shared->HasAsmWasmData()) {
12582 Handle<FeedbackVector> feedback_vector =
12583 FeedbackVector::New(isolate, shared);
12584 if (function->feedback_cell() == isolate->heap()->many_closures_cell()) {
12585 Handle<FeedbackCell> feedback_cell =
12586 isolate->factory()->NewOneClosureCell(feedback_vector);
12587 function->set_feedback_cell(*feedback_cell);
12588 } else {
12589 function->feedback_cell()->set_value(*feedback_vector);
12590 }
12591 }
12592 }
12593 }
12594
GetMinInobjectSlack(Map * map,void * data)12595 static void GetMinInobjectSlack(Map* map, void* data) {
12596 int slack = map->UnusedPropertyFields();
12597 if (*reinterpret_cast<int*>(data) > slack) {
12598 *reinterpret_cast<int*>(data) = slack;
12599 }
12600 }
12601
InstanceSizeFromSlack(int slack) const12602 int Map::InstanceSizeFromSlack(int slack) const {
12603 return instance_size() - slack * kPointerSize;
12604 }
12605
ShrinkInstanceSize(Map * map,void * data)12606 static void ShrinkInstanceSize(Map* map, void* data) {
12607 int slack = *reinterpret_cast<int*>(data);
12608 DCHECK_GE(slack, 0);
12609 #ifdef DEBUG
12610 int old_visitor_id = Map::GetVisitorId(map);
12611 int new_unused = map->UnusedPropertyFields() - slack;
12612 #endif
12613 map->set_instance_size(map->InstanceSizeFromSlack(slack));
12614 map->set_construction_counter(Map::kNoSlackTracking);
12615 DCHECK_EQ(old_visitor_id, Map::GetVisitorId(map));
12616 DCHECK_EQ(new_unused, map->UnusedPropertyFields());
12617 }
12618
StopSlackTracking(Map * map,void * data)12619 static void StopSlackTracking(Map* map, void* data) {
12620 map->set_construction_counter(Map::kNoSlackTracking);
12621 }
12622
ComputeMinObjectSlack(Isolate * isolate)12623 int Map::ComputeMinObjectSlack(Isolate* isolate) {
12624 DisallowHeapAllocation no_gc;
12625 // Has to be an initial map.
12626 DCHECK(GetBackPointer()->IsUndefined(isolate));
12627
12628 int slack = UnusedPropertyFields();
12629 TransitionsAccessor transitions(isolate, this, &no_gc);
12630 transitions.TraverseTransitionTree(&GetMinInobjectSlack, &slack);
12631 return slack;
12632 }
12633
CompleteInobjectSlackTracking(Isolate * isolate)12634 void Map::CompleteInobjectSlackTracking(Isolate* isolate) {
12635 DisallowHeapAllocation no_gc;
12636 // Has to be an initial map.
12637 DCHECK(GetBackPointer()->IsUndefined(isolate));
12638
12639 int slack = ComputeMinObjectSlack(isolate);
12640 TransitionsAccessor transitions(isolate, this, &no_gc);
12641 if (slack != 0) {
12642 // Resize the initial map and all maps in its transition tree.
12643 transitions.TraverseTransitionTree(&ShrinkInstanceSize, &slack);
12644 } else {
12645 transitions.TraverseTransitionTree(&StopSlackTracking, nullptr);
12646 }
12647 }
12648
12649
PrototypeBenefitsFromNormalization(Handle<JSObject> object)12650 static bool PrototypeBenefitsFromNormalization(Handle<JSObject> object) {
12651 DisallowHeapAllocation no_gc;
12652 if (!object->HasFastProperties()) return false;
12653 if (object->IsJSGlobalProxy()) return false;
12654 if (object->GetIsolate()->bootstrapper()->IsActive()) return false;
12655 return !object->map()->is_prototype_map() ||
12656 !object->map()->should_be_fast_prototype_map();
12657 }
12658
12659 // static
MakePrototypesFast(Handle<Object> receiver,WhereToStart where_to_start,Isolate * isolate)12660 void JSObject::MakePrototypesFast(Handle<Object> receiver,
12661 WhereToStart where_to_start,
12662 Isolate* isolate) {
12663 if (!receiver->IsJSReceiver()) return;
12664 for (PrototypeIterator iter(isolate, Handle<JSReceiver>::cast(receiver),
12665 where_to_start);
12666 !iter.IsAtEnd(); iter.Advance()) {
12667 Handle<Object> current = PrototypeIterator::GetCurrent(iter);
12668 if (!current->IsJSObject()) return;
12669 Handle<JSObject> current_obj = Handle<JSObject>::cast(current);
12670 Map* current_map = current_obj->map();
12671 if (current_map->is_prototype_map()) {
12672 // If the map is already marked as should be fast, we're done. Its
12673 // prototypes will have been marked already as well.
12674 if (current_map->should_be_fast_prototype_map()) return;
12675 Handle<Map> map(current_map, isolate);
12676 Map::SetShouldBeFastPrototypeMap(map, true, isolate);
12677 JSObject::OptimizeAsPrototype(current_obj);
12678 }
12679 }
12680 }
12681
12682 // static
OptimizeAsPrototype(Handle<JSObject> object,bool enable_setup_mode)12683 void JSObject::OptimizeAsPrototype(Handle<JSObject> object,
12684 bool enable_setup_mode) {
12685 if (object->IsJSGlobalObject()) return;
12686 if (enable_setup_mode && PrototypeBenefitsFromNormalization(object)) {
12687 // First normalize to ensure all JSFunctions are DATA_CONSTANT.
12688 JSObject::NormalizeProperties(object, KEEP_INOBJECT_PROPERTIES, 0,
12689 "NormalizeAsPrototype");
12690 }
12691 if (object->map()->is_prototype_map()) {
12692 if (object->map()->should_be_fast_prototype_map() &&
12693 !object->HasFastProperties()) {
12694 JSObject::MigrateSlowToFast(object, 0, "OptimizeAsPrototype");
12695 }
12696 } else {
12697 Handle<Map> new_map = Map::Copy(object->GetIsolate(),
12698 handle(object->map(), object->GetIsolate()),
12699 "CopyAsPrototype");
12700 JSObject::MigrateToMap(object, new_map);
12701 object->map()->set_is_prototype_map(true);
12702
12703 // Replace the pointer to the exact constructor with the Object function
12704 // from the same context if undetectable from JS. This is to avoid keeping
12705 // memory alive unnecessarily.
12706 Object* maybe_constructor = object->map()->GetConstructor();
12707 if (maybe_constructor->IsJSFunction()) {
12708 JSFunction* constructor = JSFunction::cast(maybe_constructor);
12709 if (!constructor->shared()->IsApiFunction()) {
12710 Context* context = constructor->context()->native_context();
12711 JSFunction* object_function = context->object_function();
12712 object->map()->SetConstructor(object_function);
12713 }
12714 }
12715 }
12716 }
12717
12718
12719 // static
ReoptimizeIfPrototype(Handle<JSObject> object)12720 void JSObject::ReoptimizeIfPrototype(Handle<JSObject> object) {
12721 if (!object->map()->is_prototype_map()) return;
12722 if (!object->map()->should_be_fast_prototype_map()) return;
12723 OptimizeAsPrototype(object);
12724 }
12725
12726
12727 // static
LazyRegisterPrototypeUser(Handle<Map> user,Isolate * isolate)12728 void JSObject::LazyRegisterPrototypeUser(Handle<Map> user, Isolate* isolate) {
12729 // Contract: In line with InvalidatePrototypeChains()'s requirements,
12730 // leaf maps don't need to register as users, only prototypes do.
12731 DCHECK(user->is_prototype_map());
12732
12733 Handle<Map> current_user = user;
12734 Handle<PrototypeInfo> current_user_info =
12735 Map::GetOrCreatePrototypeInfo(user, isolate);
12736 for (PrototypeIterator iter(isolate, user); !iter.IsAtEnd(); iter.Advance()) {
12737 // Walk up the prototype chain as far as links haven't been registered yet.
12738 if (current_user_info->registry_slot() != PrototypeInfo::UNREGISTERED) {
12739 break;
12740 }
12741 Handle<Object> maybe_proto = PrototypeIterator::GetCurrent(iter);
12742 // Proxies on the prototype chain are not supported. They make it
12743 // impossible to make any assumptions about the prototype chain anyway.
12744 if (maybe_proto->IsJSProxy()) return;
12745 Handle<JSObject> proto = Handle<JSObject>::cast(maybe_proto);
12746 Handle<PrototypeInfo> proto_info =
12747 Map::GetOrCreatePrototypeInfo(proto, isolate);
12748 Handle<Object> maybe_registry(proto_info->prototype_users(), isolate);
12749 Handle<WeakArrayList> registry =
12750 maybe_registry->IsSmi()
12751 ? handle(ReadOnlyRoots(isolate->heap()).empty_weak_array_list(),
12752 isolate)
12753 : Handle<WeakArrayList>::cast(maybe_registry);
12754 int slot = 0;
12755 Handle<WeakArrayList> new_array =
12756 PrototypeUsers::Add(isolate, registry, current_user, &slot);
12757 current_user_info->set_registry_slot(slot);
12758 if (!maybe_registry.is_identical_to(new_array)) {
12759 proto_info->set_prototype_users(*new_array);
12760 }
12761 if (FLAG_trace_prototype_users) {
12762 PrintF("Registering %p as a user of prototype %p (map=%p).\n",
12763 reinterpret_cast<void*>(*current_user),
12764 reinterpret_cast<void*>(*proto),
12765 reinterpret_cast<void*>(proto->map()));
12766 }
12767
12768 current_user = handle(proto->map(), isolate);
12769 current_user_info = proto_info;
12770 }
12771 }
12772
12773
12774 // Can be called regardless of whether |user| was actually registered with
12775 // |prototype|. Returns true when there was a registration.
12776 // static
UnregisterPrototypeUser(Handle<Map> user,Isolate * isolate)12777 bool JSObject::UnregisterPrototypeUser(Handle<Map> user, Isolate* isolate) {
12778 DCHECK(user->is_prototype_map());
12779 // If it doesn't have a PrototypeInfo, it was never registered.
12780 if (!user->prototype_info()->IsPrototypeInfo()) return false;
12781 // If it had no prototype before, see if it had users that might expect
12782 // registration.
12783 if (!user->prototype()->IsJSObject()) {
12784 Object* users =
12785 PrototypeInfo::cast(user->prototype_info())->prototype_users();
12786 return users->IsWeakArrayList();
12787 }
12788 Handle<JSObject> prototype(JSObject::cast(user->prototype()), isolate);
12789 Handle<PrototypeInfo> user_info =
12790 Map::GetOrCreatePrototypeInfo(user, isolate);
12791 int slot = user_info->registry_slot();
12792 if (slot == PrototypeInfo::UNREGISTERED) return false;
12793 DCHECK(prototype->map()->is_prototype_map());
12794 Object* maybe_proto_info = prototype->map()->prototype_info();
12795 // User knows its registry slot, prototype info and user registry must exist.
12796 DCHECK(maybe_proto_info->IsPrototypeInfo());
12797 Handle<PrototypeInfo> proto_info(PrototypeInfo::cast(maybe_proto_info),
12798 isolate);
12799 Handle<WeakArrayList> prototype_users(
12800 WeakArrayList::cast(proto_info->prototype_users()), isolate);
12801 DCHECK_EQ(prototype_users->Get(slot), HeapObjectReference::Weak(*user));
12802 PrototypeUsers::MarkSlotEmpty(*prototype_users, slot);
12803 if (FLAG_trace_prototype_users) {
12804 PrintF("Unregistering %p as a user of prototype %p.\n",
12805 reinterpret_cast<void*>(*user), reinterpret_cast<void*>(*prototype));
12806 }
12807 return true;
12808 }
12809
12810 namespace {
12811
12812 // This function must be kept in sync with
12813 // AccessorAssembler::InvalidateValidityCellIfPrototype() which does pre-checks
12814 // before jumping here.
InvalidateOnePrototypeValidityCellInternal(Map * map)12815 void InvalidateOnePrototypeValidityCellInternal(Map* map) {
12816 DCHECK(map->is_prototype_map());
12817 if (FLAG_trace_prototype_users) {
12818 PrintF("Invalidating prototype map %p 's cell\n",
12819 reinterpret_cast<void*>(map));
12820 }
12821 Object* maybe_cell = map->prototype_validity_cell();
12822 if (maybe_cell->IsCell()) {
12823 // Just set the value; the cell will be replaced lazily.
12824 Cell* cell = Cell::cast(maybe_cell);
12825 cell->set_value(Smi::FromInt(Map::kPrototypeChainInvalid));
12826 }
12827 }
12828
InvalidatePrototypeChainsInternal(Map * map)12829 void InvalidatePrototypeChainsInternal(Map* map) {
12830 InvalidateOnePrototypeValidityCellInternal(map);
12831
12832 Object* maybe_proto_info = map->prototype_info();
12833 if (!maybe_proto_info->IsPrototypeInfo()) return;
12834 PrototypeInfo* proto_info = PrototypeInfo::cast(maybe_proto_info);
12835 WeakArrayList* prototype_users =
12836 WeakArrayList::cast(proto_info->prototype_users());
12837 // For now, only maps register themselves as users.
12838 for (int i = PrototypeUsers::kFirstIndex; i < prototype_users->length();
12839 ++i) {
12840 HeapObject* heap_object;
12841 if (prototype_users->Get(i)->ToWeakHeapObject(&heap_object) &&
12842 heap_object->IsMap()) {
12843 // Walk the prototype chain (backwards, towards leaf objects) if
12844 // necessary.
12845 InvalidatePrototypeChainsInternal(Map::cast(heap_object));
12846 }
12847 }
12848 }
12849
12850 } // namespace
12851
12852 // static
InvalidatePrototypeChains(Map * map)12853 Map* JSObject::InvalidatePrototypeChains(Map* map) {
12854 DisallowHeapAllocation no_gc;
12855 InvalidatePrototypeChainsInternal(map);
12856 return map;
12857 }
12858
12859 // We also invalidate global objects validity cell when a new lexical
12860 // environment variable is added. This is necessary to ensure that
12861 // Load/StoreGlobalIC handlers that load/store from global object's prototype
12862 // get properly invalidated.
12863 // Note, that the normal Load/StoreICs that load/store through the global object
12864 // in the prototype chain are not affected by appearance of a new lexical
12865 // variable and therefore we don't propagate invalidation down.
12866 // static
InvalidatePrototypeValidityCell(JSGlobalObject * global)12867 void JSObject::InvalidatePrototypeValidityCell(JSGlobalObject* global) {
12868 DisallowHeapAllocation no_gc;
12869 InvalidateOnePrototypeValidityCellInternal(global->map());
12870 }
12871
12872 // static
GetOrCreatePrototypeInfo(Handle<JSObject> prototype,Isolate * isolate)12873 Handle<PrototypeInfo> Map::GetOrCreatePrototypeInfo(Handle<JSObject> prototype,
12874 Isolate* isolate) {
12875 Object* maybe_proto_info = prototype->map()->prototype_info();
12876 if (maybe_proto_info->IsPrototypeInfo()) {
12877 return handle(PrototypeInfo::cast(maybe_proto_info), isolate);
12878 }
12879 Handle<PrototypeInfo> proto_info = isolate->factory()->NewPrototypeInfo();
12880 prototype->map()->set_prototype_info(*proto_info);
12881 return proto_info;
12882 }
12883
12884
12885 // static
GetOrCreatePrototypeInfo(Handle<Map> prototype_map,Isolate * isolate)12886 Handle<PrototypeInfo> Map::GetOrCreatePrototypeInfo(Handle<Map> prototype_map,
12887 Isolate* isolate) {
12888 Object* maybe_proto_info = prototype_map->prototype_info();
12889 if (maybe_proto_info->IsPrototypeInfo()) {
12890 return handle(PrototypeInfo::cast(maybe_proto_info), isolate);
12891 }
12892 Handle<PrototypeInfo> proto_info = isolate->factory()->NewPrototypeInfo();
12893 prototype_map->set_prototype_info(*proto_info);
12894 return proto_info;
12895 }
12896
12897 // static
SetShouldBeFastPrototypeMap(Handle<Map> map,bool value,Isolate * isolate)12898 void Map::SetShouldBeFastPrototypeMap(Handle<Map> map, bool value,
12899 Isolate* isolate) {
12900 if (value == false && !map->prototype_info()->IsPrototypeInfo()) {
12901 // "False" is the implicit default value, so there's nothing to do.
12902 return;
12903 }
12904 GetOrCreatePrototypeInfo(map, isolate)->set_should_be_fast_map(value);
12905 }
12906
12907 // static
GetOrCreatePrototypeChainValidityCell(Handle<Map> map,Isolate * isolate)12908 Handle<Object> Map::GetOrCreatePrototypeChainValidityCell(Handle<Map> map,
12909 Isolate* isolate) {
12910 Handle<Object> maybe_prototype;
12911 if (map->IsJSGlobalObjectMap()) {
12912 DCHECK(map->is_prototype_map());
12913 // Global object is prototype of a global proxy and therefore we can
12914 // use its validity cell for guarding global object's prototype change.
12915 maybe_prototype = isolate->global_object();
12916 } else {
12917 maybe_prototype =
12918 handle(map->GetPrototypeChainRootMap(isolate)->prototype(), isolate);
12919 }
12920 if (!maybe_prototype->IsJSObject()) {
12921 return handle(Smi::FromInt(Map::kPrototypeChainValid), isolate);
12922 }
12923 Handle<JSObject> prototype = Handle<JSObject>::cast(maybe_prototype);
12924 // Ensure the prototype is registered with its own prototypes so its cell
12925 // will be invalidated when necessary.
12926 JSObject::LazyRegisterPrototypeUser(handle(prototype->map(), isolate),
12927 isolate);
12928
12929 Object* maybe_cell = prototype->map()->prototype_validity_cell();
12930 // Return existing cell if it's still valid.
12931 if (maybe_cell->IsCell()) {
12932 Handle<Cell> cell(Cell::cast(maybe_cell), isolate);
12933 if (cell->value() == Smi::FromInt(Map::kPrototypeChainValid)) {
12934 return cell;
12935 }
12936 }
12937 // Otherwise create a new cell.
12938 Handle<Cell> cell = isolate->factory()->NewCell(
12939 handle(Smi::FromInt(Map::kPrototypeChainValid), isolate));
12940 prototype->map()->set_prototype_validity_cell(*cell);
12941 return cell;
12942 }
12943
12944 // static
IsPrototypeChainInvalidated(Map * map)12945 bool Map::IsPrototypeChainInvalidated(Map* map) {
12946 DCHECK(map->is_prototype_map());
12947 Object* maybe_cell = map->prototype_validity_cell();
12948 if (maybe_cell->IsCell()) {
12949 Cell* cell = Cell::cast(maybe_cell);
12950 return cell->value() != Smi::FromInt(Map::kPrototypeChainValid);
12951 }
12952 return true;
12953 }
12954
12955 // static
SetPrototype(Isolate * isolate,Handle<Map> map,Handle<Object> prototype,bool enable_prototype_setup_mode)12956 void Map::SetPrototype(Isolate* isolate, Handle<Map> map,
12957 Handle<Object> prototype,
12958 bool enable_prototype_setup_mode) {
12959 RuntimeCallTimerScope stats_scope(isolate, *map,
12960 RuntimeCallCounterId::kMap_SetPrototype);
12961
12962 bool is_hidden = false;
12963 if (prototype->IsJSObject()) {
12964 Handle<JSObject> prototype_jsobj = Handle<JSObject>::cast(prototype);
12965 JSObject::OptimizeAsPrototype(prototype_jsobj, enable_prototype_setup_mode);
12966
12967 Object* maybe_constructor = prototype_jsobj->map()->GetConstructor();
12968 if (maybe_constructor->IsJSFunction()) {
12969 JSFunction* constructor = JSFunction::cast(maybe_constructor);
12970 Object* data = constructor->shared()->function_data();
12971 is_hidden = (data->IsFunctionTemplateInfo() &&
12972 FunctionTemplateInfo::cast(data)->hidden_prototype()) ||
12973 prototype->IsJSGlobalObject();
12974 } else if (maybe_constructor->IsFunctionTemplateInfo()) {
12975 is_hidden =
12976 FunctionTemplateInfo::cast(maybe_constructor)->hidden_prototype() ||
12977 prototype->IsJSGlobalObject();
12978 }
12979 }
12980 map->set_has_hidden_prototype(is_hidden);
12981
12982 WriteBarrierMode wb_mode =
12983 prototype->IsNull(isolate) ? SKIP_WRITE_BARRIER : UPDATE_WRITE_BARRIER;
12984 map->set_prototype(*prototype, wb_mode);
12985 }
12986
CacheInitialJSArrayMaps(Handle<Context> native_context,Handle<Map> initial_map)12987 Handle<Object> CacheInitialJSArrayMaps(Handle<Context> native_context,
12988 Handle<Map> initial_map) {
12989 // Replace all of the cached initial array maps in the native context with
12990 // the appropriate transitioned elements kind maps.
12991 Handle<Map> current_map = initial_map;
12992 ElementsKind kind = current_map->elements_kind();
12993 DCHECK_EQ(GetInitialFastElementsKind(), kind);
12994 native_context->set(Context::ArrayMapIndex(kind), *current_map);
12995 for (int i = GetSequenceIndexFromFastElementsKind(kind) + 1;
12996 i < kFastElementsKindCount; ++i) {
12997 Handle<Map> new_map;
12998 ElementsKind next_kind = GetFastElementsKindFromSequenceIndex(i);
12999 if (Map* maybe_elements_transition = current_map->ElementsTransitionMap()) {
13000 new_map = handle(maybe_elements_transition, native_context->GetIsolate());
13001 } else {
13002 new_map =
13003 Map::CopyAsElementsKind(native_context->GetIsolate(), current_map,
13004 next_kind, INSERT_TRANSITION);
13005 }
13006 DCHECK_EQ(next_kind, new_map->elements_kind());
13007 native_context->set(Context::ArrayMapIndex(next_kind), *new_map);
13008 current_map = new_map;
13009 }
13010 return initial_map;
13011 }
13012
13013 namespace {
13014
SetInstancePrototype(Isolate * isolate,Handle<JSFunction> function,Handle<JSReceiver> value)13015 void SetInstancePrototype(Isolate* isolate, Handle<JSFunction> function,
13016 Handle<JSReceiver> value) {
13017 // Now some logic for the maps of the objects that are created by using this
13018 // function as a constructor.
13019 if (function->has_initial_map()) {
13020 // If the function has allocated the initial map replace it with a
13021 // copy containing the new prototype. Also complete any in-object
13022 // slack tracking that is in progress at this point because it is
13023 // still tracking the old copy.
13024 function->CompleteInobjectSlackTrackingIfActive();
13025
13026 Handle<Map> initial_map(function->initial_map(), isolate);
13027
13028 if (!isolate->bootstrapper()->IsActive() &&
13029 initial_map->instance_type() == JS_OBJECT_TYPE) {
13030 // Put the value in the initial map field until an initial map is needed.
13031 // At that point, a new initial map is created and the prototype is put
13032 // into the initial map where it belongs.
13033 function->set_prototype_or_initial_map(*value);
13034 } else {
13035 Handle<Map> new_map =
13036 Map::Copy(isolate, initial_map, "SetInstancePrototype");
13037 JSFunction::SetInitialMap(function, new_map, value);
13038
13039 // If the function is used as the global Array function, cache the
13040 // updated initial maps (and transitioned versions) in the native context.
13041 Handle<Context> native_context(function->context()->native_context(),
13042 isolate);
13043 Handle<Object> array_function(
13044 native_context->get(Context::ARRAY_FUNCTION_INDEX), isolate);
13045 if (array_function->IsJSFunction() &&
13046 *function == JSFunction::cast(*array_function)) {
13047 CacheInitialJSArrayMaps(native_context, new_map);
13048 }
13049 }
13050
13051 // Deoptimize all code that embeds the previous initial map.
13052 initial_map->dependent_code()->DeoptimizeDependentCodeGroup(
13053 isolate, DependentCode::kInitialMapChangedGroup);
13054 } else {
13055 // Put the value in the initial map field until an initial map is
13056 // needed. At that point, a new initial map is created and the
13057 // prototype is put into the initial map where it belongs.
13058 function->set_prototype_or_initial_map(*value);
13059 if (value->IsJSObject()) {
13060 // Optimize as prototype to detach it from its transition tree.
13061 JSObject::OptimizeAsPrototype(Handle<JSObject>::cast(value));
13062 }
13063 }
13064 }
13065
13066 } // anonymous namespace
13067
SetPrototype(Handle<JSFunction> function,Handle<Object> value)13068 void JSFunction::SetPrototype(Handle<JSFunction> function,
13069 Handle<Object> value) {
13070 DCHECK(function->IsConstructor() ||
13071 IsGeneratorFunction(function->shared()->kind()));
13072 Isolate* isolate = function->GetIsolate();
13073 Handle<JSReceiver> construct_prototype;
13074
13075 // If the value is not a JSReceiver, store the value in the map's
13076 // constructor field so it can be accessed. Also, set the prototype
13077 // used for constructing objects to the original object prototype.
13078 // See ECMA-262 13.2.2.
13079 if (!value->IsJSReceiver()) {
13080 // Copy the map so this does not affect unrelated functions.
13081 // Remove map transitions because they point to maps with a
13082 // different prototype.
13083 Handle<Map> new_map =
13084 Map::Copy(isolate, handle(function->map(), isolate), "SetPrototype");
13085
13086 JSObject::MigrateToMap(function, new_map);
13087 new_map->SetConstructor(*value);
13088 new_map->set_has_non_instance_prototype(true);
13089
13090 FunctionKind kind = function->shared()->kind();
13091 Handle<Context> native_context(function->context()->native_context(),
13092 isolate);
13093
13094 construct_prototype = Handle<JSReceiver>(
13095 IsGeneratorFunction(kind)
13096 ? IsAsyncFunction(kind)
13097 ? native_context->initial_async_generator_prototype()
13098 : native_context->initial_generator_prototype()
13099 : native_context->initial_object_prototype(),
13100 isolate);
13101 } else {
13102 construct_prototype = Handle<JSReceiver>::cast(value);
13103 function->map()->set_has_non_instance_prototype(false);
13104 }
13105
13106 SetInstancePrototype(isolate, function, construct_prototype);
13107 }
13108
SetInitialMap(Handle<JSFunction> function,Handle<Map> map,Handle<Object> prototype)13109 void JSFunction::SetInitialMap(Handle<JSFunction> function, Handle<Map> map,
13110 Handle<Object> prototype) {
13111 if (map->prototype() != *prototype)
13112 Map::SetPrototype(function->GetIsolate(), map, prototype);
13113 function->set_prototype_or_initial_map(*map);
13114 map->SetConstructor(*function);
13115 if (FLAG_trace_maps) {
13116 LOG(function->GetIsolate(), MapEvent("InitialMap", nullptr, *map, "",
13117 function->shared()->DebugName()));
13118 }
13119 }
13120
13121
13122 #ifdef DEBUG
13123 namespace {
13124
CanSubclassHaveInobjectProperties(InstanceType instance_type)13125 bool CanSubclassHaveInobjectProperties(InstanceType instance_type) {
13126 switch (instance_type) {
13127 case JS_API_OBJECT_TYPE:
13128 case JS_ARRAY_BUFFER_TYPE:
13129 case JS_ARRAY_TYPE:
13130 case JS_ASYNC_FROM_SYNC_ITERATOR_TYPE:
13131 case JS_CONTEXT_EXTENSION_OBJECT_TYPE:
13132 case JS_DATA_VIEW_TYPE:
13133 case JS_DATE_TYPE:
13134 case JS_FUNCTION_TYPE:
13135 case JS_GENERATOR_OBJECT_TYPE:
13136 #ifdef V8_INTL_SUPPORT
13137 case JS_INTL_COLLATOR_TYPE:
13138 case JS_INTL_LIST_FORMAT_TYPE:
13139 case JS_INTL_PLURAL_RULES_TYPE:
13140 case JS_INTL_RELATIVE_TIME_FORMAT_TYPE:
13141 #endif
13142 case JS_ASYNC_GENERATOR_OBJECT_TYPE:
13143 case JS_MAP_TYPE:
13144 case JS_MESSAGE_OBJECT_TYPE:
13145 case JS_OBJECT_TYPE:
13146 case JS_ERROR_TYPE:
13147 case JS_ARGUMENTS_TYPE:
13148 case JS_PROMISE_TYPE:
13149 case JS_REGEXP_TYPE:
13150 case JS_SET_TYPE:
13151 case JS_SPECIAL_API_OBJECT_TYPE:
13152 case JS_TYPED_ARRAY_TYPE:
13153 case JS_VALUE_TYPE:
13154 case JS_WEAK_MAP_TYPE:
13155 case JS_WEAK_SET_TYPE:
13156 case WASM_GLOBAL_TYPE:
13157 case WASM_INSTANCE_TYPE:
13158 case WASM_MEMORY_TYPE:
13159 case WASM_MODULE_TYPE:
13160 case WASM_TABLE_TYPE:
13161 return true;
13162
13163 case BIGINT_TYPE:
13164 case OBJECT_BOILERPLATE_DESCRIPTION_TYPE:
13165 case BYTECODE_ARRAY_TYPE:
13166 case BYTE_ARRAY_TYPE:
13167 case CELL_TYPE:
13168 case CODE_TYPE:
13169 case FILLER_TYPE:
13170 case FIXED_ARRAY_TYPE:
13171 case SCRIPT_CONTEXT_TABLE_TYPE:
13172 case FIXED_DOUBLE_ARRAY_TYPE:
13173 case FEEDBACK_METADATA_TYPE:
13174 case FOREIGN_TYPE:
13175 case FREE_SPACE_TYPE:
13176 case HASH_TABLE_TYPE:
13177 case ORDERED_HASH_MAP_TYPE:
13178 case ORDERED_HASH_SET_TYPE:
13179 case NAME_DICTIONARY_TYPE:
13180 case GLOBAL_DICTIONARY_TYPE:
13181 case NUMBER_DICTIONARY_TYPE:
13182 case SIMPLE_NUMBER_DICTIONARY_TYPE:
13183 case STRING_TABLE_TYPE:
13184 case HEAP_NUMBER_TYPE:
13185 case JS_BOUND_FUNCTION_TYPE:
13186 case JS_GLOBAL_OBJECT_TYPE:
13187 case JS_GLOBAL_PROXY_TYPE:
13188 case JS_PROXY_TYPE:
13189 case MAP_TYPE:
13190 case MUTABLE_HEAP_NUMBER_TYPE:
13191 case ODDBALL_TYPE:
13192 case PROPERTY_CELL_TYPE:
13193 case SHARED_FUNCTION_INFO_TYPE:
13194 case SYMBOL_TYPE:
13195 case ALLOCATION_SITE_TYPE:
13196
13197 #define TYPED_ARRAY_CASE(Type, type, TYPE, ctype, size) \
13198 case FIXED_##TYPE##_ARRAY_TYPE:
13199 #undef TYPED_ARRAY_CASE
13200
13201 #define MAKE_STRUCT_CASE(NAME, Name, name) case NAME##_TYPE:
13202 STRUCT_LIST(MAKE_STRUCT_CASE)
13203 #undef MAKE_STRUCT_CASE
13204 // We must not end up here for these instance types at all.
13205 UNREACHABLE();
13206 // Fall through.
13207 default:
13208 return false;
13209 }
13210 }
13211
13212 } // namespace
13213 #endif
13214
13215
EnsureHasInitialMap(Handle<JSFunction> function)13216 void JSFunction::EnsureHasInitialMap(Handle<JSFunction> function) {
13217 DCHECK(function->has_prototype_slot());
13218 DCHECK(function->IsConstructor() ||
13219 IsResumableFunction(function->shared()->kind()));
13220 if (function->has_initial_map()) return;
13221 Isolate* isolate = function->GetIsolate();
13222
13223 // First create a new map with the size and number of in-object properties
13224 // suggested by the function.
13225 InstanceType instance_type;
13226 if (IsResumableFunction(function->shared()->kind())) {
13227 instance_type = IsAsyncGeneratorFunction(function->shared()->kind())
13228 ? JS_ASYNC_GENERATOR_OBJECT_TYPE
13229 : JS_GENERATOR_OBJECT_TYPE;
13230 } else {
13231 instance_type = JS_OBJECT_TYPE;
13232 }
13233
13234 // The constructor should be compiled for the optimization hints to be
13235 // available.
13236 int expected_nof_properties = 0;
13237 if (function->shared()->is_compiled() ||
13238 Compiler::Compile(function, Compiler::CLEAR_EXCEPTION)) {
13239 DCHECK(function->shared()->is_compiled());
13240 expected_nof_properties = function->shared()->expected_nof_properties();
13241 }
13242
13243 int instance_size;
13244 int inobject_properties;
13245 CalculateInstanceSizeHelper(instance_type, false, 0, expected_nof_properties,
13246 &instance_size, &inobject_properties);
13247
13248 Handle<Map> map = isolate->factory()->NewMap(instance_type, instance_size,
13249 TERMINAL_FAST_ELEMENTS_KIND,
13250 inobject_properties);
13251
13252 // Fetch or allocate prototype.
13253 Handle<Object> prototype;
13254 if (function->has_instance_prototype()) {
13255 prototype = handle(function->instance_prototype(), isolate);
13256 } else {
13257 prototype = isolate->factory()->NewFunctionPrototype(function);
13258 }
13259 DCHECK(map->has_fast_object_elements());
13260
13261 // Finally link initial map and constructor function.
13262 DCHECK(prototype->IsJSReceiver());
13263 JSFunction::SetInitialMap(function, map, prototype);
13264 map->StartInobjectSlackTracking();
13265 }
13266
13267 namespace {
FastInitializeDerivedMap(Isolate * isolate,Handle<JSFunction> new_target,Handle<JSFunction> constructor,Handle<Map> constructor_initial_map)13268 bool FastInitializeDerivedMap(Isolate* isolate, Handle<JSFunction> new_target,
13269 Handle<JSFunction> constructor,
13270 Handle<Map> constructor_initial_map) {
13271 // Check that |function|'s initial map still in sync with the |constructor|,
13272 // otherwise we must create a new initial map for |function|.
13273 if (new_target->has_initial_map() &&
13274 new_target->initial_map()->GetConstructor() == *constructor) {
13275 DCHECK(new_target->instance_prototype()->IsJSReceiver());
13276 return true;
13277 }
13278 InstanceType instance_type = constructor_initial_map->instance_type();
13279 DCHECK(CanSubclassHaveInobjectProperties(instance_type));
13280 // Create a new map with the size and number of in-object properties
13281 // suggested by |function|.
13282
13283 // Link initial map and constructor function if the new.target is actually a
13284 // subclass constructor.
13285 if (!IsDerivedConstructor(new_target->shared()->kind())) return false;
13286
13287 int instance_size;
13288 int in_object_properties;
13289 int embedder_fields =
13290 JSObject::GetEmbedderFieldCount(*constructor_initial_map);
13291 bool success = JSFunction::CalculateInstanceSizeForDerivedClass(
13292 new_target, instance_type, embedder_fields, &instance_size,
13293 &in_object_properties);
13294
13295 Handle<Map> map;
13296 if (success) {
13297 int pre_allocated = constructor_initial_map->GetInObjectProperties() -
13298 constructor_initial_map->UnusedPropertyFields();
13299 CHECK_LE(constructor_initial_map->UsedInstanceSize(), instance_size);
13300 int unused_property_fields = in_object_properties - pre_allocated;
13301 map = Map::CopyInitialMap(isolate, constructor_initial_map, instance_size,
13302 in_object_properties, unused_property_fields);
13303 } else {
13304 map = Map::CopyInitialMap(isolate, constructor_initial_map);
13305 }
13306 map->set_new_target_is_base(false);
13307 Handle<Object> prototype(new_target->instance_prototype(), isolate);
13308 JSFunction::SetInitialMap(new_target, map, prototype);
13309 DCHECK(new_target->instance_prototype()->IsJSReceiver());
13310 map->SetConstructor(*constructor);
13311 map->set_construction_counter(Map::kNoSlackTracking);
13312 map->StartInobjectSlackTracking();
13313 return true;
13314 }
13315
13316 } // namespace
13317
13318 // static
GetDerivedMap(Isolate * isolate,Handle<JSFunction> constructor,Handle<JSReceiver> new_target)13319 MaybeHandle<Map> JSFunction::GetDerivedMap(Isolate* isolate,
13320 Handle<JSFunction> constructor,
13321 Handle<JSReceiver> new_target) {
13322 EnsureHasInitialMap(constructor);
13323
13324 Handle<Map> constructor_initial_map(constructor->initial_map(), isolate);
13325 if (*new_target == *constructor) return constructor_initial_map;
13326
13327 Handle<Map> result_map;
13328 // Fast case, new.target is a subclass of constructor. The map is cacheable
13329 // (and may already have been cached). new.target.prototype is guaranteed to
13330 // be a JSReceiver.
13331 if (new_target->IsJSFunction()) {
13332 Handle<JSFunction> function = Handle<JSFunction>::cast(new_target);
13333 if (FastInitializeDerivedMap(isolate, function, constructor,
13334 constructor_initial_map)) {
13335 return handle(function->initial_map(), isolate);
13336 }
13337 }
13338
13339 // Slow path, new.target is either a proxy or can't cache the map.
13340 // new.target.prototype is not guaranteed to be a JSReceiver, and may need to
13341 // fall back to the intrinsicDefaultProto.
13342 Handle<Object> prototype;
13343 if (new_target->IsJSFunction()) {
13344 Handle<JSFunction> function = Handle<JSFunction>::cast(new_target);
13345 // Make sure the new.target.prototype is cached.
13346 EnsureHasInitialMap(function);
13347 prototype = handle(function->prototype(), isolate);
13348 } else {
13349 Handle<String> prototype_string = isolate->factory()->prototype_string();
13350 ASSIGN_RETURN_ON_EXCEPTION(
13351 isolate, prototype,
13352 JSReceiver::GetProperty(isolate, new_target, prototype_string), Map);
13353 // The above prototype lookup might change the constructor and its
13354 // prototype, hence we have to reload the initial map.
13355 EnsureHasInitialMap(constructor);
13356 constructor_initial_map = handle(constructor->initial_map(), isolate);
13357 }
13358
13359 // If prototype is not a JSReceiver, fetch the intrinsicDefaultProto from the
13360 // correct realm. Rather than directly fetching the .prototype, we fetch the
13361 // constructor that points to the .prototype. This relies on
13362 // constructor.prototype being FROZEN for those constructors.
13363 if (!prototype->IsJSReceiver()) {
13364 Handle<Context> context;
13365 ASSIGN_RETURN_ON_EXCEPTION(isolate, context,
13366 JSReceiver::GetFunctionRealm(new_target), Map);
13367 DCHECK(context->IsNativeContext());
13368 Handle<Object> maybe_index = JSReceiver::GetDataProperty(
13369 constructor, isolate->factory()->native_context_index_symbol());
13370 int index = maybe_index->IsSmi() ? Smi::ToInt(*maybe_index)
13371 : Context::OBJECT_FUNCTION_INDEX;
13372 Handle<JSFunction> realm_constructor(JSFunction::cast(context->get(index)),
13373 isolate);
13374 prototype = handle(realm_constructor->prototype(), isolate);
13375 }
13376
13377 Handle<Map> map = Map::CopyInitialMap(isolate, constructor_initial_map);
13378 map->set_new_target_is_base(false);
13379 CHECK(prototype->IsJSReceiver());
13380 if (map->prototype() != *prototype)
13381 Map::SetPrototype(isolate, map, prototype);
13382 map->SetConstructor(*constructor);
13383 return map;
13384 }
13385
ComputeInstanceSizeWithMinSlack(Isolate * isolate)13386 int JSFunction::ComputeInstanceSizeWithMinSlack(Isolate* isolate) {
13387 if (has_prototype_slot() && has_initial_map() &&
13388 initial_map()->IsInobjectSlackTrackingInProgress()) {
13389 int slack = initial_map()->ComputeMinObjectSlack(isolate);
13390 return initial_map()->InstanceSizeFromSlack(slack);
13391 }
13392 return initial_map()->instance_size();
13393 }
13394
PrintName(FILE * out)13395 void JSFunction::PrintName(FILE* out) {
13396 std::unique_ptr<char[]> name = shared()->DebugName()->ToCString();
13397 PrintF(out, "%s", name.get());
13398 }
13399
13400
GetName(Handle<JSFunction> function)13401 Handle<String> JSFunction::GetName(Handle<JSFunction> function) {
13402 Isolate* isolate = function->GetIsolate();
13403 Handle<Object> name =
13404 JSReceiver::GetDataProperty(function, isolate->factory()->name_string());
13405 if (name->IsString()) return Handle<String>::cast(name);
13406 return handle(function->shared()->DebugName(), isolate);
13407 }
13408
13409
GetDebugName(Handle<JSFunction> function)13410 Handle<String> JSFunction::GetDebugName(Handle<JSFunction> function) {
13411 Isolate* isolate = function->GetIsolate();
13412 Handle<Object> name = JSReceiver::GetDataProperty(
13413 function, isolate->factory()->display_name_string());
13414 if (name->IsString()) return Handle<String>::cast(name);
13415 return JSFunction::GetName(function);
13416 }
13417
SetName(Handle<JSFunction> function,Handle<Name> name,Handle<String> prefix)13418 bool JSFunction::SetName(Handle<JSFunction> function, Handle<Name> name,
13419 Handle<String> prefix) {
13420 Isolate* isolate = function->GetIsolate();
13421 Handle<String> function_name;
13422 ASSIGN_RETURN_ON_EXCEPTION_VALUE(isolate, function_name,
13423 Name::ToFunctionName(isolate, name), false);
13424 if (prefix->length() > 0) {
13425 IncrementalStringBuilder builder(isolate);
13426 builder.AppendString(prefix);
13427 builder.AppendCharacter(' ');
13428 builder.AppendString(function_name);
13429 ASSIGN_RETURN_ON_EXCEPTION_VALUE(isolate, function_name, builder.Finish(),
13430 false);
13431 }
13432 RETURN_ON_EXCEPTION_VALUE(
13433 isolate,
13434 JSObject::DefinePropertyOrElementIgnoreAttributes(
13435 function, isolate->factory()->name_string(), function_name,
13436 static_cast<PropertyAttributes>(DONT_ENUM | READ_ONLY)),
13437 false);
13438 return true;
13439 }
13440
13441 namespace {
13442
NativeCodeFunctionSourceString(Handle<SharedFunctionInfo> shared_info)13443 Handle<String> NativeCodeFunctionSourceString(
13444 Handle<SharedFunctionInfo> shared_info) {
13445 Isolate* const isolate = shared_info->GetIsolate();
13446 IncrementalStringBuilder builder(isolate);
13447 builder.AppendCString("function ");
13448 builder.AppendString(handle(shared_info->Name(), isolate));
13449 builder.AppendCString("() { [native code] }");
13450 return builder.Finish().ToHandleChecked();
13451 }
13452
13453 } // namespace
13454
13455
13456 // static
ToString(Handle<JSBoundFunction> function)13457 Handle<String> JSBoundFunction::ToString(Handle<JSBoundFunction> function) {
13458 Isolate* const isolate = function->GetIsolate();
13459 return isolate->factory()->function_native_code_string();
13460 }
13461
13462
13463 // static
ToString(Handle<JSFunction> function)13464 Handle<String> JSFunction::ToString(Handle<JSFunction> function) {
13465 Isolate* const isolate = function->GetIsolate();
13466 Handle<SharedFunctionInfo> shared_info(function->shared(), isolate);
13467
13468 // Check if {function} should hide its source code.
13469 if (!shared_info->IsUserJavaScript()) {
13470 return NativeCodeFunctionSourceString(shared_info);
13471 }
13472
13473 // Check if we should print {function} as a class.
13474 Handle<Object> maybe_class_positions = JSReceiver::GetDataProperty(
13475 function, isolate->factory()->class_positions_symbol());
13476 if (maybe_class_positions->IsTuple2()) {
13477 Tuple2* class_positions = Tuple2::cast(*maybe_class_positions);
13478 int start_position = Smi::ToInt(class_positions->value1());
13479 int end_position = Smi::ToInt(class_positions->value2());
13480 Handle<String> script_source(
13481 String::cast(Script::cast(shared_info->script())->source()), isolate);
13482 return isolate->factory()->NewSubString(script_source, start_position,
13483 end_position);
13484 }
13485
13486 // Check if we have source code for the {function}.
13487 if (!shared_info->HasSourceCode()) {
13488 return NativeCodeFunctionSourceString(shared_info);
13489 }
13490
13491 if (FLAG_harmony_function_tostring) {
13492 if (shared_info->function_token_position() == kNoSourcePosition) {
13493 // If the function token position isn't valid, return [native code] to
13494 // ensure calling eval on the returned source code throws rather than
13495 // giving inconsistent call behaviour.
13496 isolate->CountUsage(v8::Isolate::UseCounterFeature::
13497 kFunctionTokenOffsetTooLongForToString);
13498 return NativeCodeFunctionSourceString(shared_info);
13499 }
13500 return Handle<String>::cast(
13501 SharedFunctionInfo::GetSourceCodeHarmony(shared_info));
13502 }
13503
13504 IncrementalStringBuilder builder(isolate);
13505 FunctionKind kind = shared_info->kind();
13506 if (!IsArrowFunction(kind)) {
13507 if (IsConciseMethod(kind)) {
13508 if (IsAsyncGeneratorFunction(kind)) {
13509 builder.AppendCString("async *");
13510 } else if (IsGeneratorFunction(kind)) {
13511 builder.AppendCharacter('*');
13512 } else if (IsAsyncFunction(kind)) {
13513 builder.AppendCString("async ");
13514 }
13515 } else {
13516 if (IsAsyncGeneratorFunction(kind)) {
13517 builder.AppendCString("async function* ");
13518 } else if (IsGeneratorFunction(kind)) {
13519 builder.AppendCString("function* ");
13520 } else if (IsAsyncFunction(kind)) {
13521 builder.AppendCString("async function ");
13522 } else {
13523 builder.AppendCString("function ");
13524 }
13525 }
13526 if (shared_info->name_should_print_as_anonymous()) {
13527 builder.AppendCString("anonymous");
13528 } else if (!shared_info->is_anonymous_expression()) {
13529 builder.AppendString(handle(shared_info->Name(), isolate));
13530 }
13531 }
13532 if (shared_info->is_wrapped()) {
13533 builder.AppendCharacter('(');
13534 Handle<FixedArray> args(
13535 Script::cast(shared_info->script())->wrapped_arguments(), isolate);
13536 int argc = args->length();
13537 for (int i = 0; i < argc; i++) {
13538 if (i > 0) builder.AppendCString(", ");
13539 builder.AppendString(Handle<String>(String::cast(args->get(i)), isolate));
13540 }
13541 builder.AppendCString(") {\n");
13542 }
13543 builder.AppendString(
13544 Handle<String>::cast(SharedFunctionInfo::GetSourceCode(shared_info)));
13545 if (shared_info->is_wrapped()) {
13546 builder.AppendCString("\n}");
13547 }
13548 return builder.Finish().ToHandleChecked();
13549 }
13550
Initialize(Isolate * isolate,Handle<Oddball> oddball,const char * to_string,Handle<Object> to_number,const char * type_of,byte kind)13551 void Oddball::Initialize(Isolate* isolate, Handle<Oddball> oddball,
13552 const char* to_string, Handle<Object> to_number,
13553 const char* type_of, byte kind) {
13554 Handle<String> internalized_to_string =
13555 isolate->factory()->InternalizeUtf8String(to_string);
13556 Handle<String> internalized_type_of =
13557 isolate->factory()->InternalizeUtf8String(type_of);
13558 if (to_number->IsHeapNumber()) {
13559 oddball->set_to_number_raw_as_bits(
13560 Handle<HeapNumber>::cast(to_number)->value_as_bits());
13561 } else {
13562 oddball->set_to_number_raw(to_number->Number());
13563 }
13564 oddball->set_to_number(*to_number);
13565 oddball->set_to_string(*internalized_to_string);
13566 oddball->set_type_of(*internalized_type_of);
13567 oddball->set_kind(kind);
13568 }
13569
GetEvalPosition()13570 int Script::GetEvalPosition() {
13571 DisallowHeapAllocation no_gc;
13572 DCHECK(compilation_type() == Script::COMPILATION_TYPE_EVAL);
13573 int position = eval_from_position();
13574 if (position < 0) {
13575 // Due to laziness, the position may not have been translated from code
13576 // offset yet, which would be encoded as negative integer. In that case,
13577 // translate and set the position.
13578 if (!has_eval_from_shared()) {
13579 position = 0;
13580 } else {
13581 SharedFunctionInfo* shared = eval_from_shared();
13582 position = shared->abstract_code()->SourcePosition(-position);
13583 }
13584 DCHECK_GE(position, 0);
13585 set_eval_from_position(position);
13586 }
13587 return position;
13588 }
13589
InitLineEnds(Handle<Script> script)13590 void Script::InitLineEnds(Handle<Script> script) {
13591 Isolate* isolate = script->GetIsolate();
13592 if (!script->line_ends()->IsUndefined(isolate)) return;
13593 DCHECK_NE(Script::TYPE_WASM, script->type());
13594
13595 Object* src_obj = script->source();
13596 if (!src_obj->IsString()) {
13597 DCHECK(src_obj->IsUndefined(isolate));
13598 script->set_line_ends(ReadOnlyRoots(isolate).empty_fixed_array());
13599 } else {
13600 DCHECK(src_obj->IsString());
13601 Handle<String> src(String::cast(src_obj), isolate);
13602 Handle<FixedArray> array = String::CalculateLineEnds(isolate, src, true);
13603 script->set_line_ends(*array);
13604 }
13605
13606 DCHECK(script->line_ends()->IsFixedArray());
13607 }
13608
GetPositionInfo(Handle<Script> script,int position,PositionInfo * info,OffsetFlag offset_flag)13609 bool Script::GetPositionInfo(Handle<Script> script, int position,
13610 PositionInfo* info, OffsetFlag offset_flag) {
13611 // For wasm, we do not create an artificial line_ends array, but do the
13612 // translation directly.
13613 if (script->type() != Script::TYPE_WASM) InitLineEnds(script);
13614 return script->GetPositionInfo(position, info, offset_flag);
13615 }
13616
IsUserJavaScript()13617 bool Script::IsUserJavaScript() { return type() == Script::TYPE_NORMAL; }
13618
ContainsAsmModule()13619 bool Script::ContainsAsmModule() {
13620 DisallowHeapAllocation no_gc;
13621 SharedFunctionInfo::ScriptIterator iter(this->GetIsolate(), this);
13622 while (SharedFunctionInfo* info = iter.Next()) {
13623 if (info->HasAsmWasmData()) return true;
13624 }
13625 return false;
13626 }
13627
13628 namespace {
GetPositionInfoSlow(const Script * script,int position,Script::PositionInfo * info)13629 bool GetPositionInfoSlow(const Script* script, int position,
13630 Script::PositionInfo* info) {
13631 if (!script->source()->IsString()) return false;
13632 if (position < 0) position = 0;
13633
13634 String* source_string = String::cast(script->source());
13635 int line = 0;
13636 int line_start = 0;
13637 int len = source_string->length();
13638 for (int pos = 0; pos <= len; ++pos) {
13639 if (pos == len || source_string->Get(pos) == '\n') {
13640 if (position <= pos) {
13641 info->line = line;
13642 info->column = position - line_start;
13643 info->line_start = line_start;
13644 info->line_end = pos;
13645 return true;
13646 }
13647 line++;
13648 line_start = pos + 1;
13649 }
13650 }
13651 return false;
13652 }
13653 } // namespace
13654
13655 #define SMI_VALUE(x) (Smi::ToInt(x))
GetPositionInfo(int position,PositionInfo * info,OffsetFlag offset_flag) const13656 bool Script::GetPositionInfo(int position, PositionInfo* info,
13657 OffsetFlag offset_flag) const {
13658 DisallowHeapAllocation no_allocation;
13659
13660 // For wasm, we do not rely on the line_ends array, but do the translation
13661 // directly.
13662 if (type() == Script::TYPE_WASM) {
13663 DCHECK_LE(0, position);
13664 return WasmModuleObject::cast(wasm_module_object())
13665 ->GetPositionInfo(static_cast<uint32_t>(position), info);
13666 }
13667
13668 if (line_ends()->IsUndefined()) {
13669 // Slow mode: we do not have line_ends. We have to iterate through source.
13670 if (!GetPositionInfoSlow(this, position, info)) return false;
13671 } else {
13672 DCHECK(line_ends()->IsFixedArray());
13673 FixedArray* ends = FixedArray::cast(line_ends());
13674
13675 const int ends_len = ends->length();
13676 if (ends_len == 0) return false;
13677
13678 // Return early on invalid positions. Negative positions behave as if 0 was
13679 // passed, and positions beyond the end of the script return as failure.
13680 if (position < 0) {
13681 position = 0;
13682 } else if (position > SMI_VALUE(ends->get(ends_len - 1))) {
13683 return false;
13684 }
13685
13686 // Determine line number by doing a binary search on the line ends array.
13687 if (SMI_VALUE(ends->get(0)) >= position) {
13688 info->line = 0;
13689 info->line_start = 0;
13690 info->column = position;
13691 } else {
13692 int left = 0;
13693 int right = ends_len - 1;
13694
13695 while (right > 0) {
13696 DCHECK_LE(left, right);
13697 const int mid = (left + right) / 2;
13698 if (position > SMI_VALUE(ends->get(mid))) {
13699 left = mid + 1;
13700 } else if (position <= SMI_VALUE(ends->get(mid - 1))) {
13701 right = mid - 1;
13702 } else {
13703 info->line = mid;
13704 break;
13705 }
13706 }
13707 DCHECK(SMI_VALUE(ends->get(info->line)) >= position &&
13708 SMI_VALUE(ends->get(info->line - 1)) < position);
13709 info->line_start = SMI_VALUE(ends->get(info->line - 1)) + 1;
13710 info->column = position - info->line_start;
13711 }
13712
13713 // Line end is position of the linebreak character.
13714 info->line_end = SMI_VALUE(ends->get(info->line));
13715 if (info->line_end > 0) {
13716 DCHECK(source()->IsString());
13717 String* src = String::cast(source());
13718 if (src->length() >= info->line_end &&
13719 src->Get(info->line_end - 1) == '\r') {
13720 info->line_end--;
13721 }
13722 }
13723 }
13724
13725 // Add offsets if requested.
13726 if (offset_flag == WITH_OFFSET) {
13727 if (info->line == 0) {
13728 info->column += column_offset();
13729 }
13730 info->line += line_offset();
13731 }
13732
13733 return true;
13734 }
13735 #undef SMI_VALUE
13736
GetColumnNumber(Handle<Script> script,int code_pos)13737 int Script::GetColumnNumber(Handle<Script> script, int code_pos) {
13738 PositionInfo info;
13739 GetPositionInfo(script, code_pos, &info, WITH_OFFSET);
13740 return info.column;
13741 }
13742
GetColumnNumber(int code_pos) const13743 int Script::GetColumnNumber(int code_pos) const {
13744 PositionInfo info;
13745 GetPositionInfo(code_pos, &info, WITH_OFFSET);
13746 return info.column;
13747 }
13748
GetLineNumber(Handle<Script> script,int code_pos)13749 int Script::GetLineNumber(Handle<Script> script, int code_pos) {
13750 PositionInfo info;
13751 GetPositionInfo(script, code_pos, &info, WITH_OFFSET);
13752 return info.line;
13753 }
13754
GetLineNumber(int code_pos) const13755 int Script::GetLineNumber(int code_pos) const {
13756 PositionInfo info;
13757 GetPositionInfo(code_pos, &info, WITH_OFFSET);
13758 return info.line;
13759 }
13760
GetNameOrSourceURL()13761 Object* Script::GetNameOrSourceURL() {
13762 // Keep in sync with ScriptNameOrSourceURL in messages.js.
13763 if (!source_url()->IsUndefined()) return source_url();
13764 return name();
13765 }
13766
FindSharedFunctionInfo(Isolate * isolate,const FunctionLiteral * fun)13767 MaybeHandle<SharedFunctionInfo> Script::FindSharedFunctionInfo(
13768 Isolate* isolate, const FunctionLiteral* fun) {
13769 CHECK_NE(fun->function_literal_id(), FunctionLiteral::kIdTypeInvalid);
13770 // If this check fails, the problem is most probably the function id
13771 // renumbering done by AstFunctionLiteralIdReindexer; in particular, that
13772 // AstTraversalVisitor doesn't recurse properly in the construct which
13773 // triggers the mismatch.
13774 CHECK_LT(fun->function_literal_id(), shared_function_infos()->length());
13775 MaybeObject* shared =
13776 shared_function_infos()->Get(fun->function_literal_id());
13777 HeapObject* heap_object;
13778 if (!shared->ToStrongOrWeakHeapObject(&heap_object) ||
13779 heap_object->IsUndefined(isolate)) {
13780 return MaybeHandle<SharedFunctionInfo>();
13781 }
13782 return handle(SharedFunctionInfo::cast(heap_object), isolate);
13783 }
13784
Iterator(Isolate * isolate)13785 Script::Iterator::Iterator(Isolate* isolate)
13786 : iterator_(isolate->heap()->script_list()) {}
13787
Next()13788 Script* Script::Iterator::Next() {
13789 Object* o = iterator_.Next();
13790 if (o != nullptr) {
13791 return Script::cast(o);
13792 }
13793 return nullptr;
13794 }
13795
GetCode() const13796 Code* SharedFunctionInfo::GetCode() const {
13797 // ======
13798 // NOTE: This chain of checks MUST be kept in sync with the equivalent CSA
13799 // GetSharedFunctionInfoCode method in code-stub-assembler.cc.
13800 // ======
13801
13802 Isolate* isolate = GetIsolate();
13803 Object* data = function_data();
13804 if (data->IsSmi()) {
13805 // Holding a Smi means we are a builtin.
13806 DCHECK(HasBuiltinId());
13807 return isolate->builtins()->builtin(builtin_id());
13808 } else if (data->IsBytecodeArray()) {
13809 // Having a bytecode array means we are a compiled, interpreted function.
13810 DCHECK(HasBytecodeArray());
13811 return isolate->builtins()->builtin(Builtins::kInterpreterEntryTrampoline);
13812 } else if (data->IsFixedArray()) {
13813 // Having a fixed array means we are an asm.js/wasm function.
13814 DCHECK(HasAsmWasmData());
13815 return isolate->builtins()->builtin(Builtins::kInstantiateAsmJs);
13816 } else if (data->IsUncompiledData()) {
13817 // Having uncompiled data (with or without scope) means we need to compile.
13818 DCHECK(HasUncompiledData());
13819 return isolate->builtins()->builtin(Builtins::kCompileLazy);
13820 } else if (data->IsFunctionTemplateInfo()) {
13821 // Having a function template info means we are an API function.
13822 DCHECK(IsApiFunction());
13823 return isolate->builtins()->builtin(Builtins::kHandleApiCall);
13824 } else if (data->IsWasmExportedFunctionData()) {
13825 // Having a WasmExportedFunctionData means the code is in there.
13826 DCHECK(HasWasmExportedFunctionData());
13827 return wasm_exported_function_data()->wrapper_code();
13828 } else if (data->IsInterpreterData()) {
13829 Code* code = InterpreterTrampoline();
13830 DCHECK(code->IsCode());
13831 DCHECK(code->is_interpreter_trampoline_builtin());
13832 return code;
13833 }
13834 UNREACHABLE();
13835 }
13836
wasm_exported_function_data() const13837 WasmExportedFunctionData* SharedFunctionInfo::wasm_exported_function_data()
13838 const {
13839 DCHECK(HasWasmExportedFunctionData());
13840 return WasmExportedFunctionData::cast(function_data());
13841 }
13842
ScriptIterator(Isolate * isolate,Script * script)13843 SharedFunctionInfo::ScriptIterator::ScriptIterator(Isolate* isolate,
13844 Script* script)
13845 : ScriptIterator(isolate,
13846 handle(script->shared_function_infos(), isolate)) {}
13847
ScriptIterator(Isolate * isolate,Handle<WeakFixedArray> shared_function_infos)13848 SharedFunctionInfo::ScriptIterator::ScriptIterator(
13849 Isolate* isolate, Handle<WeakFixedArray> shared_function_infos)
13850 : isolate_(isolate),
13851 shared_function_infos_(shared_function_infos),
13852 index_(0) {}
13853
Next()13854 SharedFunctionInfo* SharedFunctionInfo::ScriptIterator::Next() {
13855 while (index_ < shared_function_infos_->length()) {
13856 MaybeObject* raw = shared_function_infos_->Get(index_++);
13857 HeapObject* heap_object;
13858 if (!raw->ToStrongOrWeakHeapObject(&heap_object) ||
13859 heap_object->IsUndefined(isolate_)) {
13860 continue;
13861 }
13862 return SharedFunctionInfo::cast(heap_object);
13863 }
13864 return nullptr;
13865 }
13866
Reset(Script * script)13867 void SharedFunctionInfo::ScriptIterator::Reset(Script* script) {
13868 shared_function_infos_ = handle(script->shared_function_infos(), isolate_);
13869 index_ = 0;
13870 }
13871
GlobalIterator(Isolate * isolate)13872 SharedFunctionInfo::GlobalIterator::GlobalIterator(Isolate* isolate)
13873 : script_iterator_(isolate),
13874 noscript_sfi_iterator_(isolate->heap()->noscript_shared_function_infos()),
13875 sfi_iterator_(isolate, script_iterator_.Next()) {}
13876
Next()13877 SharedFunctionInfo* SharedFunctionInfo::GlobalIterator::Next() {
13878 HeapObject* next = noscript_sfi_iterator_.Next();
13879 if (next != nullptr) return SharedFunctionInfo::cast(next);
13880 for (;;) {
13881 next = sfi_iterator_.Next();
13882 if (next != nullptr) return SharedFunctionInfo::cast(next);
13883 Script* next_script = script_iterator_.Next();
13884 if (next_script == nullptr) return nullptr;
13885 sfi_iterator_.Reset(next_script);
13886 }
13887 }
13888
SetScript(Handle<SharedFunctionInfo> shared,Handle<Object> script_object,int function_literal_id,bool reset_preparsed_scope_data)13889 void SharedFunctionInfo::SetScript(Handle<SharedFunctionInfo> shared,
13890 Handle<Object> script_object,
13891 int function_literal_id,
13892 bool reset_preparsed_scope_data) {
13893 if (shared->script() == *script_object) return;
13894 Isolate* isolate = shared->GetIsolate();
13895
13896 if (reset_preparsed_scope_data &&
13897 shared->HasUncompiledDataWithPreParsedScope()) {
13898 shared->ClearPreParsedScopeData();
13899 }
13900
13901 // Add shared function info to new script's list. If a collection occurs,
13902 // the shared function info may be temporarily in two lists.
13903 // This is okay because the gc-time processing of these lists can tolerate
13904 // duplicates.
13905 if (script_object->IsScript()) {
13906 DCHECK(!shared->script()->IsScript());
13907 Handle<Script> script = Handle<Script>::cast(script_object);
13908 Handle<WeakFixedArray> list =
13909 handle(script->shared_function_infos(), isolate);
13910 #ifdef DEBUG
13911 DCHECK_LT(function_literal_id, list->length());
13912 MaybeObject* maybe_object = list->Get(function_literal_id);
13913 HeapObject* heap_object;
13914 if (maybe_object->ToWeakHeapObject(&heap_object)) {
13915 DCHECK_EQ(heap_object, *shared);
13916 }
13917 #endif
13918 list->Set(function_literal_id, HeapObjectReference::Weak(*shared));
13919
13920 // Remove shared function info from root array.
13921 WeakArrayList* noscript_list =
13922 isolate->heap()->noscript_shared_function_infos();
13923 CHECK(noscript_list->RemoveOne(MaybeObjectHandle::Weak(shared)));
13924 } else {
13925 DCHECK(shared->script()->IsScript());
13926 Handle<WeakArrayList> list =
13927 isolate->factory()->noscript_shared_function_infos();
13928
13929 #ifdef DEBUG
13930 if (FLAG_enable_slow_asserts) {
13931 WeakArrayList::Iterator iterator(*list);
13932 HeapObject* next;
13933 while ((next = iterator.Next()) != nullptr) {
13934 DCHECK_NE(next, *shared);
13935 }
13936 }
13937 #endif // DEBUG
13938
13939 list =
13940 WeakArrayList::AddToEnd(isolate, list, MaybeObjectHandle::Weak(shared));
13941
13942 isolate->heap()->SetRootNoScriptSharedFunctionInfos(*list);
13943
13944 // Remove shared function info from old script's list.
13945 Script* old_script = Script::cast(shared->script());
13946
13947 // Due to liveedit, it might happen that the old_script doesn't know
13948 // about the SharedFunctionInfo, so we have to guard against that.
13949 Handle<WeakFixedArray> infos(old_script->shared_function_infos(), isolate);
13950 if (function_literal_id < infos->length()) {
13951 MaybeObject* raw =
13952 old_script->shared_function_infos()->Get(function_literal_id);
13953 HeapObject* heap_object;
13954 if (raw->ToWeakHeapObject(&heap_object) && heap_object == *shared) {
13955 old_script->shared_function_infos()->Set(
13956 function_literal_id, HeapObjectReference::Strong(
13957 ReadOnlyRoots(isolate).undefined_value()));
13958 }
13959 }
13960 }
13961
13962 // Finally set new script.
13963 shared->set_script(*script_object);
13964 }
13965
HasBreakInfo() const13966 bool SharedFunctionInfo::HasBreakInfo() const {
13967 if (!HasDebugInfo()) return false;
13968 DebugInfo* info = DebugInfo::cast(GetDebugInfo());
13969 bool has_break_info = info->HasBreakInfo();
13970 return has_break_info;
13971 }
13972
BreakAtEntry() const13973 bool SharedFunctionInfo::BreakAtEntry() const {
13974 if (!HasDebugInfo()) return false;
13975 DebugInfo* info = DebugInfo::cast(GetDebugInfo());
13976 bool break_at_entry = info->BreakAtEntry();
13977 return break_at_entry;
13978 }
13979
HasCoverageInfo() const13980 bool SharedFunctionInfo::HasCoverageInfo() const {
13981 if (!HasDebugInfo()) return false;
13982 DebugInfo* info = DebugInfo::cast(GetDebugInfo());
13983 bool has_coverage_info = info->HasCoverageInfo();
13984 return has_coverage_info;
13985 }
13986
GetCoverageInfo() const13987 CoverageInfo* SharedFunctionInfo::GetCoverageInfo() const {
13988 DCHECK(HasCoverageInfo());
13989 return CoverageInfo::cast(GetDebugInfo()->coverage_info());
13990 }
13991
DebugName()13992 String* SharedFunctionInfo::DebugName() {
13993 DisallowHeapAllocation no_gc;
13994 String* function_name = Name();
13995 if (function_name->length() > 0) return function_name;
13996 return inferred_name();
13997 }
13998
PassesFilter(const char * raw_filter)13999 bool SharedFunctionInfo::PassesFilter(const char* raw_filter) {
14000 Vector<const char> filter = CStrVector(raw_filter);
14001 std::unique_ptr<char[]> cstrname(DebugName()->ToCString());
14002 return v8::internal::PassesFilter(CStrVector(cstrname.get()), filter);
14003 }
14004
HasSourceCode() const14005 bool SharedFunctionInfo::HasSourceCode() const {
14006 Isolate* isolate = GetIsolate();
14007 return !script()->IsUndefined(isolate) &&
14008 !reinterpret_cast<Script*>(script())->source()->IsUndefined(isolate);
14009 }
14010
14011 // static
GetSourceCode(Handle<SharedFunctionInfo> shared)14012 Handle<Object> SharedFunctionInfo::GetSourceCode(
14013 Handle<SharedFunctionInfo> shared) {
14014 Isolate* isolate = shared->GetIsolate();
14015 if (!shared->HasSourceCode()) return isolate->factory()->undefined_value();
14016 Handle<String> source(String::cast(Script::cast(shared->script())->source()),
14017 isolate);
14018 return isolate->factory()->NewSubString(source, shared->StartPosition(),
14019 shared->EndPosition());
14020 }
14021
14022 // static
GetSourceCodeHarmony(Handle<SharedFunctionInfo> shared)14023 Handle<Object> SharedFunctionInfo::GetSourceCodeHarmony(
14024 Handle<SharedFunctionInfo> shared) {
14025 Isolate* isolate = shared->GetIsolate();
14026 if (!shared->HasSourceCode()) return isolate->factory()->undefined_value();
14027 Handle<String> script_source(
14028 String::cast(Script::cast(shared->script())->source()), isolate);
14029 int start_pos = shared->function_token_position();
14030 DCHECK_NE(start_pos, kNoSourcePosition);
14031 Handle<String> source = isolate->factory()->NewSubString(
14032 script_source, start_pos, shared->EndPosition());
14033 if (!shared->is_wrapped()) return source;
14034
14035 DCHECK(!shared->name_should_print_as_anonymous());
14036 IncrementalStringBuilder builder(isolate);
14037 builder.AppendCString("function ");
14038 builder.AppendString(Handle<String>(shared->Name(), isolate));
14039 builder.AppendCString("(");
14040 Handle<FixedArray> args(Script::cast(shared->script())->wrapped_arguments(),
14041 isolate);
14042 int argc = args->length();
14043 for (int i = 0; i < argc; i++) {
14044 if (i > 0) builder.AppendCString(", ");
14045 builder.AppendString(Handle<String>(String::cast(args->get(i)), isolate));
14046 }
14047 builder.AppendCString(") {\n");
14048 builder.AppendString(source);
14049 builder.AppendCString("\n}");
14050 return builder.Finish().ToHandleChecked();
14051 }
14052
IsInlineable()14053 bool SharedFunctionInfo::IsInlineable() {
14054 // Check that the function has a script associated with it.
14055 if (!script()->IsScript()) return false;
14056 if (GetIsolate()->is_precise_binary_code_coverage() &&
14057 !has_reported_binary_coverage()) {
14058 // We may miss invocations if this function is inlined.
14059 return false;
14060 }
14061 return !optimization_disabled();
14062 }
14063
SourceSize()14064 int SharedFunctionInfo::SourceSize() { return EndPosition() - StartPosition(); }
14065
FindIndexInScript(Isolate * isolate) const14066 int SharedFunctionInfo::FindIndexInScript(Isolate* isolate) const {
14067 DisallowHeapAllocation no_gc;
14068
14069 Object* script_obj = script();
14070 if (!script_obj->IsScript()) return FunctionLiteral::kIdTypeInvalid;
14071
14072 WeakFixedArray* shared_info_list =
14073 Script::cast(script_obj)->shared_function_infos();
14074 SharedFunctionInfo::ScriptIterator iterator(
14075 isolate, Handle<WeakFixedArray>(&shared_info_list));
14076
14077 for (SharedFunctionInfo* shared = iterator.Next(); shared != nullptr;
14078 shared = iterator.Next()) {
14079 if (shared == this) {
14080 return iterator.CurrentIndex();
14081 }
14082 }
14083
14084 return FunctionLiteral::kIdTypeInvalid;
14085 }
14086
CalculateInstanceSizeHelper(InstanceType instance_type,bool has_prototype_slot,int requested_embedder_fields,int requested_in_object_properties,int * instance_size,int * in_object_properties)14087 void JSFunction::CalculateInstanceSizeHelper(InstanceType instance_type,
14088 bool has_prototype_slot,
14089 int requested_embedder_fields,
14090 int requested_in_object_properties,
14091 int* instance_size,
14092 int* in_object_properties) {
14093 DCHECK_LE(static_cast<unsigned>(requested_embedder_fields),
14094 JSObject::kMaxEmbedderFields);
14095 int header_size = JSObject::GetHeaderSize(instance_type, has_prototype_slot);
14096 int max_nof_fields =
14097 (JSObject::kMaxInstanceSize - header_size) >> kPointerSizeLog2;
14098 CHECK_LE(max_nof_fields, JSObject::kMaxInObjectProperties);
14099 CHECK_LE(static_cast<unsigned>(requested_embedder_fields),
14100 static_cast<unsigned>(max_nof_fields));
14101 *in_object_properties = Min(requested_in_object_properties,
14102 max_nof_fields - requested_embedder_fields);
14103 *instance_size =
14104 header_size +
14105 ((requested_embedder_fields + *in_object_properties) << kPointerSizeLog2);
14106 CHECK_EQ(*in_object_properties,
14107 ((*instance_size - header_size) >> kPointerSizeLog2) -
14108 requested_embedder_fields);
14109 CHECK_LE(static_cast<unsigned>(*instance_size),
14110 static_cast<unsigned>(JSObject::kMaxInstanceSize));
14111 }
14112
14113 // static
CalculateInstanceSizeForDerivedClass(Handle<JSFunction> function,InstanceType instance_type,int requested_embedder_fields,int * instance_size,int * in_object_properties)14114 bool JSFunction::CalculateInstanceSizeForDerivedClass(
14115 Handle<JSFunction> function, InstanceType instance_type,
14116 int requested_embedder_fields, int* instance_size,
14117 int* in_object_properties) {
14118 Isolate* isolate = function->GetIsolate();
14119 int expected_nof_properties = 0;
14120 for (PrototypeIterator iter(isolate, function, kStartAtReceiver);
14121 !iter.IsAtEnd(); iter.Advance()) {
14122 Handle<JSReceiver> current =
14123 PrototypeIterator::GetCurrent<JSReceiver>(iter);
14124 if (!current->IsJSFunction()) break;
14125 Handle<JSFunction> func(Handle<JSFunction>::cast(current));
14126 // The super constructor should be compiled for the number of expected
14127 // properties to be available.
14128 Handle<SharedFunctionInfo> shared(func->shared(), isolate);
14129 if (shared->is_compiled() ||
14130 Compiler::Compile(func, Compiler::CLEAR_EXCEPTION)) {
14131 DCHECK(shared->is_compiled());
14132 int count = shared->expected_nof_properties();
14133 // Check that the estimate is sane.
14134 if (expected_nof_properties <= JSObject::kMaxInObjectProperties - count) {
14135 expected_nof_properties += count;
14136 } else {
14137 expected_nof_properties = JSObject::kMaxInObjectProperties;
14138 }
14139 } else if (!shared->is_compiled()) {
14140 // In case there was a compilation error for the constructor we will
14141 // throw an error during instantiation. Hence we directly return 0;
14142 return false;
14143 }
14144 if (!IsDerivedConstructor(shared->kind())) break;
14145 }
14146 CalculateInstanceSizeHelper(instance_type, true, requested_embedder_fields,
14147 expected_nof_properties, instance_size,
14148 in_object_properties);
14149 return true;
14150 }
14151
14152
14153 // Output the source code without any allocation in the heap.
operator <<(std::ostream & os,const SourceCodeOf & v)14154 std::ostream& operator<<(std::ostream& os, const SourceCodeOf& v) {
14155 const SharedFunctionInfo* s = v.value;
14156 // For some native functions there is no source.
14157 if (!s->HasSourceCode()) return os << "<No Source>";
14158
14159 // Get the source for the script which this function came from.
14160 // Don't use String::cast because we don't want more assertion errors while
14161 // we are already creating a stack dump.
14162 String* script_source =
14163 reinterpret_cast<String*>(Script::cast(s->script())->source());
14164
14165 if (!script_source->LooksValid()) return os << "<Invalid Source>";
14166
14167 if (!s->is_toplevel()) {
14168 os << "function ";
14169 String* name = s->Name();
14170 if (name->length() > 0) {
14171 name->PrintUC16(os);
14172 }
14173 }
14174
14175 int len = s->EndPosition() - s->StartPosition();
14176 if (len <= v.max_length || v.max_length < 0) {
14177 script_source->PrintUC16(os, s->StartPosition(), s->EndPosition());
14178 return os;
14179 } else {
14180 script_source->PrintUC16(os, s->StartPosition(),
14181 s->StartPosition() + v.max_length);
14182 return os << "...\n";
14183 }
14184 }
14185
14186
DisableOptimization(BailoutReason reason)14187 void SharedFunctionInfo::DisableOptimization(BailoutReason reason) {
14188 DCHECK_NE(reason, BailoutReason::kNoReason);
14189
14190 set_flags(DisabledOptimizationReasonBits::update(flags(), reason));
14191 // Code should be the lazy compilation stub or else interpreted.
14192 DCHECK(abstract_code()->kind() == AbstractCode::INTERPRETED_FUNCTION ||
14193 abstract_code()->kind() == AbstractCode::BUILTIN);
14194 PROFILE(GetIsolate(), CodeDisableOptEvent(abstract_code(), this));
14195 if (FLAG_trace_opt) {
14196 PrintF("[disabled optimization for ");
14197 ShortPrint();
14198 PrintF(", reason: %s]\n", GetBailoutReason(reason));
14199 }
14200 }
14201
InitFromFunctionLiteral(Handle<SharedFunctionInfo> shared_info,FunctionLiteral * lit,bool is_toplevel)14202 void SharedFunctionInfo::InitFromFunctionLiteral(
14203 Handle<SharedFunctionInfo> shared_info, FunctionLiteral* lit,
14204 bool is_toplevel) {
14205 Isolate* isolate = shared_info->GetIsolate();
14206 bool needs_position_info = true;
14207
14208 // When adding fields here, make sure DeclarationScope::AnalyzePartially is
14209 // updated accordingly.
14210 shared_info->set_internal_formal_parameter_count(lit->parameter_count());
14211 shared_info->SetFunctionTokenPosition(lit->function_token_position(),
14212 lit->start_position());
14213 if (shared_info->scope_info()->HasPositionInfo()) {
14214 shared_info->scope_info()->SetPositionInfo(lit->start_position(),
14215 lit->end_position());
14216 needs_position_info = false;
14217 }
14218 shared_info->set_is_declaration(lit->is_declaration());
14219 shared_info->set_is_named_expression(lit->is_named_expression());
14220 shared_info->set_is_anonymous_expression(lit->is_anonymous_expression());
14221 shared_info->set_allows_lazy_compilation(lit->AllowsLazyCompilation());
14222 shared_info->set_language_mode(lit->language_mode());
14223 shared_info->set_is_wrapped(lit->is_wrapped());
14224 // shared_info->set_kind(lit->kind());
14225 // FunctionKind must have already been set.
14226 DCHECK(lit->kind() == shared_info->kind());
14227 shared_info->set_needs_home_object(lit->scope()->NeedsHomeObject());
14228 DCHECK_IMPLIES(lit->requires_instance_fields_initializer(),
14229 IsClassConstructor(lit->kind()));
14230 shared_info->set_requires_instance_fields_initializer(
14231 lit->requires_instance_fields_initializer());
14232
14233 shared_info->set_is_toplevel(is_toplevel);
14234 DCHECK(shared_info->outer_scope_info()->IsTheHole());
14235 if (!is_toplevel) {
14236 Scope* outer_scope = lit->scope()->GetOuterScopeWithContext();
14237 if (outer_scope) {
14238 shared_info->set_outer_scope_info(*outer_scope->scope_info());
14239 }
14240 }
14241
14242 // For lazy parsed functions, the following flags will be inaccurate since we
14243 // don't have the information yet. They're set later in
14244 // SetSharedFunctionFlagsFromLiteral (compiler.cc), when the function is
14245 // really parsed and compiled.
14246 if (lit->body() != nullptr) {
14247 shared_info->set_length(lit->function_length());
14248 shared_info->set_has_duplicate_parameters(lit->has_duplicate_parameters());
14249 shared_info->SetExpectedNofPropertiesFromEstimate(lit);
14250 DCHECK_NULL(lit->produced_preparsed_scope_data());
14251 if (lit->ShouldEagerCompile()) {
14252 // If we're about to eager compile, we'll have the function literal
14253 // available, so there's no need to wastefully allocate an uncompiled
14254 // data.
14255 // TODO(leszeks): This should be explicitly passed as a parameter, rather
14256 // than relying on a property of the literal.
14257 needs_position_info = false;
14258 }
14259 } else {
14260 // Set an invalid length for lazy functions. This way we can set the correct
14261 // value after compiling, but avoid overwriting values set manually by the
14262 // bootstrapper.
14263 shared_info->set_length(SharedFunctionInfo::kInvalidLength);
14264 if (FLAG_preparser_scope_analysis) {
14265 ProducedPreParsedScopeData* scope_data =
14266 lit->produced_preparsed_scope_data();
14267 if (scope_data != nullptr) {
14268 Handle<PreParsedScopeData> pre_parsed_scope_data;
14269 if (scope_data->Serialize(shared_info->GetIsolate())
14270 .ToHandle(&pre_parsed_scope_data)) {
14271 Handle<UncompiledData> data =
14272 isolate->factory()->NewUncompiledDataWithPreParsedScope(
14273 lit->inferred_name(), lit->start_position(),
14274 lit->end_position(), lit->function_literal_id(),
14275 pre_parsed_scope_data);
14276 shared_info->set_uncompiled_data(*data);
14277 needs_position_info = false;
14278 }
14279 }
14280 }
14281 }
14282 if (needs_position_info) {
14283 Handle<UncompiledData> data =
14284 isolate->factory()->NewUncompiledDataWithoutPreParsedScope(
14285 lit->inferred_name(), lit->start_position(), lit->end_position(),
14286 lit->function_literal_id());
14287 shared_info->set_uncompiled_data(*data);
14288 }
14289 }
14290
SetExpectedNofPropertiesFromEstimate(FunctionLiteral * literal)14291 void SharedFunctionInfo::SetExpectedNofPropertiesFromEstimate(
14292 FunctionLiteral* literal) {
14293 int estimate = literal->expected_property_count();
14294
14295 // If no properties are added in the constructor, they are more likely
14296 // to be added later.
14297 if (estimate == 0) estimate = 2;
14298
14299 // Inobject slack tracking will reclaim redundant inobject space later,
14300 // so we can afford to adjust the estimate generously.
14301 estimate += 8;
14302
14303 // Limit actual estimate to fit in a 8 bit field, we will never allocate
14304 // more than this in any case.
14305 STATIC_ASSERT(JSObject::kMaxInObjectProperties <= kMaxUInt8);
14306 estimate = std::min(estimate, kMaxUInt8);
14307
14308 set_expected_nof_properties(estimate);
14309 }
14310
SetFunctionTokenPosition(int function_token_position,int start_position)14311 void SharedFunctionInfo::SetFunctionTokenPosition(int function_token_position,
14312 int start_position) {
14313 int offset;
14314 if (function_token_position == kNoSourcePosition) {
14315 offset = 0;
14316 } else {
14317 offset = start_position - function_token_position;
14318 }
14319
14320 if (offset > kMaximumFunctionTokenOffset) {
14321 offset = kFunctionTokenOutOfRange;
14322 }
14323 set_raw_function_token_offset(offset);
14324 }
14325
StartInobjectSlackTracking()14326 void Map::StartInobjectSlackTracking() {
14327 DCHECK(!IsInobjectSlackTrackingInProgress());
14328 if (UnusedPropertyFields() == 0) return;
14329 set_construction_counter(Map::kSlackTrackingCounterStart);
14330 }
14331
VisitCodeTarget(Code * host,RelocInfo * rinfo)14332 void ObjectVisitor::VisitCodeTarget(Code* host, RelocInfo* rinfo) {
14333 DCHECK(RelocInfo::IsCodeTargetMode(rinfo->rmode()));
14334 Object* old_pointer = Code::GetCodeFromTargetAddress(rinfo->target_address());
14335 Object* new_pointer = old_pointer;
14336 VisitPointer(host, &new_pointer);
14337 DCHECK_EQ(old_pointer, new_pointer);
14338 }
14339
VisitEmbeddedPointer(Code * host,RelocInfo * rinfo)14340 void ObjectVisitor::VisitEmbeddedPointer(Code* host, RelocInfo* rinfo) {
14341 DCHECK(rinfo->rmode() == RelocInfo::EMBEDDED_OBJECT);
14342 Object* old_pointer = rinfo->target_object();
14343 Object* new_pointer = old_pointer;
14344 VisitPointer(host, &new_pointer);
14345 DCHECK_EQ(old_pointer, new_pointer);
14346 }
14347
VisitRelocInfo(RelocIterator * it)14348 void ObjectVisitor::VisitRelocInfo(RelocIterator* it) {
14349 for (; !it->done(); it->next()) {
14350 it->rinfo()->Visit(this);
14351 }
14352 }
14353
InvalidateEmbeddedObjects(Heap * heap)14354 void Code::InvalidateEmbeddedObjects(Heap* heap) {
14355 HeapObject* undefined = ReadOnlyRoots(heap).undefined_value();
14356 int mode_mask = RelocInfo::ModeMask(RelocInfo::EMBEDDED_OBJECT);
14357 for (RelocIterator it(this, mode_mask); !it.done(); it.next()) {
14358 RelocInfo::Mode mode = it.rinfo()->rmode();
14359 if (mode == RelocInfo::EMBEDDED_OBJECT) {
14360 it.rinfo()->set_target_object(heap, undefined, SKIP_WRITE_BARRIER);
14361 }
14362 }
14363 }
14364
14365
Relocate(intptr_t delta)14366 void Code::Relocate(intptr_t delta) {
14367 for (RelocIterator it(this, RelocInfo::kApplyMask); !it.done(); it.next()) {
14368 it.rinfo()->apply(delta);
14369 }
14370 Assembler::FlushICache(raw_instruction_start(), raw_instruction_size());
14371 }
14372
FlushICache() const14373 void Code::FlushICache() const {
14374 Assembler::FlushICache(raw_instruction_start(), raw_instruction_size());
14375 }
14376
CopyFrom(Heap * heap,const CodeDesc & desc)14377 void Code::CopyFrom(Heap* heap, const CodeDesc& desc) {
14378 CopyFromNoFlush(heap, desc);
14379 FlushICache();
14380 }
14381
CopyFromNoFlush(Heap * heap,const CodeDesc & desc)14382 void Code::CopyFromNoFlush(Heap* heap, const CodeDesc& desc) {
14383 // Copy code.
14384 CopyBytes(reinterpret_cast<byte*>(raw_instruction_start()), desc.buffer,
14385 static_cast<size_t>(desc.instr_size));
14386
14387 // Copy unwinding info, if any.
14388 if (desc.unwinding_info) {
14389 DCHECK_GT(desc.unwinding_info_size, 0);
14390 set_unwinding_info_size(desc.unwinding_info_size);
14391 CopyBytes(reinterpret_cast<byte*>(unwinding_info_start()),
14392 desc.unwinding_info,
14393 static_cast<size_t>(desc.unwinding_info_size));
14394 }
14395
14396 // Copy reloc info.
14397 CopyBytes(relocation_start(),
14398 desc.buffer + desc.buffer_size - desc.reloc_size,
14399 static_cast<size_t>(desc.reloc_size));
14400
14401 // Unbox handles and relocate.
14402 Assembler* origin = desc.origin;
14403 AllowDeferredHandleDereference embedding_raw_address;
14404 const int mode_mask = RelocInfo::PostCodegenRelocationMask();
14405 for (RelocIterator it(this, mode_mask); !it.done(); it.next()) {
14406 RelocInfo::Mode mode = it.rinfo()->rmode();
14407 if (mode == RelocInfo::EMBEDDED_OBJECT) {
14408 Handle<HeapObject> p = it.rinfo()->target_object_handle(origin);
14409 it.rinfo()->set_target_object(heap, *p, UPDATE_WRITE_BARRIER,
14410 SKIP_ICACHE_FLUSH);
14411 } else if (RelocInfo::IsCodeTargetMode(mode)) {
14412 // Rewrite code handles to direct pointers to the first instruction in the
14413 // code object.
14414 Handle<Object> p = it.rinfo()->target_object_handle(origin);
14415 Code* code = Code::cast(*p);
14416 it.rinfo()->set_target_address(code->raw_instruction_start(),
14417 UPDATE_WRITE_BARRIER, SKIP_ICACHE_FLUSH);
14418 } else if (RelocInfo::IsRuntimeEntry(mode)) {
14419 Address p = it.rinfo()->target_runtime_entry(origin);
14420 it.rinfo()->set_target_runtime_entry(p, UPDATE_WRITE_BARRIER,
14421 SKIP_ICACHE_FLUSH);
14422 } else {
14423 intptr_t delta =
14424 raw_instruction_start() - reinterpret_cast<Address>(desc.buffer);
14425 it.rinfo()->apply(delta);
14426 }
14427 }
14428 }
14429
14430
GetSafepointEntry(Address pc)14431 SafepointEntry Code::GetSafepointEntry(Address pc) {
14432 SafepointTable table(this);
14433 return table.FindEntry(pc);
14434 }
14435
OffHeapInstructionSize() const14436 int Code::OffHeapInstructionSize() const {
14437 DCHECK(is_off_heap_trampoline());
14438 if (Isolate::CurrentEmbeddedBlob() == nullptr) return raw_instruction_size();
14439 EmbeddedData d = EmbeddedData::FromBlob();
14440 return d.InstructionSizeOfBuiltin(builtin_index());
14441 }
14442
OffHeapInstructionStart() const14443 Address Code::OffHeapInstructionStart() const {
14444 DCHECK(is_off_heap_trampoline());
14445 if (Isolate::CurrentEmbeddedBlob() == nullptr) return raw_instruction_start();
14446 EmbeddedData d = EmbeddedData::FromBlob();
14447 return d.InstructionStartOfBuiltin(builtin_index());
14448 }
14449
OffHeapInstructionEnd() const14450 Address Code::OffHeapInstructionEnd() const {
14451 DCHECK(is_off_heap_trampoline());
14452 if (Isolate::CurrentEmbeddedBlob() == nullptr) return raw_instruction_end();
14453 EmbeddedData d = EmbeddedData::FromBlob();
14454 return d.InstructionStartOfBuiltin(builtin_index()) +
14455 d.InstructionSizeOfBuiltin(builtin_index());
14456 }
14457
14458 namespace {
14459 template <typename Code>
SetStackFrameCacheCommon(Isolate * isolate,Handle<Code> code,Handle<SimpleNumberDictionary> cache)14460 void SetStackFrameCacheCommon(Isolate* isolate, Handle<Code> code,
14461 Handle<SimpleNumberDictionary> cache) {
14462 Handle<Object> maybe_table(code->source_position_table(), isolate);
14463 if (maybe_table->IsSourcePositionTableWithFrameCache()) {
14464 Handle<SourcePositionTableWithFrameCache>::cast(maybe_table)
14465 ->set_stack_frame_cache(*cache);
14466 return;
14467 }
14468 DCHECK(maybe_table->IsByteArray());
14469 Handle<ByteArray> table(Handle<ByteArray>::cast(maybe_table));
14470 Handle<SourcePositionTableWithFrameCache> table_with_cache =
14471 isolate->factory()->NewSourcePositionTableWithFrameCache(table, cache);
14472 code->set_source_position_table(*table_with_cache);
14473 }
14474 } // namespace
14475
14476 // static
SetStackFrameCache(Handle<AbstractCode> abstract_code,Handle<SimpleNumberDictionary> cache)14477 void AbstractCode::SetStackFrameCache(Handle<AbstractCode> abstract_code,
14478 Handle<SimpleNumberDictionary> cache) {
14479 if (abstract_code->IsCode()) {
14480 SetStackFrameCacheCommon(
14481 abstract_code->GetIsolate(),
14482 handle(abstract_code->GetCode(), abstract_code->GetIsolate()), cache);
14483 } else {
14484 SetStackFrameCacheCommon(
14485 abstract_code->GetIsolate(),
14486 handle(abstract_code->GetBytecodeArray(), abstract_code->GetIsolate()),
14487 cache);
14488 }
14489 }
14490
14491 namespace {
14492 template <typename Code>
DropStackFrameCacheCommon(Code * code)14493 void DropStackFrameCacheCommon(Code* code) {
14494 i::Object* maybe_table = code->source_position_table();
14495 if (maybe_table->IsByteArray()) return;
14496 DCHECK(maybe_table->IsSourcePositionTableWithFrameCache());
14497 code->set_source_position_table(
14498 i::SourcePositionTableWithFrameCache::cast(maybe_table)
14499 ->source_position_table());
14500 }
14501 } // namespace
14502
DropStackFrameCache()14503 void AbstractCode::DropStackFrameCache() {
14504 if (IsCode()) {
14505 DropStackFrameCacheCommon(GetCode());
14506 } else {
14507 DropStackFrameCacheCommon(GetBytecodeArray());
14508 }
14509 }
14510
SourcePosition(int offset)14511 int AbstractCode::SourcePosition(int offset) {
14512 int position = 0;
14513 // Subtract one because the current PC is one instruction after the call site.
14514 if (IsCode()) offset--;
14515 for (SourcePositionTableIterator iterator(source_position_table());
14516 !iterator.done() && iterator.code_offset() <= offset;
14517 iterator.Advance()) {
14518 position = iterator.source_position().ScriptOffset();
14519 }
14520 return position;
14521 }
14522
SourceStatementPosition(int offset)14523 int AbstractCode::SourceStatementPosition(int offset) {
14524 // First find the closest position.
14525 int position = SourcePosition(offset);
14526 // Now find the closest statement position before the position.
14527 int statement_position = 0;
14528 for (SourcePositionTableIterator it(source_position_table()); !it.done();
14529 it.Advance()) {
14530 if (it.is_statement()) {
14531 int p = it.source_position().ScriptOffset();
14532 if (statement_position < p && p <= position) {
14533 statement_position = p;
14534 }
14535 }
14536 }
14537 return statement_position;
14538 }
14539
ClearTypeFeedbackInfo()14540 void JSFunction::ClearTypeFeedbackInfo() {
14541 if (feedback_cell()->value()->IsFeedbackVector()) {
14542 FeedbackVector* vector = feedback_vector();
14543 Isolate* isolate = GetIsolate();
14544 if (vector->ClearSlots(isolate)) {
14545 IC::OnFeedbackChanged(isolate, vector, FeedbackSlot::Invalid(), this,
14546 "ClearTypeFeedbackInfo");
14547 }
14548 }
14549 }
14550
PrintDeoptLocation(FILE * out,const char * str,Address pc)14551 void Code::PrintDeoptLocation(FILE* out, const char* str, Address pc) {
14552 Deoptimizer::DeoptInfo info = Deoptimizer::GetDeoptInfo(this, pc);
14553 class SourcePosition pos = info.position;
14554 if (info.deopt_reason != DeoptimizeReason::kUnknown || pos.IsKnown()) {
14555 PrintF(out, "%s", str);
14556 OFStream outstr(out);
14557 pos.Print(outstr, this);
14558 PrintF(out, ", %s\n", DeoptimizeReasonToString(info.deopt_reason));
14559 }
14560 }
14561
14562
CanDeoptAt(Address pc)14563 bool Code::CanDeoptAt(Address pc) {
14564 DeoptimizationData* deopt_data =
14565 DeoptimizationData::cast(deoptimization_data());
14566 Address code_start_address = InstructionStart();
14567 for (int i = 0; i < deopt_data->DeoptCount(); i++) {
14568 if (deopt_data->Pc(i)->value() == -1) continue;
14569 Address address = code_start_address + deopt_data->Pc(i)->value();
14570 if (address == pc && deopt_data->BytecodeOffset(i) != BailoutId::None()) {
14571 return true;
14572 }
14573 }
14574 return false;
14575 }
14576
14577
14578 // Identify kind of code.
Kind2String(Kind kind)14579 const char* Code::Kind2String(Kind kind) {
14580 switch (kind) {
14581 #define CASE(name) case name: return #name;
14582 CODE_KIND_LIST(CASE)
14583 #undef CASE
14584 case NUMBER_OF_KINDS: break;
14585 }
14586 UNREACHABLE();
14587 }
14588
14589 // Identify kind of code.
Kind2String(Kind kind)14590 const char* AbstractCode::Kind2String(Kind kind) {
14591 if (kind < AbstractCode::INTERPRETED_FUNCTION)
14592 return Code::Kind2String((Code::Kind)kind);
14593 if (kind == AbstractCode::INTERPRETED_FUNCTION) return "INTERPRETED_FUNCTION";
14594 UNREACHABLE();
14595 }
14596
IsIsolateIndependent(Isolate * isolate)14597 bool Code::IsIsolateIndependent(Isolate* isolate) {
14598 constexpr int all_real_modes_mask =
14599 (1 << (RelocInfo::LAST_REAL_RELOC_MODE + 1)) - 1;
14600 constexpr int mode_mask = all_real_modes_mask &
14601 ~RelocInfo::ModeMask(RelocInfo::COMMENT) &
14602 ~RelocInfo::ModeMask(RelocInfo::CONST_POOL) &
14603 ~RelocInfo::ModeMask(RelocInfo::OFF_HEAP_TARGET) &
14604 ~RelocInfo::ModeMask(RelocInfo::VENEER_POOL);
14605 STATIC_ASSERT(RelocInfo::LAST_REAL_RELOC_MODE == RelocInfo::VENEER_POOL);
14606 STATIC_ASSERT(RelocInfo::ModeMask(RelocInfo::COMMENT) ==
14607 (1 << RelocInfo::COMMENT));
14608 STATIC_ASSERT(mode_mask ==
14609 (RelocInfo::ModeMask(RelocInfo::CODE_TARGET) |
14610 RelocInfo::ModeMask(RelocInfo::RELATIVE_CODE_TARGET) |
14611 RelocInfo::ModeMask(RelocInfo::EMBEDDED_OBJECT) |
14612 RelocInfo::ModeMask(RelocInfo::EXTERNAL_REFERENCE) |
14613 RelocInfo::ModeMask(RelocInfo::INTERNAL_REFERENCE) |
14614 RelocInfo::ModeMask(RelocInfo::INTERNAL_REFERENCE_ENCODED) |
14615 RelocInfo::ModeMask(RelocInfo::JS_TO_WASM_CALL) |
14616 RelocInfo::ModeMask(RelocInfo::RUNTIME_ENTRY) |
14617 RelocInfo::ModeMask(RelocInfo::WASM_CALL) |
14618 RelocInfo::ModeMask(RelocInfo::WASM_STUB_CALL)));
14619
14620 bool is_process_independent = true;
14621 for (RelocIterator it(this, mode_mask); !it.done(); it.next()) {
14622 #if defined(V8_TARGET_ARCH_X64) || defined(V8_TARGET_ARCH_ARM64) || \
14623 defined(V8_TARGET_ARCH_ARM)
14624 // On X64, ARM, ARM64 we emit relative builtin-to-builtin jumps for isolate
14625 // independent builtins in the snapshot. They are later rewritten as
14626 // pc-relative jumps to the off-heap instruction stream and are thus
14627 // process-independent.
14628 // See also: FinalizeEmbeddedCodeTargets.
14629 if (RelocInfo::IsCodeTargetMode(it.rinfo()->rmode())) {
14630 Address target_address = it.rinfo()->target_address();
14631 if (InstructionStream::PcIsOffHeap(isolate, target_address)) continue;
14632
14633 Code* target = Code::GetCodeFromTargetAddress(target_address);
14634 CHECK(target->IsCode());
14635 if (Builtins::IsIsolateIndependentBuiltin(target)) continue;
14636 }
14637 #endif
14638 is_process_independent = false;
14639 }
14640
14641 return is_process_independent;
14642 }
14643
Inlines(SharedFunctionInfo * sfi)14644 bool Code::Inlines(SharedFunctionInfo* sfi) {
14645 // We can only check for inlining for optimized code.
14646 DCHECK(is_optimized_code());
14647 DisallowHeapAllocation no_gc;
14648 DeoptimizationData* const data =
14649 DeoptimizationData::cast(deoptimization_data());
14650 if (data->length() == 0) return false;
14651 if (data->SharedFunctionInfo() == sfi) return true;
14652 FixedArray* const literals = data->LiteralArray();
14653 int const inlined_count = data->InlinedFunctionCount()->value();
14654 for (int i = 0; i < inlined_count; ++i) {
14655 if (SharedFunctionInfo::cast(literals->get(i)) == sfi) return true;
14656 }
14657 return false;
14658 }
14659
OptimizedCodeIterator(Isolate * isolate)14660 Code::OptimizedCodeIterator::OptimizedCodeIterator(Isolate* isolate) {
14661 isolate_ = isolate;
14662 Object* list = isolate->heap()->native_contexts_list();
14663 next_context_ = list->IsUndefined(isolate_) ? nullptr : Context::cast(list);
14664 current_code_ = nullptr;
14665 }
14666
Next()14667 Code* Code::OptimizedCodeIterator::Next() {
14668 do {
14669 Object* next;
14670 if (current_code_ != nullptr) {
14671 // Get next code in the linked list.
14672 next = Code::cast(current_code_)->next_code_link();
14673 } else if (next_context_ != nullptr) {
14674 // Linked list of code exhausted. Get list of next context.
14675 next = next_context_->OptimizedCodeListHead();
14676 Object* next_context = next_context_->next_context_link();
14677 next_context_ = next_context->IsUndefined(isolate_)
14678 ? nullptr
14679 : Context::cast(next_context);
14680 } else {
14681 // Exhausted contexts.
14682 return nullptr;
14683 }
14684 current_code_ = next->IsUndefined(isolate_) ? nullptr : Code::cast(next);
14685 } while (current_code_ == nullptr);
14686 Code* code = Code::cast(current_code_);
14687 DCHECK_EQ(Code::OPTIMIZED_FUNCTION, code->kind());
14688 return code;
14689 }
14690
14691 #ifdef ENABLE_DISASSEMBLER
14692
14693 namespace {
print_pc(std::ostream & os,int pc)14694 void print_pc(std::ostream& os, int pc) {
14695 if (pc == -1) {
14696 os << "NA";
14697 } else {
14698 os << std::hex << pc << std::dec;
14699 }
14700 }
14701 } // anonymous namespace
14702
DeoptimizationDataPrint(std::ostream & os)14703 void DeoptimizationData::DeoptimizationDataPrint(std::ostream& os) { // NOLINT
14704 if (length() == 0) {
14705 os << "Deoptimization Input Data invalidated by lazy deoptimization\n";
14706 return;
14707 }
14708
14709 disasm::NameConverter converter;
14710 int const inlined_function_count = InlinedFunctionCount()->value();
14711 os << "Inlined functions (count = " << inlined_function_count << ")\n";
14712 for (int id = 0; id < inlined_function_count; ++id) {
14713 Object* info = LiteralArray()->get(id);
14714 os << " " << Brief(SharedFunctionInfo::cast(info)) << "\n";
14715 }
14716 os << "\n";
14717 int deopt_count = DeoptCount();
14718 os << "Deoptimization Input Data (deopt points = " << deopt_count << ")\n";
14719 if (0 != deopt_count) {
14720 os << " index bytecode-offset pc";
14721 if (FLAG_print_code_verbose) os << " commands";
14722 os << "\n";
14723 }
14724 for (int i = 0; i < deopt_count; i++) {
14725 os << std::setw(6) << i << " " << std::setw(15)
14726 << BytecodeOffset(i).ToInt() << " " << std::setw(4);
14727 print_pc(os, Pc(i)->value());
14728 os << std::setw(2);
14729
14730 if (!FLAG_print_code_verbose) {
14731 os << "\n";
14732 continue;
14733 }
14734
14735 // Print details of the frame translation.
14736 int translation_index = TranslationIndex(i)->value();
14737 TranslationIterator iterator(TranslationByteArray(), translation_index);
14738 Translation::Opcode opcode =
14739 static_cast<Translation::Opcode>(iterator.Next());
14740 DCHECK(Translation::BEGIN == opcode);
14741 int frame_count = iterator.Next();
14742 int jsframe_count = iterator.Next();
14743 int update_feedback_count = iterator.Next();
14744 os << " " << Translation::StringFor(opcode)
14745 << " {frame count=" << frame_count
14746 << ", js frame count=" << jsframe_count
14747 << ", update_feedback_count=" << update_feedback_count << "}\n";
14748
14749 while (iterator.HasNext() &&
14750 Translation::BEGIN !=
14751 (opcode = static_cast<Translation::Opcode>(iterator.Next()))) {
14752 os << std::setw(31) << " " << Translation::StringFor(opcode) << " ";
14753
14754 switch (opcode) {
14755 case Translation::BEGIN:
14756 UNREACHABLE();
14757 break;
14758
14759 case Translation::INTERPRETED_FRAME: {
14760 int bytecode_offset = iterator.Next();
14761 int shared_info_id = iterator.Next();
14762 unsigned height = iterator.Next();
14763 Object* shared_info = LiteralArray()->get(shared_info_id);
14764 os << "{bytecode_offset=" << bytecode_offset << ", function="
14765 << Brief(SharedFunctionInfo::cast(shared_info)->DebugName())
14766 << ", height=" << height << "}";
14767 break;
14768 }
14769
14770 case Translation::CONSTRUCT_STUB_FRAME: {
14771 int bailout_id = iterator.Next();
14772 int shared_info_id = iterator.Next();
14773 Object* shared_info = LiteralArray()->get(shared_info_id);
14774 unsigned height = iterator.Next();
14775 os << "{bailout_id=" << bailout_id << ", function="
14776 << Brief(SharedFunctionInfo::cast(shared_info)->DebugName())
14777 << ", height=" << height << "}";
14778 break;
14779 }
14780
14781 case Translation::BUILTIN_CONTINUATION_FRAME:
14782 case Translation::JAVA_SCRIPT_BUILTIN_CONTINUATION_FRAME:
14783 case Translation::JAVA_SCRIPT_BUILTIN_CONTINUATION_WITH_CATCH_FRAME: {
14784 int bailout_id = iterator.Next();
14785 int shared_info_id = iterator.Next();
14786 Object* shared_info = LiteralArray()->get(shared_info_id);
14787 unsigned height = iterator.Next();
14788 os << "{bailout_id=" << bailout_id << ", function="
14789 << Brief(SharedFunctionInfo::cast(shared_info)->DebugName())
14790 << ", height=" << height << "}";
14791 break;
14792 }
14793
14794 case Translation::ARGUMENTS_ADAPTOR_FRAME: {
14795 int shared_info_id = iterator.Next();
14796 Object* shared_info = LiteralArray()->get(shared_info_id);
14797 unsigned height = iterator.Next();
14798 os << "{function="
14799 << Brief(SharedFunctionInfo::cast(shared_info)->DebugName())
14800 << ", height=" << height << "}";
14801 break;
14802 }
14803
14804 case Translation::REGISTER: {
14805 int reg_code = iterator.Next();
14806 os << "{input=" << converter.NameOfCPURegister(reg_code) << "}";
14807 break;
14808 }
14809
14810 case Translation::INT32_REGISTER: {
14811 int reg_code = iterator.Next();
14812 os << "{input=" << converter.NameOfCPURegister(reg_code) << "}";
14813 break;
14814 }
14815
14816 case Translation::UINT32_REGISTER: {
14817 int reg_code = iterator.Next();
14818 os << "{input=" << converter.NameOfCPURegister(reg_code)
14819 << " (unsigned)}";
14820 break;
14821 }
14822
14823 case Translation::BOOL_REGISTER: {
14824 int reg_code = iterator.Next();
14825 os << "{input=" << converter.NameOfCPURegister(reg_code)
14826 << " (bool)}";
14827 break;
14828 }
14829
14830 case Translation::FLOAT_REGISTER: {
14831 int reg_code = iterator.Next();
14832 os << "{input="
14833 << RegisterConfiguration::Default()->GetFloatRegisterName(reg_code)
14834 << "}";
14835 break;
14836 }
14837
14838 case Translation::DOUBLE_REGISTER: {
14839 int reg_code = iterator.Next();
14840 os << "{input="
14841 << RegisterConfiguration::Default()->GetDoubleRegisterName(
14842 reg_code)
14843 << "}";
14844 break;
14845 }
14846
14847 case Translation::STACK_SLOT: {
14848 int input_slot_index = iterator.Next();
14849 os << "{input=" << input_slot_index << "}";
14850 break;
14851 }
14852
14853 case Translation::INT32_STACK_SLOT: {
14854 int input_slot_index = iterator.Next();
14855 os << "{input=" << input_slot_index << "}";
14856 break;
14857 }
14858
14859 case Translation::UINT32_STACK_SLOT: {
14860 int input_slot_index = iterator.Next();
14861 os << "{input=" << input_slot_index << " (unsigned)}";
14862 break;
14863 }
14864
14865 case Translation::BOOL_STACK_SLOT: {
14866 int input_slot_index = iterator.Next();
14867 os << "{input=" << input_slot_index << " (bool)}";
14868 break;
14869 }
14870
14871 case Translation::FLOAT_STACK_SLOT:
14872 case Translation::DOUBLE_STACK_SLOT: {
14873 int input_slot_index = iterator.Next();
14874 os << "{input=" << input_slot_index << "}";
14875 break;
14876 }
14877
14878 case Translation::LITERAL: {
14879 int literal_index = iterator.Next();
14880 Object* literal_value = LiteralArray()->get(literal_index);
14881 os << "{literal_id=" << literal_index << " (" << Brief(literal_value)
14882 << ")}";
14883 break;
14884 }
14885
14886 case Translation::DUPLICATED_OBJECT: {
14887 int object_index = iterator.Next();
14888 os << "{object_index=" << object_index << "}";
14889 break;
14890 }
14891
14892 case Translation::ARGUMENTS_ELEMENTS:
14893 case Translation::ARGUMENTS_LENGTH: {
14894 CreateArgumentsType arguments_type =
14895 static_cast<CreateArgumentsType>(iterator.Next());
14896 os << "{arguments_type=" << arguments_type << "}";
14897 break;
14898 }
14899
14900 case Translation::CAPTURED_OBJECT: {
14901 int args_length = iterator.Next();
14902 os << "{length=" << args_length << "}";
14903 break;
14904 }
14905
14906 case Translation::UPDATE_FEEDBACK: {
14907 int literal_index = iterator.Next();
14908 FeedbackSlot slot(iterator.Next());
14909 os << "{feedback={vector_index=" << literal_index << ", slot=" << slot
14910 << "}}";
14911 break;
14912 }
14913 }
14914 os << "\n";
14915 }
14916 }
14917 }
14918
GetName(Isolate * isolate) const14919 const char* Code::GetName(Isolate* isolate) const {
14920 if (is_stub()) {
14921 return CodeStub::MajorName(CodeStub::GetMajorKey(this));
14922 } else if (kind() == BYTECODE_HANDLER) {
14923 return isolate->interpreter()->LookupNameOfBytecodeHandler(this);
14924 } else {
14925 // There are some handlers and ICs that we can also find names for with
14926 // Builtins::Lookup.
14927 return isolate->builtins()->Lookup(raw_instruction_start());
14928 }
14929 }
14930
PrintBuiltinCode(Isolate * isolate,const char * name)14931 void Code::PrintBuiltinCode(Isolate* isolate, const char* name) {
14932 DCHECK(FLAG_print_builtin_code);
14933 if (name == nullptr) {
14934 name = GetName(isolate);
14935 }
14936 if (name != nullptr &&
14937 PassesFilter(CStrVector(name),
14938 CStrVector(FLAG_print_builtin_code_filter))) {
14939 CodeTracer::Scope trace_scope(isolate->GetCodeTracer());
14940 OFStream os(trace_scope.file());
14941 Disassemble(name, os);
14942 os << "\n";
14943 }
14944 }
14945
14946 namespace {
14947
DisassembleCodeRange(Isolate * isolate,std::ostream & os,Code * code,Address begin,size_t size,Address current_pc)14948 inline void DisassembleCodeRange(Isolate* isolate, std::ostream& os, Code* code,
14949 Address begin, size_t size,
14950 Address current_pc) {
14951 Address end = begin + size;
14952 // TODO(mstarzinger): Refactor CodeReference to avoid the
14953 // unhandlified->handlified transition.
14954 AllowHandleAllocation allow_handles;
14955 DisallowHeapAllocation no_gc;
14956 HandleScope handle_scope(isolate);
14957 Disassembler::Decode(isolate, &os, reinterpret_cast<byte*>(begin),
14958 reinterpret_cast<byte*>(end),
14959 CodeReference(handle(code, isolate)), current_pc);
14960 }
14961
14962 } // namespace
14963
Disassemble(const char * name,std::ostream & os,Address current_pc)14964 void Code::Disassemble(const char* name, std::ostream& os, Address current_pc) {
14965 Isolate* isolate = GetIsolate();
14966 os << "kind = " << Kind2String(kind()) << "\n";
14967 if (is_stub()) {
14968 const char* n = CodeStub::MajorName(CodeStub::GetMajorKey(this));
14969 os << "major_key = " << (n == nullptr ? "null" : n) << "\n";
14970 os << "minor_key = " << CodeStub::MinorKeyFromKey(this->stub_key()) << "\n";
14971 }
14972 if (name == nullptr) {
14973 name = GetName(isolate);
14974 }
14975 if ((name != nullptr) && (name[0] != '\0')) {
14976 os << "name = " << name << "\n";
14977 }
14978 if (kind() == OPTIMIZED_FUNCTION) {
14979 os << "stack_slots = " << stack_slots() << "\n";
14980 }
14981 os << "compiler = " << (is_turbofanned() ? "turbofan" : "unknown") << "\n";
14982 os << "address = " << static_cast<const void*>(this) << "\n\n";
14983
14984 if (is_off_heap_trampoline()) {
14985 int trampoline_size = raw_instruction_size();
14986 os << "Trampoline (size = " << trampoline_size << ")\n";
14987 DisassembleCodeRange(isolate, os, this, raw_instruction_start(),
14988 trampoline_size, current_pc);
14989 os << "\n";
14990 }
14991
14992 {
14993 int size = InstructionSize();
14994 int safepoint_offset =
14995 has_safepoint_info() ? safepoint_table_offset() : size;
14996 int constant_pool_offset = this->constant_pool_offset();
14997 int handler_offset = handler_table_offset() ? handler_table_offset() : size;
14998
14999 // Stop before reaching any embedded tables
15000 int code_size =
15001 Min(handler_offset, Min(safepoint_offset, constant_pool_offset));
15002 os << "Instructions (size = " << code_size << ")\n";
15003 DisassembleCodeRange(isolate, os, this, InstructionStart(), code_size,
15004 current_pc);
15005
15006 if (constant_pool_offset < size) {
15007 int constant_pool_size = safepoint_offset - constant_pool_offset;
15008 DCHECK_EQ(constant_pool_size & kPointerAlignmentMask, 0);
15009 os << "\nConstant Pool (size = " << constant_pool_size << ")\n";
15010 Vector<char> buf = Vector<char>::New(50);
15011 intptr_t* ptr = reinterpret_cast<intptr_t*>(InstructionStart() +
15012 constant_pool_offset);
15013 for (int i = 0; i < constant_pool_size; i += kPointerSize, ptr++) {
15014 SNPrintF(buf, "%4d %08" V8PRIxPTR, i, *ptr);
15015 os << static_cast<const void*>(ptr) << " " << buf.start() << "\n";
15016 }
15017 }
15018 }
15019 os << "\n";
15020
15021 SourcePositionTableIterator it(SourcePositionTable());
15022 if (!it.done()) {
15023 os << "Source positions:\n pc offset position\n";
15024 for (; !it.done(); it.Advance()) {
15025 os << std::setw(10) << std::hex << it.code_offset() << std::dec
15026 << std::setw(10) << it.source_position().ScriptOffset()
15027 << (it.is_statement() ? " statement" : "") << "\n";
15028 }
15029 os << "\n";
15030 }
15031
15032 if (kind() == OPTIMIZED_FUNCTION) {
15033 DeoptimizationData* data =
15034 DeoptimizationData::cast(this->deoptimization_data());
15035 data->DeoptimizationDataPrint(os);
15036 }
15037 os << "\n";
15038
15039 if (has_safepoint_info()) {
15040 SafepointTable table(this);
15041 os << "Safepoints (size = " << table.size() << ")\n";
15042 for (unsigned i = 0; i < table.length(); i++) {
15043 unsigned pc_offset = table.GetPcOffset(i);
15044 os << reinterpret_cast<const void*>(InstructionStart() + pc_offset)
15045 << " ";
15046 os << std::setw(6) << std::hex << pc_offset << " " << std::setw(4);
15047 int trampoline_pc = table.GetTrampolinePcOffset(i);
15048 print_pc(os, trampoline_pc);
15049 os << std::dec << " ";
15050 table.PrintEntry(i, os);
15051 os << " (sp -> fp) ";
15052 SafepointEntry entry = table.GetEntry(i);
15053 if (entry.deoptimization_index() != Safepoint::kNoDeoptimizationIndex) {
15054 os << std::setw(6) << entry.deoptimization_index();
15055 } else {
15056 os << "<none>";
15057 }
15058 if (entry.argument_count() > 0) {
15059 os << " argc: " << entry.argument_count();
15060 }
15061 os << "\n";
15062 }
15063 os << "\n";
15064 }
15065
15066 if (handler_table_offset() > 0) {
15067 HandlerTable table(this);
15068 os << "Handler Table (size = " << table.NumberOfReturnEntries() << ")\n";
15069 if (kind() == OPTIMIZED_FUNCTION) {
15070 table.HandlerTableReturnPrint(os);
15071 }
15072 os << "\n";
15073 }
15074
15075 os << "RelocInfo (size = " << relocation_size() << ")\n";
15076 for (RelocIterator it(this); !it.done(); it.next()) {
15077 it.rinfo()->Print(isolate, os);
15078 }
15079 os << "\n";
15080
15081 if (has_unwinding_info()) {
15082 os << "UnwindingInfo (size = " << unwinding_info_size() << ")\n";
15083 EhFrameDisassembler eh_frame_disassembler(
15084 reinterpret_cast<byte*>(unwinding_info_start()),
15085 reinterpret_cast<byte*>(unwinding_info_end()));
15086 eh_frame_disassembler.DisassembleToStream(os);
15087 os << "\n";
15088 }
15089 }
15090 #endif // ENABLE_DISASSEMBLER
15091
Disassemble(std::ostream & os)15092 void BytecodeArray::Disassemble(std::ostream& os) {
15093 DisallowHeapAllocation no_gc;
15094
15095 os << "Parameter count " << parameter_count() << "\n";
15096 os << "Frame size " << frame_size() << "\n";
15097
15098 Address base_address = GetFirstBytecodeAddress();
15099 SourcePositionTableIterator source_positions(SourcePositionTable());
15100
15101 // Storage for backing the handle passed to the iterator. This handle won't be
15102 // updated by the gc, but that's ok because we've disallowed GCs anyway.
15103 BytecodeArray* handle_storage = this;
15104 Handle<BytecodeArray> handle(&handle_storage);
15105 interpreter::BytecodeArrayIterator iterator(handle);
15106 while (!iterator.done()) {
15107 if (!source_positions.done() &&
15108 iterator.current_offset() == source_positions.code_offset()) {
15109 os << std::setw(5) << source_positions.source_position().ScriptOffset();
15110 os << (source_positions.is_statement() ? " S> " : " E> ");
15111 source_positions.Advance();
15112 } else {
15113 os << " ";
15114 }
15115 Address current_address = base_address + iterator.current_offset();
15116 os << reinterpret_cast<const void*>(current_address) << " @ "
15117 << std::setw(4) << iterator.current_offset() << " : ";
15118 interpreter::BytecodeDecoder::Decode(
15119 os, reinterpret_cast<byte*>(current_address), parameter_count());
15120 if (interpreter::Bytecodes::IsJump(iterator.current_bytecode())) {
15121 Address jump_target = base_address + iterator.GetJumpTargetOffset();
15122 os << " (" << reinterpret_cast<void*>(jump_target) << " @ "
15123 << iterator.GetJumpTargetOffset() << ")";
15124 }
15125 if (interpreter::Bytecodes::IsSwitch(iterator.current_bytecode())) {
15126 os << " {";
15127 bool first_entry = true;
15128 for (const auto& entry : iterator.GetJumpTableTargetOffsets()) {
15129 if (first_entry) {
15130 first_entry = false;
15131 } else {
15132 os << ",";
15133 }
15134 os << " " << entry.case_value << ": @" << entry.target_offset;
15135 }
15136 os << " }";
15137 }
15138 os << std::endl;
15139 iterator.Advance();
15140 }
15141
15142 os << "Constant pool (size = " << constant_pool()->length() << ")\n";
15143 #ifdef OBJECT_PRINT
15144 if (constant_pool()->length() > 0) {
15145 constant_pool()->Print();
15146 }
15147 #endif
15148
15149 os << "Handler Table (size = " << handler_table()->length() << ")\n";
15150 #ifdef ENABLE_DISASSEMBLER
15151 if (handler_table()->length() > 0) {
15152 HandlerTable table(this);
15153 table.HandlerTableRangePrint(os);
15154 }
15155 #endif
15156 }
15157
CopyBytecodesTo(BytecodeArray * to)15158 void BytecodeArray::CopyBytecodesTo(BytecodeArray* to) {
15159 BytecodeArray* from = this;
15160 DCHECK_EQ(from->length(), to->length());
15161 CopyBytes(reinterpret_cast<byte*>(to->GetFirstBytecodeAddress()),
15162 reinterpret_cast<byte*>(from->GetFirstBytecodeAddress()),
15163 from->length());
15164 }
15165
MakeOlder()15166 void BytecodeArray::MakeOlder() {
15167 // BytecodeArray is aged in concurrent marker.
15168 // The word must be completely within the byte code array.
15169 Address age_addr = address() + kBytecodeAgeOffset;
15170 DCHECK_LE((age_addr & ~kPointerAlignmentMask) + kPointerSize,
15171 address() + Size());
15172 Age age = bytecode_age();
15173 if (age < kLastBytecodeAge) {
15174 base::AsAtomic8::Release_CompareAndSwap(reinterpret_cast<byte*>(age_addr),
15175 age, age + 1);
15176 }
15177
15178 DCHECK_GE(bytecode_age(), kFirstBytecodeAge);
15179 DCHECK_LE(bytecode_age(), kLastBytecodeAge);
15180 }
15181
IsOld() const15182 bool BytecodeArray::IsOld() const {
15183 return bytecode_age() >= kIsOldBytecodeAge;
15184 }
15185
15186 // static
Initialize(Handle<JSArray> array,int capacity,int length)15187 void JSArray::Initialize(Handle<JSArray> array, int capacity, int length) {
15188 DCHECK_GE(capacity, 0);
15189 array->GetIsolate()->factory()->NewJSArrayStorage(
15190 array, length, capacity, INITIALIZE_ARRAY_ELEMENTS_WITH_HOLE);
15191 }
15192
SetLength(Handle<JSArray> array,uint32_t new_length)15193 void JSArray::SetLength(Handle<JSArray> array, uint32_t new_length) {
15194 // We should never end in here with a pixel or external array.
15195 DCHECK(array->AllowsSetLength());
15196 if (array->SetLengthWouldNormalize(new_length)) {
15197 JSObject::NormalizeElements(array);
15198 }
15199 array->GetElementsAccessor()->SetLength(array, new_length);
15200 }
15201
GetDependentCode(Handle<HeapObject> object)15202 DependentCode* DependentCode::GetDependentCode(Handle<HeapObject> object) {
15203 if (object->IsMap()) {
15204 return Handle<Map>::cast(object)->dependent_code();
15205 } else if (object->IsPropertyCell()) {
15206 return Handle<PropertyCell>::cast(object)->dependent_code();
15207 } else if (object->IsAllocationSite()) {
15208 return Handle<AllocationSite>::cast(object)->dependent_code();
15209 }
15210 UNREACHABLE();
15211 }
15212
SetDependentCode(Handle<HeapObject> object,Handle<DependentCode> dep)15213 void DependentCode::SetDependentCode(Handle<HeapObject> object,
15214 Handle<DependentCode> dep) {
15215 if (object->IsMap()) {
15216 Handle<Map>::cast(object)->set_dependent_code(*dep);
15217 } else if (object->IsPropertyCell()) {
15218 Handle<PropertyCell>::cast(object)->set_dependent_code(*dep);
15219 } else if (object->IsAllocationSite()) {
15220 Handle<AllocationSite>::cast(object)->set_dependent_code(*dep);
15221 } else {
15222 UNREACHABLE();
15223 }
15224 }
15225
InstallDependency(Isolate * isolate,MaybeObjectHandle code,Handle<HeapObject> object,DependencyGroup group)15226 void DependentCode::InstallDependency(Isolate* isolate, MaybeObjectHandle code,
15227 Handle<HeapObject> object,
15228 DependencyGroup group) {
15229 Handle<DependentCode> old_deps(DependentCode::GetDependentCode(object),
15230 isolate);
15231 Handle<DependentCode> new_deps =
15232 InsertWeakCode(isolate, old_deps, group, code);
15233 // Update the list head if necessary.
15234 if (!new_deps.is_identical_to(old_deps))
15235 DependentCode::SetDependentCode(object, new_deps);
15236 }
15237
InsertWeakCode(Isolate * isolate,Handle<DependentCode> entries,DependencyGroup group,MaybeObjectHandle code)15238 Handle<DependentCode> DependentCode::InsertWeakCode(
15239 Isolate* isolate, Handle<DependentCode> entries, DependencyGroup group,
15240 MaybeObjectHandle code) {
15241 if (entries->length() == 0 || entries->group() > group) {
15242 // There is no such group.
15243 return DependentCode::New(isolate, group, code, entries);
15244 }
15245 if (entries->group() < group) {
15246 // The group comes later in the list.
15247 Handle<DependentCode> old_next(entries->next_link(), isolate);
15248 Handle<DependentCode> new_next =
15249 InsertWeakCode(isolate, old_next, group, code);
15250 if (!old_next.is_identical_to(new_next)) {
15251 entries->set_next_link(*new_next);
15252 }
15253 return entries;
15254 }
15255 DCHECK_EQ(group, entries->group());
15256 int count = entries->count();
15257 // Check for existing entry to avoid duplicates.
15258 for (int i = 0; i < count; i++) {
15259 if (entries->object_at(i) == *code) return entries;
15260 }
15261 if (entries->length() < kCodesStartIndex + count + 1) {
15262 entries = EnsureSpace(isolate, entries);
15263 // Count could have changed, reload it.
15264 count = entries->count();
15265 }
15266 entries->set_object_at(count, *code);
15267 entries->set_count(count + 1);
15268 return entries;
15269 }
15270
New(Isolate * isolate,DependencyGroup group,MaybeObjectHandle object,Handle<DependentCode> next)15271 Handle<DependentCode> DependentCode::New(Isolate* isolate,
15272 DependencyGroup group,
15273 MaybeObjectHandle object,
15274 Handle<DependentCode> next) {
15275 Handle<DependentCode> result = Handle<DependentCode>::cast(
15276 isolate->factory()->NewWeakFixedArray(kCodesStartIndex + 1, TENURED));
15277 result->set_next_link(*next);
15278 result->set_flags(GroupField::encode(group) | CountField::encode(1));
15279 result->set_object_at(0, *object);
15280 return result;
15281 }
15282
EnsureSpace(Isolate * isolate,Handle<DependentCode> entries)15283 Handle<DependentCode> DependentCode::EnsureSpace(
15284 Isolate* isolate, Handle<DependentCode> entries) {
15285 if (entries->Compact()) return entries;
15286 int capacity = kCodesStartIndex + DependentCode::Grow(entries->count());
15287 int grow_by = capacity - entries->length();
15288 return Handle<DependentCode>::cast(
15289 isolate->factory()->CopyWeakFixedArrayAndGrow(entries, grow_by, TENURED));
15290 }
15291
15292
Compact()15293 bool DependentCode::Compact() {
15294 int old_count = count();
15295 int new_count = 0;
15296 for (int i = 0; i < old_count; i++) {
15297 MaybeObject* obj = object_at(i);
15298 if (!obj->IsClearedWeakHeapObject()) {
15299 if (i != new_count) {
15300 copy(i, new_count);
15301 }
15302 new_count++;
15303 }
15304 }
15305 set_count(new_count);
15306 for (int i = new_count; i < old_count; i++) {
15307 clear_at(i);
15308 }
15309 return new_count < old_count;
15310 }
15311
Contains(DependencyGroup group,MaybeObject * code)15312 bool DependentCode::Contains(DependencyGroup group, MaybeObject* code) {
15313 if (this->length() == 0 || this->group() > group) {
15314 // There is no such group.
15315 return false;
15316 }
15317 if (this->group() < group) {
15318 // The group comes later in the list.
15319 return next_link()->Contains(group, code);
15320 }
15321 DCHECK_EQ(group, this->group());
15322 int count = this->count();
15323 for (int i = 0; i < count; i++) {
15324 if (object_at(i) == code) return true;
15325 }
15326 return false;
15327 }
15328
15329
IsEmpty(DependencyGroup group)15330 bool DependentCode::IsEmpty(DependencyGroup group) {
15331 if (this->length() == 0 || this->group() > group) {
15332 // There is no such group.
15333 return true;
15334 }
15335 if (this->group() < group) {
15336 // The group comes later in the list.
15337 return next_link()->IsEmpty(group);
15338 }
15339 DCHECK_EQ(group, this->group());
15340 return count() == 0;
15341 }
15342
15343
MarkCodeForDeoptimization(Isolate * isolate,DependentCode::DependencyGroup group)15344 bool DependentCode::MarkCodeForDeoptimization(
15345 Isolate* isolate,
15346 DependentCode::DependencyGroup group) {
15347 if (this->length() == 0 || this->group() > group) {
15348 // There is no such group.
15349 return false;
15350 }
15351 if (this->group() < group) {
15352 // The group comes later in the list.
15353 return next_link()->MarkCodeForDeoptimization(isolate, group);
15354 }
15355 DCHECK_EQ(group, this->group());
15356 DisallowHeapAllocation no_allocation_scope;
15357 // Mark all the code that needs to be deoptimized.
15358 bool marked = false;
15359 int count = this->count();
15360 for (int i = 0; i < count; i++) {
15361 MaybeObject* obj = object_at(i);
15362 if (obj->IsClearedWeakHeapObject()) continue;
15363 Code* code = Code::cast(obj->ToWeakHeapObject());
15364 if (!code->marked_for_deoptimization()) {
15365 code->SetMarkedForDeoptimization(DependencyGroupName(group));
15366 marked = true;
15367 }
15368 }
15369 for (int i = 0; i < count; i++) {
15370 clear_at(i);
15371 }
15372 set_count(0);
15373 return marked;
15374 }
15375
15376
DeoptimizeDependentCodeGroup(Isolate * isolate,DependentCode::DependencyGroup group)15377 void DependentCode::DeoptimizeDependentCodeGroup(
15378 Isolate* isolate,
15379 DependentCode::DependencyGroup group) {
15380 DisallowHeapAllocation no_allocation_scope;
15381 bool marked = MarkCodeForDeoptimization(isolate, group);
15382 if (marked) {
15383 DCHECK(AllowCodeDependencyChange::IsAllowed());
15384 Deoptimizer::DeoptimizeMarkedCode(isolate);
15385 }
15386 }
15387
SetMarkedForDeoptimization(const char * reason)15388 void Code::SetMarkedForDeoptimization(const char* reason) {
15389 set_marked_for_deoptimization(true);
15390 if (FLAG_trace_deopt &&
15391 (deoptimization_data() != GetReadOnlyRoots().empty_fixed_array())) {
15392 DeoptimizationData* deopt_data =
15393 DeoptimizationData::cast(deoptimization_data());
15394 CodeTracer::Scope scope(GetHeap()->isolate()->GetCodeTracer());
15395 PrintF(scope.file(),
15396 "[marking dependent code " V8PRIxPTR_FMT
15397 " (opt #%d) for deoptimization, reason: %s]\n",
15398 reinterpret_cast<intptr_t>(this),
15399 deopt_data->OptimizationId()->value(), reason);
15400 }
15401 }
15402
15403
DependencyGroupName(DependencyGroup group)15404 const char* DependentCode::DependencyGroupName(DependencyGroup group) {
15405 switch (group) {
15406 case kTransitionGroup:
15407 return "transition";
15408 case kPrototypeCheckGroup:
15409 return "prototype-check";
15410 case kPropertyCellChangedGroup:
15411 return "property-cell-changed";
15412 case kFieldOwnerGroup:
15413 return "field-owner";
15414 case kInitialMapChangedGroup:
15415 return "initial-map-changed";
15416 case kAllocationSiteTenuringChangedGroup:
15417 return "allocation-site-tenuring-changed";
15418 case kAllocationSiteTransitionChangedGroup:
15419 return "allocation-site-transition-changed";
15420 }
15421 UNREACHABLE();
15422 }
15423
TransitionToPrototype(Isolate * isolate,Handle<Map> map,Handle<Object> prototype)15424 Handle<Map> Map::TransitionToPrototype(Isolate* isolate, Handle<Map> map,
15425 Handle<Object> prototype) {
15426 Handle<Map> new_map =
15427 TransitionsAccessor(isolate, map).GetPrototypeTransition(prototype);
15428 if (new_map.is_null()) {
15429 new_map = Copy(isolate, map, "TransitionToPrototype");
15430 TransitionsAccessor(isolate, map)
15431 .PutPrototypeTransition(prototype, new_map);
15432 Map::SetPrototype(isolate, new_map, prototype);
15433 }
15434 return new_map;
15435 }
15436
15437
SetPrototype(Handle<JSReceiver> object,Handle<Object> value,bool from_javascript,ShouldThrow should_throw)15438 Maybe<bool> JSReceiver::SetPrototype(Handle<JSReceiver> object,
15439 Handle<Object> value, bool from_javascript,
15440 ShouldThrow should_throw) {
15441 if (object->IsJSProxy()) {
15442 return JSProxy::SetPrototype(Handle<JSProxy>::cast(object), value,
15443 from_javascript, should_throw);
15444 }
15445 return JSObject::SetPrototype(Handle<JSObject>::cast(object), value,
15446 from_javascript, should_throw);
15447 }
15448
15449
15450 // ES6: 9.5.2 [[SetPrototypeOf]] (V)
15451 // static
SetPrototype(Handle<JSProxy> proxy,Handle<Object> value,bool from_javascript,ShouldThrow should_throw)15452 Maybe<bool> JSProxy::SetPrototype(Handle<JSProxy> proxy, Handle<Object> value,
15453 bool from_javascript,
15454 ShouldThrow should_throw) {
15455 Isolate* isolate = proxy->GetIsolate();
15456 STACK_CHECK(isolate, Nothing<bool>());
15457 Handle<Name> trap_name = isolate->factory()->setPrototypeOf_string();
15458 // 1. Assert: Either Type(V) is Object or Type(V) is Null.
15459 DCHECK(value->IsJSReceiver() || value->IsNull(isolate));
15460 // 2. Let handler be the value of the [[ProxyHandler]] internal slot of O.
15461 Handle<Object> handler(proxy->handler(), isolate);
15462 // 3. If handler is null, throw a TypeError exception.
15463 // 4. Assert: Type(handler) is Object.
15464 if (proxy->IsRevoked()) {
15465 isolate->Throw(*isolate->factory()->NewTypeError(
15466 MessageTemplate::kProxyRevoked, trap_name));
15467 return Nothing<bool>();
15468 }
15469 // 5. Let target be the value of the [[ProxyTarget]] internal slot.
15470 Handle<JSReceiver> target(JSReceiver::cast(proxy->target()), isolate);
15471 // 6. Let trap be ? GetMethod(handler, "getPrototypeOf").
15472 Handle<Object> trap;
15473 ASSIGN_RETURN_ON_EXCEPTION_VALUE(
15474 isolate, trap,
15475 Object::GetMethod(Handle<JSReceiver>::cast(handler), trap_name),
15476 Nothing<bool>());
15477 // 7. If trap is undefined, then return target.[[SetPrototypeOf]]().
15478 if (trap->IsUndefined(isolate)) {
15479 return JSReceiver::SetPrototype(target, value, from_javascript,
15480 should_throw);
15481 }
15482 // 8. Let booleanTrapResult be ToBoolean(? Call(trap, handler, «target, V»)).
15483 Handle<Object> argv[] = {target, value};
15484 Handle<Object> trap_result;
15485 ASSIGN_RETURN_ON_EXCEPTION_VALUE(
15486 isolate, trap_result,
15487 Execution::Call(isolate, trap, handler, arraysize(argv), argv),
15488 Nothing<bool>());
15489 bool bool_trap_result = trap_result->BooleanValue(isolate);
15490 // 9. If booleanTrapResult is false, return false.
15491 if (!bool_trap_result) {
15492 RETURN_FAILURE(
15493 isolate, should_throw,
15494 NewTypeError(MessageTemplate::kProxyTrapReturnedFalsish, trap_name));
15495 }
15496 // 10. Let extensibleTarget be ? IsExtensible(target).
15497 Maybe<bool> is_extensible = JSReceiver::IsExtensible(target);
15498 if (is_extensible.IsNothing()) return Nothing<bool>();
15499 // 11. If extensibleTarget is true, return true.
15500 if (is_extensible.FromJust()) {
15501 if (bool_trap_result) return Just(true);
15502 RETURN_FAILURE(
15503 isolate, should_throw,
15504 NewTypeError(MessageTemplate::kProxyTrapReturnedFalsish, trap_name));
15505 }
15506 // 12. Let targetProto be ? target.[[GetPrototypeOf]]().
15507 Handle<Object> target_proto;
15508 ASSIGN_RETURN_ON_EXCEPTION_VALUE(isolate, target_proto,
15509 JSReceiver::GetPrototype(isolate, target),
15510 Nothing<bool>());
15511 // 13. If SameValue(V, targetProto) is false, throw a TypeError exception.
15512 if (bool_trap_result && !value->SameValue(*target_proto)) {
15513 isolate->Throw(*isolate->factory()->NewTypeError(
15514 MessageTemplate::kProxySetPrototypeOfNonExtensible));
15515 return Nothing<bool>();
15516 }
15517 // 14. Return true.
15518 return Just(true);
15519 }
15520
15521
SetPrototype(Handle<JSObject> object,Handle<Object> value,bool from_javascript,ShouldThrow should_throw)15522 Maybe<bool> JSObject::SetPrototype(Handle<JSObject> object,
15523 Handle<Object> value, bool from_javascript,
15524 ShouldThrow should_throw) {
15525 Isolate* isolate = object->GetIsolate();
15526
15527 #ifdef DEBUG
15528 int size = object->Size();
15529 #endif
15530
15531 if (from_javascript) {
15532 if (object->IsAccessCheckNeeded() &&
15533 !isolate->MayAccess(handle(isolate->context(), isolate), object)) {
15534 isolate->ReportFailedAccessCheck(object);
15535 RETURN_VALUE_IF_SCHEDULED_EXCEPTION(isolate, Nothing<bool>());
15536 RETURN_FAILURE(isolate, should_throw,
15537 NewTypeError(MessageTemplate::kNoAccess));
15538 }
15539 } else {
15540 DCHECK(!object->IsAccessCheckNeeded());
15541 }
15542
15543 // Silently ignore the change if value is not a JSObject or null.
15544 // SpiderMonkey behaves this way.
15545 if (!value->IsJSReceiver() && !value->IsNull(isolate)) return Just(true);
15546
15547 bool all_extensible = object->map()->is_extensible();
15548 Handle<JSObject> real_receiver = object;
15549 if (from_javascript) {
15550 // Find the first object in the chain whose prototype object is not
15551 // hidden.
15552 PrototypeIterator iter(isolate, real_receiver, kStartAtPrototype,
15553 PrototypeIterator::END_AT_NON_HIDDEN);
15554 while (!iter.IsAtEnd()) {
15555 // Casting to JSObject is fine because hidden prototypes are never
15556 // JSProxies.
15557 real_receiver = PrototypeIterator::GetCurrent<JSObject>(iter);
15558 iter.Advance();
15559 all_extensible = all_extensible && real_receiver->map()->is_extensible();
15560 }
15561 }
15562 Handle<Map> map(real_receiver->map(), isolate);
15563
15564 // Nothing to do if prototype is already set.
15565 if (map->prototype() == *value) return Just(true);
15566
15567 bool immutable_proto = map->is_immutable_proto();
15568 if (immutable_proto) {
15569 RETURN_FAILURE(
15570 isolate, should_throw,
15571 NewTypeError(MessageTemplate::kImmutablePrototypeSet, object));
15572 }
15573
15574 // From 8.6.2 Object Internal Methods
15575 // ...
15576 // In addition, if [[Extensible]] is false the value of the [[Class]] and
15577 // [[Prototype]] internal properties of the object may not be modified.
15578 // ...
15579 // Implementation specific extensions that modify [[Class]], [[Prototype]]
15580 // or [[Extensible]] must not violate the invariants defined in the preceding
15581 // paragraph.
15582 if (!all_extensible) {
15583 RETURN_FAILURE(isolate, should_throw,
15584 NewTypeError(MessageTemplate::kNonExtensibleProto, object));
15585 }
15586
15587 // Before we can set the prototype we need to be sure prototype cycles are
15588 // prevented. It is sufficient to validate that the receiver is not in the
15589 // new prototype chain.
15590 if (value->IsJSReceiver()) {
15591 for (PrototypeIterator iter(isolate, JSReceiver::cast(*value),
15592 kStartAtReceiver);
15593 !iter.IsAtEnd(); iter.Advance()) {
15594 if (iter.GetCurrent<JSReceiver>() == *object) {
15595 // Cycle detected.
15596 RETURN_FAILURE(isolate, should_throw,
15597 NewTypeError(MessageTemplate::kCyclicProto));
15598 }
15599 }
15600 }
15601
15602 // Set the new prototype of the object.
15603
15604 isolate->UpdateNoElementsProtectorOnSetPrototype(real_receiver);
15605
15606 Handle<Map> new_map = Map::TransitionToPrototype(isolate, map, value);
15607 DCHECK(new_map->prototype() == *value);
15608 JSObject::MigrateToMap(real_receiver, new_map);
15609
15610 DCHECK(size == object->Size());
15611 return Just(true);
15612 }
15613
15614 // static
SetImmutableProto(Handle<JSObject> object)15615 void JSObject::SetImmutableProto(Handle<JSObject> object) {
15616 DCHECK(!object->IsAccessCheckNeeded()); // Never called from JS
15617 Handle<Map> map(object->map(), object->GetIsolate());
15618
15619 // Nothing to do if prototype is already set.
15620 if (map->is_immutable_proto()) return;
15621
15622 Handle<Map> new_map =
15623 Map::TransitionToImmutableProto(object->GetIsolate(), map);
15624 object->synchronized_set_map(*new_map);
15625 }
15626
EnsureCanContainElements(Handle<JSObject> object,Arguments * args,uint32_t first_arg,uint32_t arg_count,EnsureElementsMode mode)15627 void JSObject::EnsureCanContainElements(Handle<JSObject> object,
15628 Arguments* args,
15629 uint32_t first_arg,
15630 uint32_t arg_count,
15631 EnsureElementsMode mode) {
15632 // Elements in |Arguments| are ordered backwards (because they're on the
15633 // stack), but the method that's called here iterates over them in forward
15634 // direction.
15635 return EnsureCanContainElements(
15636 object, args->arguments() - first_arg - (arg_count - 1), arg_count, mode);
15637 }
15638
15639
GetElementsAccessor()15640 ElementsAccessor* JSObject::GetElementsAccessor() {
15641 return ElementsAccessor::ForKind(GetElementsKind());
15642 }
15643
ValidateElements(JSObject * object)15644 void JSObject::ValidateElements(JSObject* object) {
15645 #ifdef ENABLE_SLOW_DCHECKS
15646 if (FLAG_enable_slow_asserts) {
15647 object->GetElementsAccessor()->Validate(object);
15648 }
15649 #endif
15650 }
15651
15652
ShouldConvertToSlowElements(JSObject * object,uint32_t capacity,uint32_t index,uint32_t * new_capacity)15653 static bool ShouldConvertToSlowElements(JSObject* object, uint32_t capacity,
15654 uint32_t index,
15655 uint32_t* new_capacity) {
15656 STATIC_ASSERT(JSObject::kMaxUncheckedOldFastElementsLength <=
15657 JSObject::kMaxUncheckedFastElementsLength);
15658 if (index < capacity) {
15659 *new_capacity = capacity;
15660 return false;
15661 }
15662 if (index - capacity >= JSObject::kMaxGap) return true;
15663 *new_capacity = JSObject::NewElementsCapacity(index + 1);
15664 DCHECK_LT(index, *new_capacity);
15665 if (*new_capacity <= JSObject::kMaxUncheckedOldFastElementsLength ||
15666 (*new_capacity <= JSObject::kMaxUncheckedFastElementsLength &&
15667 Heap::InNewSpace(object))) {
15668 return false;
15669 }
15670 // If the fast-case backing storage takes up much more memory than a
15671 // dictionary backing storage would, the object should have slow elements.
15672 int used_elements = object->GetFastElementsUsage();
15673 uint32_t size_threshold = NumberDictionary::kPreferFastElementsSizeFactor *
15674 NumberDictionary::ComputeCapacity(used_elements) *
15675 NumberDictionary::kEntrySize;
15676 return size_threshold <= *new_capacity;
15677 }
15678
15679
WouldConvertToSlowElements(uint32_t index)15680 bool JSObject::WouldConvertToSlowElements(uint32_t index) {
15681 if (!HasFastElements()) return false;
15682 uint32_t capacity = static_cast<uint32_t>(elements()->length());
15683 uint32_t new_capacity;
15684 return ShouldConvertToSlowElements(this, capacity, index, &new_capacity);
15685 }
15686
15687
BestFittingFastElementsKind(JSObject * object)15688 static ElementsKind BestFittingFastElementsKind(JSObject* object) {
15689 if (!object->map()->CanHaveFastTransitionableElementsKind()) {
15690 return HOLEY_ELEMENTS;
15691 }
15692 if (object->HasSloppyArgumentsElements()) {
15693 return FAST_SLOPPY_ARGUMENTS_ELEMENTS;
15694 }
15695 if (object->HasStringWrapperElements()) {
15696 return FAST_STRING_WRAPPER_ELEMENTS;
15697 }
15698 DCHECK(object->HasDictionaryElements());
15699 NumberDictionary* dictionary = object->element_dictionary();
15700 ElementsKind kind = HOLEY_SMI_ELEMENTS;
15701 for (int i = 0; i < dictionary->Capacity(); i++) {
15702 Object* key = dictionary->KeyAt(i);
15703 if (key->IsNumber()) {
15704 Object* value = dictionary->ValueAt(i);
15705 if (!value->IsNumber()) return HOLEY_ELEMENTS;
15706 if (!value->IsSmi()) {
15707 if (!FLAG_unbox_double_arrays) return HOLEY_ELEMENTS;
15708 kind = HOLEY_DOUBLE_ELEMENTS;
15709 }
15710 }
15711 }
15712 return kind;
15713 }
15714
ShouldConvertToFastElements(JSObject * object,NumberDictionary * dictionary,uint32_t index,uint32_t * new_capacity)15715 static bool ShouldConvertToFastElements(JSObject* object,
15716 NumberDictionary* dictionary,
15717 uint32_t index,
15718 uint32_t* new_capacity) {
15719 // If properties with non-standard attributes or accessors were added, we
15720 // cannot go back to fast elements.
15721 if (dictionary->requires_slow_elements()) return false;
15722
15723 // Adding a property with this index will require slow elements.
15724 if (index >= static_cast<uint32_t>(Smi::kMaxValue)) return false;
15725
15726 if (object->IsJSArray()) {
15727 Object* length = JSArray::cast(object)->length();
15728 if (!length->IsSmi()) return false;
15729 *new_capacity = static_cast<uint32_t>(Smi::ToInt(length));
15730 } else if (object->IsJSSloppyArgumentsObject()) {
15731 return false;
15732 } else {
15733 *new_capacity = dictionary->max_number_key() + 1;
15734 }
15735 *new_capacity = Max(index + 1, *new_capacity);
15736
15737 uint32_t dictionary_size = static_cast<uint32_t>(dictionary->Capacity()) *
15738 NumberDictionary::kEntrySize;
15739
15740 // Turn fast if the dictionary only saves 50% space.
15741 return 2 * dictionary_size >= *new_capacity;
15742 }
15743
15744 // static
AddDataElement(Handle<JSObject> object,uint32_t index,Handle<Object> value,PropertyAttributes attributes)15745 void JSObject::AddDataElement(Handle<JSObject> object, uint32_t index,
15746 Handle<Object> value,
15747 PropertyAttributes attributes) {
15748 DCHECK(object->map()->is_extensible());
15749
15750 Isolate* isolate = object->GetIsolate();
15751
15752 uint32_t old_length = 0;
15753 uint32_t new_capacity = 0;
15754
15755 if (object->IsJSArray()) {
15756 CHECK(JSArray::cast(*object)->length()->ToArrayLength(&old_length));
15757 }
15758
15759 ElementsKind kind = object->GetElementsKind();
15760 FixedArrayBase* elements = object->elements();
15761 ElementsKind dictionary_kind = DICTIONARY_ELEMENTS;
15762 if (IsSloppyArgumentsElementsKind(kind)) {
15763 elements = SloppyArgumentsElements::cast(elements)->arguments();
15764 dictionary_kind = SLOW_SLOPPY_ARGUMENTS_ELEMENTS;
15765 } else if (IsStringWrapperElementsKind(kind)) {
15766 dictionary_kind = SLOW_STRING_WRAPPER_ELEMENTS;
15767 }
15768
15769 if (attributes != NONE) {
15770 kind = dictionary_kind;
15771 } else if (elements->IsNumberDictionary()) {
15772 kind = ShouldConvertToFastElements(
15773 *object, NumberDictionary::cast(elements), index, &new_capacity)
15774 ? BestFittingFastElementsKind(*object)
15775 : dictionary_kind;
15776 } else if (ShouldConvertToSlowElements(
15777 *object, static_cast<uint32_t>(elements->length()), index,
15778 &new_capacity)) {
15779 kind = dictionary_kind;
15780 }
15781
15782 ElementsKind to = value->OptimalElementsKind();
15783 if (IsHoleyElementsKind(kind) || !object->IsJSArray() || index > old_length) {
15784 to = GetHoleyElementsKind(to);
15785 kind = GetHoleyElementsKind(kind);
15786 }
15787 to = GetMoreGeneralElementsKind(kind, to);
15788 ElementsAccessor* accessor = ElementsAccessor::ForKind(to);
15789 accessor->Add(object, index, value, attributes, new_capacity);
15790
15791 if (object->IsJSArray() && index >= old_length) {
15792 Handle<Object> new_length =
15793 isolate->factory()->NewNumberFromUint(index + 1);
15794 JSArray::cast(*object)->set_length(*new_length);
15795 }
15796 }
15797
15798
SetLengthWouldNormalize(uint32_t new_length)15799 bool JSArray::SetLengthWouldNormalize(uint32_t new_length) {
15800 if (!HasFastElements()) return false;
15801 uint32_t capacity = static_cast<uint32_t>(elements()->length());
15802 uint32_t new_capacity;
15803 return JSArray::SetLengthWouldNormalize(GetHeap(), new_length) &&
15804 ShouldConvertToSlowElements(this, capacity, new_length - 1,
15805 &new_capacity);
15806 }
15807
15808
15809 const double AllocationSite::kPretenureRatio = 0.85;
15810
15811
ResetPretenureDecision()15812 void AllocationSite::ResetPretenureDecision() {
15813 set_pretenure_decision(kUndecided);
15814 set_memento_found_count(0);
15815 set_memento_create_count(0);
15816 }
15817
GetPretenureMode() const15818 PretenureFlag AllocationSite::GetPretenureMode() const {
15819 PretenureDecision mode = pretenure_decision();
15820 // Zombie objects "decide" to be untenured.
15821 return mode == kTenure ? TENURED : NOT_TENURED;
15822 }
15823
IsNested()15824 bool AllocationSite::IsNested() {
15825 DCHECK(FLAG_trace_track_allocation_sites);
15826 Object* current = boilerplate()->GetHeap()->allocation_sites_list();
15827 while (current->IsAllocationSite()) {
15828 AllocationSite* current_site = AllocationSite::cast(current);
15829 if (current_site->nested_site() == this) {
15830 return true;
15831 }
15832 current = current_site->weak_next();
15833 }
15834 return false;
15835 }
15836
15837 template <AllocationSiteUpdateMode update_or_check>
DigestTransitionFeedback(Handle<AllocationSite> site,ElementsKind to_kind)15838 bool AllocationSite::DigestTransitionFeedback(Handle<AllocationSite> site,
15839 ElementsKind to_kind) {
15840 Isolate* isolate = site->GetIsolate();
15841 bool result = false;
15842
15843 if (site->PointsToLiteral() && site->boilerplate()->IsJSArray()) {
15844 Handle<JSArray> boilerplate(JSArray::cast(site->boilerplate()), isolate);
15845 ElementsKind kind = boilerplate->GetElementsKind();
15846 // if kind is holey ensure that to_kind is as well.
15847 if (IsHoleyElementsKind(kind)) {
15848 to_kind = GetHoleyElementsKind(to_kind);
15849 }
15850 if (IsMoreGeneralElementsKindTransition(kind, to_kind)) {
15851 // If the array is huge, it's not likely to be defined in a local
15852 // function, so we shouldn't make new instances of it very often.
15853 uint32_t length = 0;
15854 CHECK(boilerplate->length()->ToArrayLength(&length));
15855 if (length <= kMaximumArrayBytesToPretransition) {
15856 if (update_or_check == AllocationSiteUpdateMode::kCheckOnly) {
15857 return true;
15858 }
15859 if (FLAG_trace_track_allocation_sites) {
15860 bool is_nested = site->IsNested();
15861 PrintF("AllocationSite: JSArray %p boilerplate %supdated %s->%s\n",
15862 reinterpret_cast<void*>(*site), is_nested ? "(nested)" : " ",
15863 ElementsKindToString(kind), ElementsKindToString(to_kind));
15864 }
15865 JSObject::TransitionElementsKind(boilerplate, to_kind);
15866 site->dependent_code()->DeoptimizeDependentCodeGroup(
15867 isolate, DependentCode::kAllocationSiteTransitionChangedGroup);
15868 result = true;
15869 }
15870 }
15871 } else {
15872 // The AllocationSite is for a constructed Array.
15873 ElementsKind kind = site->GetElementsKind();
15874 // if kind is holey ensure that to_kind is as well.
15875 if (IsHoleyElementsKind(kind)) {
15876 to_kind = GetHoleyElementsKind(to_kind);
15877 }
15878 if (IsMoreGeneralElementsKindTransition(kind, to_kind)) {
15879 if (update_or_check == AllocationSiteUpdateMode::kCheckOnly) return true;
15880 if (FLAG_trace_track_allocation_sites) {
15881 PrintF("AllocationSite: JSArray %p site updated %s->%s\n",
15882 reinterpret_cast<void*>(*site),
15883 ElementsKindToString(kind),
15884 ElementsKindToString(to_kind));
15885 }
15886 site->SetElementsKind(to_kind);
15887 site->dependent_code()->DeoptimizeDependentCodeGroup(
15888 isolate, DependentCode::kAllocationSiteTransitionChangedGroup);
15889 result = true;
15890 }
15891 }
15892 return result;
15893 }
15894
ShouldTrack(ElementsKind from,ElementsKind to)15895 bool AllocationSite::ShouldTrack(ElementsKind from, ElementsKind to) {
15896 return IsSmiElementsKind(from) &&
15897 IsMoreGeneralElementsKindTransition(from, to);
15898 }
15899
PretenureDecisionName(PretenureDecision decision)15900 const char* AllocationSite::PretenureDecisionName(PretenureDecision decision) {
15901 switch (decision) {
15902 case kUndecided: return "undecided";
15903 case kDontTenure: return "don't tenure";
15904 case kMaybeTenure: return "maybe tenure";
15905 case kTenure: return "tenure";
15906 case kZombie: return "zombie";
15907 default: UNREACHABLE();
15908 }
15909 return nullptr;
15910 }
15911
15912 template <AllocationSiteUpdateMode update_or_check>
UpdateAllocationSite(Handle<JSObject> object,ElementsKind to_kind)15913 bool JSObject::UpdateAllocationSite(Handle<JSObject> object,
15914 ElementsKind to_kind) {
15915 if (!object->IsJSArray()) return false;
15916
15917 if (!Heap::InNewSpace(*object)) return false;
15918
15919 Handle<AllocationSite> site;
15920 {
15921 DisallowHeapAllocation no_allocation;
15922
15923 Heap* heap = object->GetHeap();
15924 AllocationMemento* memento =
15925 heap->FindAllocationMemento<Heap::kForRuntime>(object->map(), *object);
15926 if (memento == nullptr) return false;
15927
15928 // Walk through to the Allocation Site
15929 site = handle(memento->GetAllocationSite(), heap->isolate());
15930 }
15931 return AllocationSite::DigestTransitionFeedback<update_or_check>(site,
15932 to_kind);
15933 }
15934
15935 template bool
15936 JSObject::UpdateAllocationSite<AllocationSiteUpdateMode::kCheckOnly>(
15937 Handle<JSObject> object, ElementsKind to_kind);
15938
15939 template bool JSObject::UpdateAllocationSite<AllocationSiteUpdateMode::kUpdate>(
15940 Handle<JSObject> object, ElementsKind to_kind);
15941
TransitionElementsKind(Handle<JSObject> object,ElementsKind to_kind)15942 void JSObject::TransitionElementsKind(Handle<JSObject> object,
15943 ElementsKind to_kind) {
15944 ElementsKind from_kind = object->GetElementsKind();
15945
15946 if (IsHoleyElementsKind(from_kind)) {
15947 to_kind = GetHoleyElementsKind(to_kind);
15948 }
15949
15950 if (from_kind == to_kind) return;
15951
15952 // This method should never be called for any other case.
15953 DCHECK(IsFastElementsKind(from_kind));
15954 DCHECK(IsFastElementsKind(to_kind));
15955 DCHECK_NE(TERMINAL_FAST_ELEMENTS_KIND, from_kind);
15956
15957 UpdateAllocationSite(object, to_kind);
15958 if (object->elements() == object->GetReadOnlyRoots().empty_fixed_array() ||
15959 IsDoubleElementsKind(from_kind) == IsDoubleElementsKind(to_kind)) {
15960 // No change is needed to the elements() buffer, the transition
15961 // only requires a map change.
15962 Handle<Map> new_map = GetElementsTransitionMap(object, to_kind);
15963 MigrateToMap(object, new_map);
15964 if (FLAG_trace_elements_transitions) {
15965 Handle<FixedArrayBase> elms(object->elements(), object->GetIsolate());
15966 PrintElementsTransition(stdout, object, from_kind, elms, to_kind, elms);
15967 }
15968 } else {
15969 DCHECK((IsSmiElementsKind(from_kind) && IsDoubleElementsKind(to_kind)) ||
15970 (IsDoubleElementsKind(from_kind) && IsObjectElementsKind(to_kind)));
15971 uint32_t c = static_cast<uint32_t>(object->elements()->length());
15972 ElementsAccessor::ForKind(to_kind)->GrowCapacityAndConvert(object, c);
15973 }
15974 }
15975
15976
15977 // static
IsValidElementsTransition(ElementsKind from_kind,ElementsKind to_kind)15978 bool Map::IsValidElementsTransition(ElementsKind from_kind,
15979 ElementsKind to_kind) {
15980 // Transitions can't go backwards.
15981 if (!IsMoreGeneralElementsKindTransition(from_kind, to_kind)) {
15982 return false;
15983 }
15984
15985 // Transitions from HOLEY -> PACKED are not allowed.
15986 return !IsHoleyElementsKind(from_kind) || IsHoleyElementsKind(to_kind);
15987 }
15988
15989
HasReadOnlyLength(Handle<JSArray> array)15990 bool JSArray::HasReadOnlyLength(Handle<JSArray> array) {
15991 Map* map = array->map();
15992 // Fast path: "length" is the first fast property of arrays. Since it's not
15993 // configurable, it's guaranteed to be the first in the descriptor array.
15994 if (!map->is_dictionary_map()) {
15995 DCHECK(map->instance_descriptors()->GetKey(0) ==
15996 array->GetReadOnlyRoots().length_string());
15997 return map->instance_descriptors()->GetDetails(0).IsReadOnly();
15998 }
15999
16000 Isolate* isolate = array->GetIsolate();
16001 LookupIterator it(array, isolate->factory()->length_string(), array,
16002 LookupIterator::OWN_SKIP_INTERCEPTOR);
16003 CHECK_EQ(LookupIterator::ACCESSOR, it.state());
16004 return it.IsReadOnly();
16005 }
16006
16007
WouldChangeReadOnlyLength(Handle<JSArray> array,uint32_t index)16008 bool JSArray::WouldChangeReadOnlyLength(Handle<JSArray> array,
16009 uint32_t index) {
16010 uint32_t length = 0;
16011 CHECK(array->length()->ToArrayLength(&length));
16012 if (length <= index) return HasReadOnlyLength(array);
16013 return false;
16014 }
16015
16016 template <typename BackingStore>
HoleyElementsUsage(JSObject * object,BackingStore * store)16017 static int HoleyElementsUsage(JSObject* object, BackingStore* store) {
16018 Isolate* isolate = object->GetIsolate();
16019 int limit = object->IsJSArray() ? Smi::ToInt(JSArray::cast(object)->length())
16020 : store->length();
16021 int used = 0;
16022 for (int i = 0; i < limit; ++i) {
16023 if (!store->is_the_hole(isolate, i)) ++used;
16024 }
16025 return used;
16026 }
16027
GetFastElementsUsage()16028 int JSObject::GetFastElementsUsage() {
16029 FixedArrayBase* store = elements();
16030 switch (GetElementsKind()) {
16031 case PACKED_SMI_ELEMENTS:
16032 case PACKED_DOUBLE_ELEMENTS:
16033 case PACKED_ELEMENTS:
16034 return IsJSArray() ? Smi::ToInt(JSArray::cast(this)->length())
16035 : store->length();
16036 case FAST_SLOPPY_ARGUMENTS_ELEMENTS:
16037 store = SloppyArgumentsElements::cast(store)->arguments();
16038 V8_FALLTHROUGH;
16039 case HOLEY_SMI_ELEMENTS:
16040 case HOLEY_ELEMENTS:
16041 case FAST_STRING_WRAPPER_ELEMENTS:
16042 return HoleyElementsUsage(this, FixedArray::cast(store));
16043 case HOLEY_DOUBLE_ELEMENTS:
16044 if (elements()->length() == 0) return 0;
16045 return HoleyElementsUsage(this, FixedDoubleArray::cast(store));
16046
16047 case SLOW_SLOPPY_ARGUMENTS_ELEMENTS:
16048 case SLOW_STRING_WRAPPER_ELEMENTS:
16049 case DICTIONARY_ELEMENTS:
16050 case NO_ELEMENTS:
16051 #define TYPED_ARRAY_CASE(Type, type, TYPE, ctype) case TYPE##_ELEMENTS:
16052
16053 TYPED_ARRAYS(TYPED_ARRAY_CASE)
16054 #undef TYPED_ARRAY_CASE
16055 UNREACHABLE();
16056 }
16057 return 0;
16058 }
16059
16060
16061 // Certain compilers request function template instantiation when they
16062 // see the definition of the other template functions in the
16063 // class. This requires us to have the template functions put
16064 // together, so even though this function belongs in objects-debug.cc,
16065 // we keep it here instead to satisfy certain compilers.
16066 #ifdef OBJECT_PRINT
16067 template <typename Derived, typename Shape>
Print(std::ostream & os)16068 void Dictionary<Derived, Shape>::Print(std::ostream& os) {
16069 DisallowHeapAllocation no_gc;
16070 ReadOnlyRoots roots = this->GetReadOnlyRoots();
16071 Derived* dictionary = Derived::cast(this);
16072 int capacity = dictionary->Capacity();
16073 for (int i = 0; i < capacity; i++) {
16074 Object* k = dictionary->KeyAt(i);
16075 if (!dictionary->ToKey(roots, i, &k)) continue;
16076 os << "\n ";
16077 if (k->IsString()) {
16078 String::cast(k)->StringPrint(os);
16079 } else {
16080 os << Brief(k);
16081 }
16082 os << ": " << Brief(dictionary->ValueAt(i)) << " ";
16083 dictionary->DetailsAt(i).PrintAsSlowTo(os);
16084 }
16085 }
16086 template <typename Derived, typename Shape>
Print()16087 void Dictionary<Derived, Shape>::Print() {
16088 StdoutStream os;
16089 Print(os);
16090 os << std::endl;
16091 }
16092 #endif
16093
16094
GetPropertyWithInterceptor(LookupIterator * it,bool * done)16095 MaybeHandle<Object> JSObject::GetPropertyWithInterceptor(LookupIterator* it,
16096 bool* done) {
16097 DCHECK_EQ(LookupIterator::INTERCEPTOR, it->state());
16098 return GetPropertyWithInterceptorInternal(it, it->GetInterceptor(), done);
16099 }
16100
HasRealNamedProperty(Handle<JSObject> object,Handle<Name> name)16101 Maybe<bool> JSObject::HasRealNamedProperty(Handle<JSObject> object,
16102 Handle<Name> name) {
16103 LookupIterator it = LookupIterator::PropertyOrElement(
16104 object->GetIsolate(), object, name, LookupIterator::OWN_SKIP_INTERCEPTOR);
16105 return HasProperty(&it);
16106 }
16107
16108
HasRealElementProperty(Handle<JSObject> object,uint32_t index)16109 Maybe<bool> JSObject::HasRealElementProperty(Handle<JSObject> object,
16110 uint32_t index) {
16111 Isolate* isolate = object->GetIsolate();
16112 LookupIterator it(isolate, object, index, object,
16113 LookupIterator::OWN_SKIP_INTERCEPTOR);
16114 return HasProperty(&it);
16115 }
16116
16117
HasRealNamedCallbackProperty(Handle<JSObject> object,Handle<Name> name)16118 Maybe<bool> JSObject::HasRealNamedCallbackProperty(Handle<JSObject> object,
16119 Handle<Name> name) {
16120 LookupIterator it = LookupIterator::PropertyOrElement(
16121 object->GetIsolate(), object, name, LookupIterator::OWN_SKIP_INTERCEPTOR);
16122 Maybe<PropertyAttributes> maybe_result = GetPropertyAttributes(&it);
16123 return maybe_result.IsJust() ? Just(it.state() == LookupIterator::ACCESSOR)
16124 : Nothing<bool>();
16125 }
16126
GetMaxLengthForNewSpaceAllocation(ElementsKind kind)16127 int FixedArrayBase::GetMaxLengthForNewSpaceAllocation(ElementsKind kind) {
16128 return ((kMaxRegularHeapObjectSize - FixedArrayBase::kHeaderSize) >>
16129 ElementsKindToShiftSize(kind));
16130 }
16131
IsCowArray() const16132 bool FixedArrayBase::IsCowArray() const {
16133 return map() == GetReadOnlyRoots().fixed_cow_array_map();
16134 }
16135
IsApiWrapper()16136 bool JSObject::IsApiWrapper() {
16137 auto instance_type = map()->instance_type();
16138 return instance_type == JS_API_OBJECT_TYPE ||
16139 instance_type == JS_SPECIAL_API_OBJECT_TYPE;
16140 }
16141
PrivateSymbolToName() const16142 const char* Symbol::PrivateSymbolToName() const {
16143 ReadOnlyRoots roots = GetReadOnlyRoots();
16144 #define SYMBOL_CHECK_AND_PRINT(name) \
16145 if (this == roots.name()) return #name;
16146 PRIVATE_SYMBOL_LIST(SYMBOL_CHECK_AND_PRINT)
16147 #undef SYMBOL_CHECK_AND_PRINT
16148 return "UNKNOWN";
16149 }
16150
16151
SymbolShortPrint(std::ostream & os)16152 void Symbol::SymbolShortPrint(std::ostream& os) {
16153 os << "<Symbol:";
16154 if (!name()->IsUndefined()) {
16155 os << " ";
16156 HeapStringAllocator allocator;
16157 StringStream accumulator(&allocator);
16158 String::cast(name())->StringShortPrint(&accumulator, false);
16159 os << accumulator.ToCString().get();
16160 } else {
16161 os << " (" << PrivateSymbolToName() << ")";
16162 }
16163 os << ">";
16164 }
16165
16166
16167 // StringSharedKeys are used as keys in the eval cache.
16168 class StringSharedKey : public HashTableKey {
16169 public:
16170 // This tuple unambiguously identifies calls to eval() or
16171 // CreateDynamicFunction() (such as through the Function() constructor).
16172 // * source is the string passed into eval(). For dynamic functions, this is
16173 // the effective source for the function, some of which is implicitly
16174 // generated.
16175 // * shared is the shared function info for the function containing the call
16176 // to eval(). for dynamic functions, shared is the native context closure.
16177 // * When positive, position is the position in the source where eval is
16178 // called. When negative, position is the negation of the position in the
16179 // dynamic function's effective source where the ')' ends the parameters.
StringSharedKey(Handle<String> source,Handle<SharedFunctionInfo> shared,LanguageMode language_mode,int position)16180 StringSharedKey(Handle<String> source, Handle<SharedFunctionInfo> shared,
16181 LanguageMode language_mode, int position)
16182 : HashTableKey(CompilationCacheShape::StringSharedHash(
16183 *source, *shared, language_mode, position)),
16184 source_(source),
16185 shared_(shared),
16186 language_mode_(language_mode),
16187 position_(position) {}
16188
IsMatch(Object * other)16189 bool IsMatch(Object* other) override {
16190 DisallowHeapAllocation no_allocation;
16191 if (!other->IsFixedArray()) {
16192 DCHECK(other->IsNumber());
16193 uint32_t other_hash = static_cast<uint32_t>(other->Number());
16194 return Hash() == other_hash;
16195 }
16196 FixedArray* other_array = FixedArray::cast(other);
16197 SharedFunctionInfo* shared = SharedFunctionInfo::cast(other_array->get(0));
16198 if (shared != *shared_) return false;
16199 int language_unchecked = Smi::ToInt(other_array->get(2));
16200 DCHECK(is_valid_language_mode(language_unchecked));
16201 LanguageMode language_mode = static_cast<LanguageMode>(language_unchecked);
16202 if (language_mode != language_mode_) return false;
16203 int position = Smi::ToInt(other_array->get(3));
16204 if (position != position_) return false;
16205 String* source = String::cast(other_array->get(1));
16206 return source->Equals(*source_);
16207 }
16208
AsHandle(Isolate * isolate)16209 Handle<Object> AsHandle(Isolate* isolate) {
16210 Handle<FixedArray> array = isolate->factory()->NewFixedArray(4);
16211 array->set(0, *shared_);
16212 array->set(1, *source_);
16213 array->set(2, Smi::FromEnum(language_mode_));
16214 array->set(3, Smi::FromInt(position_));
16215 array->set_map(ReadOnlyRoots(isolate).fixed_cow_array_map());
16216 return array;
16217 }
16218
16219 private:
16220 Handle<String> source_;
16221 Handle<SharedFunctionInfo> shared_;
16222 LanguageMode language_mode_;
16223 int position_;
16224 };
16225
status() const16226 v8::Promise::PromiseState JSPromise::status() const {
16227 int value = flags() & kStatusMask;
16228 DCHECK(value == 0 || value == 1 || value == 2);
16229 return static_cast<v8::Promise::PromiseState>(value);
16230 }
16231
set_status(Promise::PromiseState status)16232 void JSPromise::set_status(Promise::PromiseState status) {
16233 int value = flags() & ~kStatusMask;
16234 set_flags(value | status);
16235 }
16236
16237 // static
Status(v8::Promise::PromiseState status)16238 const char* JSPromise::Status(v8::Promise::PromiseState status) {
16239 switch (status) {
16240 case v8::Promise::kFulfilled:
16241 return "resolved";
16242 case v8::Promise::kPending:
16243 return "pending";
16244 case v8::Promise::kRejected:
16245 return "rejected";
16246 }
16247 UNREACHABLE();
16248 }
16249
async_task_id() const16250 int JSPromise::async_task_id() const {
16251 return AsyncTaskIdField::decode(flags());
16252 }
16253
set_async_task_id(int id)16254 void JSPromise::set_async_task_id(int id) {
16255 set_flags(AsyncTaskIdField::update(flags(), id));
16256 }
16257
16258 // static
Fulfill(Handle<JSPromise> promise,Handle<Object> value)16259 Handle<Object> JSPromise::Fulfill(Handle<JSPromise> promise,
16260 Handle<Object> value) {
16261 Isolate* const isolate = promise->GetIsolate();
16262
16263 // 1. Assert: The value of promise.[[PromiseState]] is "pending".
16264 DCHECK_EQ(Promise::kPending, promise->status());
16265
16266 // 2. Let reactions be promise.[[PromiseFulfillReactions]].
16267 Handle<Object> reactions(promise->reactions(), isolate);
16268
16269 // 3. Set promise.[[PromiseResult]] to value.
16270 // 4. Set promise.[[PromiseFulfillReactions]] to undefined.
16271 // 5. Set promise.[[PromiseRejectReactions]] to undefined.
16272 promise->set_reactions_or_result(*value);
16273
16274 // 6. Set promise.[[PromiseState]] to "fulfilled".
16275 promise->set_status(Promise::kFulfilled);
16276
16277 // 7. Return TriggerPromiseReactions(reactions, value).
16278 return TriggerPromiseReactions(isolate, reactions, value,
16279 PromiseReaction::kFulfill);
16280 }
16281
16282 // static
Reject(Handle<JSPromise> promise,Handle<Object> reason,bool debug_event)16283 Handle<Object> JSPromise::Reject(Handle<JSPromise> promise,
16284 Handle<Object> reason, bool debug_event) {
16285 Isolate* const isolate = promise->GetIsolate();
16286
16287 if (debug_event) isolate->debug()->OnPromiseReject(promise, reason);
16288 isolate->RunPromiseHook(PromiseHookType::kResolve, promise,
16289 isolate->factory()->undefined_value());
16290
16291 // 1. Assert: The value of promise.[[PromiseState]] is "pending".
16292 DCHECK_EQ(Promise::kPending, promise->status());
16293
16294 // 2. Let reactions be promise.[[PromiseRejectReactions]].
16295 Handle<Object> reactions(promise->reactions(), isolate);
16296
16297 // 3. Set promise.[[PromiseResult]] to reason.
16298 // 4. Set promise.[[PromiseFulfillReactions]] to undefined.
16299 // 5. Set promise.[[PromiseRejectReactions]] to undefined.
16300 promise->set_reactions_or_result(*reason);
16301
16302 // 6. Set promise.[[PromiseState]] to "rejected".
16303 promise->set_status(Promise::kRejected);
16304
16305 // 7. If promise.[[PromiseIsHandled]] is false, perform
16306 // HostPromiseRejectionTracker(promise, "reject").
16307 if (!promise->has_handler()) {
16308 isolate->ReportPromiseReject(promise, reason, kPromiseRejectWithNoHandler);
16309 }
16310
16311 // 8. Return TriggerPromiseReactions(reactions, reason).
16312 return TriggerPromiseReactions(isolate, reactions, reason,
16313 PromiseReaction::kReject);
16314 }
16315
16316 // static
Resolve(Handle<JSPromise> promise,Handle<Object> resolution)16317 MaybeHandle<Object> JSPromise::Resolve(Handle<JSPromise> promise,
16318 Handle<Object> resolution) {
16319 Isolate* const isolate = promise->GetIsolate();
16320
16321 isolate->RunPromiseHook(PromiseHookType::kResolve, promise,
16322 isolate->factory()->undefined_value());
16323
16324 // 6. If SameValue(resolution, promise) is true, then
16325 if (promise.is_identical_to(resolution)) {
16326 // a. Let selfResolutionError be a newly created TypeError object.
16327 Handle<Object> self_resolution_error = isolate->factory()->NewTypeError(
16328 MessageTemplate::kPromiseCyclic, resolution);
16329 // b. Return RejectPromise(promise, selfResolutionError).
16330 return Reject(promise, self_resolution_error);
16331 }
16332
16333 // 7. If Type(resolution) is not Object, then
16334 if (!resolution->IsJSReceiver()) {
16335 // a. Return FulfillPromise(promise, resolution).
16336 return Fulfill(promise, resolution);
16337 }
16338
16339 // 8. Let then be Get(resolution, "then").
16340 MaybeHandle<Object> then;
16341 if (isolate->IsPromiseThenLookupChainIntact(
16342 Handle<JSReceiver>::cast(resolution))) {
16343 // We can skip the "then" lookup on {resolution} if its [[Prototype]]
16344 // is the (initial) Promise.prototype and the Promise#then protector
16345 // is intact, as that guards the lookup path for the "then" property
16346 // on JSPromise instances which have the (initial) %PromisePrototype%.
16347 then = isolate->promise_then();
16348 } else {
16349 then =
16350 JSReceiver::GetProperty(isolate, Handle<JSReceiver>::cast(resolution),
16351 isolate->factory()->then_string());
16352 }
16353
16354 // 9. If then is an abrupt completion, then
16355 Handle<Object> then_action;
16356 if (!then.ToHandle(&then_action)) {
16357 // a. Return RejectPromise(promise, then.[[Value]]).
16358 Handle<Object> reason(isolate->pending_exception(), isolate);
16359 isolate->clear_pending_exception();
16360 return Reject(promise, reason, false);
16361 }
16362
16363 // 10. Let thenAction be then.[[Value]].
16364 // 11. If IsCallable(thenAction) is false, then
16365 if (!then_action->IsCallable()) {
16366 // a. Return FulfillPromise(promise, resolution).
16367 return Fulfill(promise, resolution);
16368 }
16369
16370 // 12. Perform EnqueueJob("PromiseJobs", PromiseResolveThenableJob,
16371 // «promise, resolution, thenAction»).
16372 Handle<PromiseResolveThenableJobTask> task =
16373 isolate->factory()->NewPromiseResolveThenableJobTask(
16374 promise, Handle<JSReceiver>::cast(then_action),
16375 Handle<JSReceiver>::cast(resolution), isolate->native_context());
16376 if (isolate->debug()->is_active() && resolution->IsJSPromise()) {
16377 // Mark the dependency of the new {promise} on the {resolution}.
16378 Object::SetProperty(isolate, resolution,
16379 isolate->factory()->promise_handled_by_symbol(),
16380 promise, LanguageMode::kStrict)
16381 .Check();
16382 }
16383 isolate->EnqueueMicrotask(task);
16384
16385 // 13. Return undefined.
16386 return isolate->factory()->undefined_value();
16387 }
16388
16389 // static
TriggerPromiseReactions(Isolate * isolate,Handle<Object> reactions,Handle<Object> argument,PromiseReaction::Type type)16390 Handle<Object> JSPromise::TriggerPromiseReactions(Isolate* isolate,
16391 Handle<Object> reactions,
16392 Handle<Object> argument,
16393 PromiseReaction::Type type) {
16394 DCHECK(reactions->IsSmi() || reactions->IsPromiseReaction());
16395
16396 // We need to reverse the {reactions} here, since we record them
16397 // on the JSPromise in the reverse order.
16398 {
16399 DisallowHeapAllocation no_gc;
16400 Object* current = *reactions;
16401 Object* reversed = Smi::kZero;
16402 while (!current->IsSmi()) {
16403 Object* next = PromiseReaction::cast(current)->next();
16404 PromiseReaction::cast(current)->set_next(reversed);
16405 reversed = current;
16406 current = next;
16407 }
16408 reactions = handle(reversed, isolate);
16409 }
16410
16411 // Morph the {reactions} into PromiseReactionJobTasks
16412 // and push them onto the microtask queue.
16413 while (!reactions->IsSmi()) {
16414 Handle<HeapObject> task = Handle<HeapObject>::cast(reactions);
16415 Handle<PromiseReaction> reaction = Handle<PromiseReaction>::cast(task);
16416 reactions = handle(reaction->next(), isolate);
16417
16418 STATIC_ASSERT(PromiseReaction::kSize == PromiseReactionJobTask::kSize);
16419 if (type == PromiseReaction::kFulfill) {
16420 task->synchronized_set_map(
16421 ReadOnlyRoots(isolate).promise_fulfill_reaction_job_task_map());
16422 Handle<PromiseFulfillReactionJobTask>::cast(task)->set_argument(
16423 *argument);
16424 Handle<PromiseFulfillReactionJobTask>::cast(task)->set_context(
16425 *isolate->native_context());
16426 STATIC_ASSERT(PromiseReaction::kFulfillHandlerOffset ==
16427 PromiseFulfillReactionJobTask::kHandlerOffset);
16428 STATIC_ASSERT(PromiseReaction::kPromiseOrCapabilityOffset ==
16429 PromiseFulfillReactionJobTask::kPromiseOrCapabilityOffset);
16430 } else {
16431 DisallowHeapAllocation no_gc;
16432 HeapObject* handler = reaction->reject_handler();
16433 task->synchronized_set_map(
16434 ReadOnlyRoots(isolate).promise_reject_reaction_job_task_map());
16435 Handle<PromiseRejectReactionJobTask>::cast(task)->set_argument(*argument);
16436 Handle<PromiseRejectReactionJobTask>::cast(task)->set_context(
16437 *isolate->native_context());
16438 Handle<PromiseRejectReactionJobTask>::cast(task)->set_handler(handler);
16439 STATIC_ASSERT(PromiseReaction::kPromiseOrCapabilityOffset ==
16440 PromiseRejectReactionJobTask::kPromiseOrCapabilityOffset);
16441 }
16442
16443 isolate->EnqueueMicrotask(Handle<PromiseReactionJobTask>::cast(task));
16444 }
16445
16446 return isolate->factory()->undefined_value();
16447 }
16448
16449 namespace {
16450
RegExpFlagsFromString(Handle<String> flags,bool * success)16451 JSRegExp::Flags RegExpFlagsFromString(Handle<String> flags, bool* success) {
16452 JSRegExp::Flags value = JSRegExp::kNone;
16453 int length = flags->length();
16454 // A longer flags string cannot be valid.
16455 if (length > JSRegExp::FlagCount()) return JSRegExp::Flags(0);
16456 for (int i = 0; i < length; i++) {
16457 JSRegExp::Flag flag = JSRegExp::kNone;
16458 switch (flags->Get(i)) {
16459 case 'g':
16460 flag = JSRegExp::kGlobal;
16461 break;
16462 case 'i':
16463 flag = JSRegExp::kIgnoreCase;
16464 break;
16465 case 'm':
16466 flag = JSRegExp::kMultiline;
16467 break;
16468 case 's':
16469 flag = JSRegExp::kDotAll;
16470 break;
16471 case 'u':
16472 flag = JSRegExp::kUnicode;
16473 break;
16474 case 'y':
16475 flag = JSRegExp::kSticky;
16476 break;
16477 default:
16478 return JSRegExp::Flags(0);
16479 }
16480 // Duplicate flag.
16481 if (value & flag) return JSRegExp::Flags(0);
16482 value |= flag;
16483 }
16484 *success = true;
16485 return value;
16486 }
16487
16488 } // namespace
16489
16490
16491 // static
New(Isolate * isolate,Handle<String> pattern,Flags flags)16492 MaybeHandle<JSRegExp> JSRegExp::New(Isolate* isolate, Handle<String> pattern,
16493 Flags flags) {
16494 Handle<JSFunction> constructor = isolate->regexp_function();
16495 Handle<JSRegExp> regexp =
16496 Handle<JSRegExp>::cast(isolate->factory()->NewJSObject(constructor));
16497
16498 return JSRegExp::Initialize(regexp, pattern, flags);
16499 }
16500
16501
16502 // static
Copy(Handle<JSRegExp> regexp)16503 Handle<JSRegExp> JSRegExp::Copy(Handle<JSRegExp> regexp) {
16504 Isolate* const isolate = regexp->GetIsolate();
16505 return Handle<JSRegExp>::cast(isolate->factory()->CopyJSObject(regexp));
16506 }
16507
16508
16509 template <typename Char>
CountRequiredEscapes(Handle<String> source)16510 inline int CountRequiredEscapes(Handle<String> source) {
16511 DisallowHeapAllocation no_gc;
16512 int escapes = 0;
16513 Vector<const Char> src = source->GetCharVector<Char>();
16514 for (int i = 0; i < src.length(); i++) {
16515 if (src[i] == '\\') {
16516 // Escape. Skip next character;
16517 i++;
16518 } else if (src[i] == '/') {
16519 // Not escaped forward-slash needs escape.
16520 escapes++;
16521 }
16522 }
16523 return escapes;
16524 }
16525
16526
16527 template <typename Char, typename StringType>
WriteEscapedRegExpSource(Handle<String> source,Handle<StringType> result)16528 inline Handle<StringType> WriteEscapedRegExpSource(Handle<String> source,
16529 Handle<StringType> result) {
16530 DisallowHeapAllocation no_gc;
16531 Vector<const Char> src = source->GetCharVector<Char>();
16532 Vector<Char> dst(result->GetChars(), result->length());
16533 int s = 0;
16534 int d = 0;
16535 while (s < src.length()) {
16536 if (src[s] == '\\') {
16537 // Escape. Copy this and next character.
16538 dst[d++] = src[s++];
16539 if (s == src.length()) break;
16540 } else if (src[s] == '/') {
16541 // Not escaped forward-slash needs escape.
16542 dst[d++] = '\\';
16543 }
16544 dst[d++] = src[s++];
16545 }
16546 DCHECK_EQ(result->length(), d);
16547 return result;
16548 }
16549
16550
EscapeRegExpSource(Isolate * isolate,Handle<String> source)16551 MaybeHandle<String> EscapeRegExpSource(Isolate* isolate,
16552 Handle<String> source) {
16553 DCHECK(source->IsFlat());
16554 if (source->length() == 0) return isolate->factory()->query_colon_string();
16555 bool one_byte = source->IsOneByteRepresentationUnderneath();
16556 int escapes = one_byte ? CountRequiredEscapes<uint8_t>(source)
16557 : CountRequiredEscapes<uc16>(source);
16558 if (escapes == 0) return source;
16559 int length = source->length() + escapes;
16560 if (one_byte) {
16561 Handle<SeqOneByteString> result;
16562 ASSIGN_RETURN_ON_EXCEPTION(isolate, result,
16563 isolate->factory()->NewRawOneByteString(length),
16564 String);
16565 return WriteEscapedRegExpSource<uint8_t>(source, result);
16566 } else {
16567 Handle<SeqTwoByteString> result;
16568 ASSIGN_RETURN_ON_EXCEPTION(isolate, result,
16569 isolate->factory()->NewRawTwoByteString(length),
16570 String);
16571 return WriteEscapedRegExpSource<uc16>(source, result);
16572 }
16573 }
16574
16575
16576 // static
Initialize(Handle<JSRegExp> regexp,Handle<String> source,Handle<String> flags_string)16577 MaybeHandle<JSRegExp> JSRegExp::Initialize(Handle<JSRegExp> regexp,
16578 Handle<String> source,
16579 Handle<String> flags_string) {
16580 Isolate* isolate = regexp->GetIsolate();
16581 bool success = false;
16582 Flags flags = RegExpFlagsFromString(flags_string, &success);
16583 if (!success) {
16584 THROW_NEW_ERROR(
16585 isolate,
16586 NewSyntaxError(MessageTemplate::kInvalidRegExpFlags, flags_string),
16587 JSRegExp);
16588 }
16589 return Initialize(regexp, source, flags);
16590 }
16591
16592
16593 // static
Initialize(Handle<JSRegExp> regexp,Handle<String> source,Flags flags)16594 MaybeHandle<JSRegExp> JSRegExp::Initialize(Handle<JSRegExp> regexp,
16595 Handle<String> source, Flags flags) {
16596 Isolate* isolate = regexp->GetIsolate();
16597 Factory* factory = isolate->factory();
16598 // If source is the empty string we set it to "(?:)" instead as
16599 // suggested by ECMA-262, 5th, section 15.10.4.1.
16600 if (source->length() == 0) source = factory->query_colon_string();
16601
16602 source = String::Flatten(isolate, source);
16603
16604 Handle<String> escaped_source;
16605 ASSIGN_RETURN_ON_EXCEPTION(isolate, escaped_source,
16606 EscapeRegExpSource(isolate, source), JSRegExp);
16607
16608 RETURN_ON_EXCEPTION(
16609 isolate, RegExpImpl::Compile(isolate, regexp, source, flags), JSRegExp);
16610
16611 regexp->set_source(*escaped_source);
16612 regexp->set_flags(Smi::FromInt(flags));
16613
16614 Map* map = regexp->map();
16615 Object* constructor = map->GetConstructor();
16616 if (constructor->IsJSFunction() &&
16617 JSFunction::cast(constructor)->initial_map() == map) {
16618 // If we still have the original map, set in-object properties directly.
16619 regexp->InObjectPropertyAtPut(JSRegExp::kLastIndexFieldIndex, Smi::kZero,
16620 SKIP_WRITE_BARRIER);
16621 } else {
16622 // Map has changed, so use generic, but slower, method.
16623 RETURN_ON_EXCEPTION(
16624 isolate,
16625 JSReceiver::SetProperty(isolate, regexp, factory->lastIndex_string(),
16626 Handle<Smi>(Smi::kZero, isolate),
16627 LanguageMode::kStrict),
16628 JSRegExp);
16629 }
16630
16631 return regexp;
16632 }
16633
16634
16635 // RegExpKey carries the source and flags of a regular expression as key.
16636 class RegExpKey : public HashTableKey {
16637 public:
RegExpKey(Handle<String> string,JSRegExp::Flags flags)16638 RegExpKey(Handle<String> string, JSRegExp::Flags flags)
16639 : HashTableKey(
16640 CompilationCacheShape::RegExpHash(*string, Smi::FromInt(flags))),
16641 string_(string),
16642 flags_(Smi::FromInt(flags)) {}
16643
16644 // Rather than storing the key in the hash table, a pointer to the
16645 // stored value is stored where the key should be. IsMatch then
16646 // compares the search key to the found object, rather than comparing
16647 // a key to a key.
IsMatch(Object * obj)16648 bool IsMatch(Object* obj) override {
16649 FixedArray* val = FixedArray::cast(obj);
16650 return string_->Equals(String::cast(val->get(JSRegExp::kSourceIndex)))
16651 && (flags_ == val->get(JSRegExp::kFlagsIndex));
16652 }
16653
16654 Handle<String> string_;
16655 Smi* flags_;
16656 };
16657
AsHandle(Isolate * isolate)16658 Handle<String> OneByteStringKey::AsHandle(Isolate* isolate) {
16659 return isolate->factory()->NewOneByteInternalizedString(string_, HashField());
16660 }
16661
AsHandle(Isolate * isolate)16662 Handle<String> TwoByteStringKey::AsHandle(Isolate* isolate) {
16663 return isolate->factory()->NewTwoByteInternalizedString(string_, HashField());
16664 }
16665
AsHandle(Isolate * isolate)16666 Handle<String> SeqOneByteSubStringKey::AsHandle(Isolate* isolate) {
16667 return isolate->factory()->NewOneByteInternalizedSubString(
16668 string_, from_, length_, HashField());
16669 }
16670
16671
IsMatch(Object * string)16672 bool SeqOneByteSubStringKey::IsMatch(Object* string) {
16673 Vector<const uint8_t> chars(string_->GetChars() + from_, length_);
16674 return String::cast(string)->IsOneByteEqualTo(chars);
16675 }
16676
16677
16678 // InternalizedStringKey carries a string/internalized-string object as key.
16679 class InternalizedStringKey : public StringTableKey {
16680 public:
InternalizedStringKey(Handle<String> string)16681 explicit InternalizedStringKey(Handle<String> string)
16682 : StringTableKey(0), string_(string) {
16683 DCHECK(!string->IsInternalizedString());
16684 DCHECK(string->IsFlat());
16685 // Make sure hash_field is computed.
16686 string->Hash();
16687 set_hash_field(string->hash_field());
16688 }
16689
IsMatch(Object * string)16690 bool IsMatch(Object* string) override {
16691 return string_->SlowEquals(String::cast(string));
16692 }
16693
AsHandle(Isolate * isolate)16694 Handle<String> AsHandle(Isolate* isolate) override {
16695 // Internalize the string if possible.
16696 MaybeHandle<Map> maybe_map =
16697 isolate->factory()->InternalizedStringMapForString(string_);
16698 Handle<Map> map;
16699 if (maybe_map.ToHandle(&map)) {
16700 string_->set_map_no_write_barrier(*map);
16701 DCHECK(string_->IsInternalizedString());
16702 return string_;
16703 }
16704 if (FLAG_thin_strings) {
16705 // External strings get special treatment, to avoid copying their
16706 // contents.
16707 if (string_->IsExternalOneByteString()) {
16708 return isolate->factory()
16709 ->InternalizeExternalString<ExternalOneByteString>(string_);
16710 } else if (string_->IsExternalTwoByteString()) {
16711 return isolate->factory()
16712 ->InternalizeExternalString<ExternalTwoByteString>(string_);
16713 }
16714 }
16715 // Otherwise allocate a new internalized string.
16716 return isolate->factory()->NewInternalizedStringImpl(
16717 string_, string_->length(), string_->hash_field());
16718 }
16719
16720 private:
16721 Handle<String> string_;
16722 };
16723
16724 template <typename Derived, typename Shape>
IteratePrefix(ObjectVisitor * v)16725 void HashTable<Derived, Shape>::IteratePrefix(ObjectVisitor* v) {
16726 BodyDescriptorBase::IteratePointers(this, 0, kElementsStartOffset, v);
16727 }
16728
16729 template <typename Derived, typename Shape>
IterateElements(ObjectVisitor * v)16730 void HashTable<Derived, Shape>::IterateElements(ObjectVisitor* v) {
16731 BodyDescriptorBase::IteratePointers(this, kElementsStartOffset,
16732 kHeaderSize + length() * kPointerSize, v);
16733 }
16734
16735 template <typename Derived, typename Shape>
New(Isolate * isolate,int at_least_space_for,PretenureFlag pretenure,MinimumCapacity capacity_option)16736 Handle<Derived> HashTable<Derived, Shape>::New(
16737 Isolate* isolate, int at_least_space_for, PretenureFlag pretenure,
16738 MinimumCapacity capacity_option) {
16739 DCHECK_LE(0, at_least_space_for);
16740 DCHECK_IMPLIES(capacity_option == USE_CUSTOM_MINIMUM_CAPACITY,
16741 base::bits::IsPowerOfTwo(at_least_space_for));
16742
16743 int capacity = (capacity_option == USE_CUSTOM_MINIMUM_CAPACITY)
16744 ? at_least_space_for
16745 : ComputeCapacity(at_least_space_for);
16746 if (capacity > HashTable::kMaxCapacity) {
16747 isolate->heap()->FatalProcessOutOfMemory("invalid table size");
16748 }
16749 return NewInternal(isolate, capacity, pretenure);
16750 }
16751
16752 template <typename Derived, typename Shape>
NewInternal(Isolate * isolate,int capacity,PretenureFlag pretenure)16753 Handle<Derived> HashTable<Derived, Shape>::NewInternal(
16754 Isolate* isolate, int capacity, PretenureFlag pretenure) {
16755 Factory* factory = isolate->factory();
16756 int length = EntryToIndex(capacity);
16757 Heap::RootListIndex map_root_index =
16758 static_cast<Heap::RootListIndex>(Shape::GetMapRootIndex());
16759 Handle<FixedArray> array =
16760 factory->NewFixedArrayWithMap(map_root_index, length, pretenure);
16761 Handle<Derived> table = Handle<Derived>::cast(array);
16762
16763 table->SetNumberOfElements(0);
16764 table->SetNumberOfDeletedElements(0);
16765 table->SetCapacity(capacity);
16766 return table;
16767 }
16768
16769 template <typename Derived, typename Shape>
Rehash(Isolate * isolate,Derived * new_table)16770 void HashTable<Derived, Shape>::Rehash(Isolate* isolate, Derived* new_table) {
16771 DisallowHeapAllocation no_gc;
16772 WriteBarrierMode mode = new_table->GetWriteBarrierMode(no_gc);
16773
16774 DCHECK_LT(NumberOfElements(), new_table->Capacity());
16775
16776 // Copy prefix to new array.
16777 for (int i = kPrefixStartIndex; i < kElementsStartIndex; i++) {
16778 new_table->set(i, get(i), mode);
16779 }
16780
16781 // Rehash the elements.
16782 int capacity = this->Capacity();
16783 ReadOnlyRoots roots(isolate);
16784 for (int i = 0; i < capacity; i++) {
16785 uint32_t from_index = EntryToIndex(i);
16786 Object* k = this->get(from_index);
16787 if (!Shape::IsLive(roots, k)) continue;
16788 uint32_t hash = Shape::HashForObject(isolate, k);
16789 uint32_t insertion_index =
16790 EntryToIndex(new_table->FindInsertionEntry(hash));
16791 for (int j = 0; j < Shape::kEntrySize; j++) {
16792 new_table->set(insertion_index + j, get(from_index + j), mode);
16793 }
16794 }
16795 new_table->SetNumberOfElements(NumberOfElements());
16796 new_table->SetNumberOfDeletedElements(0);
16797 }
16798
16799 template <typename Derived, typename Shape>
EntryForProbe(Isolate * isolate,Object * k,int probe,uint32_t expected)16800 uint32_t HashTable<Derived, Shape>::EntryForProbe(Isolate* isolate, Object* k,
16801 int probe,
16802 uint32_t expected) {
16803 uint32_t hash = Shape::HashForObject(isolate, k);
16804 uint32_t capacity = this->Capacity();
16805 uint32_t entry = FirstProbe(hash, capacity);
16806 for (int i = 1; i < probe; i++) {
16807 if (entry == expected) return expected;
16808 entry = NextProbe(entry, i, capacity);
16809 }
16810 return entry;
16811 }
16812
16813 template <typename Derived, typename Shape>
Swap(uint32_t entry1,uint32_t entry2,WriteBarrierMode mode)16814 void HashTable<Derived, Shape>::Swap(uint32_t entry1, uint32_t entry2,
16815 WriteBarrierMode mode) {
16816 int index1 = EntryToIndex(entry1);
16817 int index2 = EntryToIndex(entry2);
16818 Object* temp[Shape::kEntrySize];
16819 for (int j = 0; j < Shape::kEntrySize; j++) {
16820 temp[j] = get(index1 + j);
16821 }
16822 for (int j = 0; j < Shape::kEntrySize; j++) {
16823 set(index1 + j, get(index2 + j), mode);
16824 }
16825 for (int j = 0; j < Shape::kEntrySize; j++) {
16826 set(index2 + j, temp[j], mode);
16827 }
16828 }
16829
16830 template <typename Derived, typename Shape>
Rehash(Isolate * isolate)16831 void HashTable<Derived, Shape>::Rehash(Isolate* isolate) {
16832 DisallowHeapAllocation no_gc;
16833 WriteBarrierMode mode = GetWriteBarrierMode(no_gc);
16834 ReadOnlyRoots roots(isolate);
16835 uint32_t capacity = Capacity();
16836 bool done = false;
16837 for (int probe = 1; !done; probe++) {
16838 // All elements at entries given by one of the first _probe_ probes
16839 // are placed correctly. Other elements might need to be moved.
16840 done = true;
16841 for (uint32_t current = 0; current < capacity; current++) {
16842 Object* current_key = KeyAt(current);
16843 if (!Shape::IsLive(roots, current_key)) continue;
16844 uint32_t target = EntryForProbe(isolate, current_key, probe, current);
16845 if (current == target) continue;
16846 Object* target_key = KeyAt(target);
16847 if (!Shape::IsLive(roots, target_key) ||
16848 EntryForProbe(isolate, target_key, probe, target) != target) {
16849 // Put the current element into the correct position.
16850 Swap(current, target, mode);
16851 // The other element will be processed on the next iteration.
16852 current--;
16853 } else {
16854 // The place for the current element is occupied. Leave the element
16855 // for the next probe.
16856 done = false;
16857 }
16858 }
16859 }
16860 // Wipe deleted entries.
16861 Object* the_hole = roots.the_hole_value();
16862 Object* undefined = roots.undefined_value();
16863 for (uint32_t current = 0; current < capacity; current++) {
16864 if (KeyAt(current) == the_hole) {
16865 set(EntryToIndex(current) + kEntryKeyIndex, undefined);
16866 }
16867 }
16868 SetNumberOfDeletedElements(0);
16869 }
16870
16871 template <typename Derived, typename Shape>
EnsureCapacity(Isolate * isolate,Handle<Derived> table,int n,PretenureFlag pretenure)16872 Handle<Derived> HashTable<Derived, Shape>::EnsureCapacity(
16873 Isolate* isolate, Handle<Derived> table, int n, PretenureFlag pretenure) {
16874 if (table->HasSufficientCapacityToAdd(n)) return table;
16875
16876 int capacity = table->Capacity();
16877 int new_nof = table->NumberOfElements() + n;
16878
16879 const int kMinCapacityForPretenure = 256;
16880 bool should_pretenure =
16881 pretenure == TENURED ||
16882 ((capacity > kMinCapacityForPretenure) && !Heap::InNewSpace(*table));
16883 Handle<Derived> new_table = HashTable::New(
16884 isolate, new_nof, should_pretenure ? TENURED : NOT_TENURED);
16885
16886 table->Rehash(isolate, *new_table);
16887 return new_table;
16888 }
16889
16890 template bool
16891 HashTable<NameDictionary, NameDictionaryShape>::HasSufficientCapacityToAdd(int);
16892
16893 template <typename Derived, typename Shape>
HasSufficientCapacityToAdd(int number_of_additional_elements)16894 bool HashTable<Derived, Shape>::HasSufficientCapacityToAdd(
16895 int number_of_additional_elements) {
16896 int capacity = Capacity();
16897 int nof = NumberOfElements() + number_of_additional_elements;
16898 int nod = NumberOfDeletedElements();
16899 // Return true if:
16900 // 50% is still free after adding number_of_additional_elements elements and
16901 // at most 50% of the free elements are deleted elements.
16902 if ((nof < capacity) && ((nod <= (capacity - nof) >> 1))) {
16903 int needed_free = nof >> 1;
16904 if (nof + needed_free <= capacity) return true;
16905 }
16906 return false;
16907 }
16908
16909 template <typename Derived, typename Shape>
Shrink(Isolate * isolate,Handle<Derived> table,int additionalCapacity)16910 Handle<Derived> HashTable<Derived, Shape>::Shrink(Isolate* isolate,
16911 Handle<Derived> table,
16912 int additionalCapacity) {
16913 int capacity = table->Capacity();
16914 int nof = table->NumberOfElements();
16915
16916 // Shrink to fit the number of elements if only a quarter of the
16917 // capacity is filled with elements.
16918 if (nof > (capacity >> 2)) return table;
16919 // Allocate a new dictionary with room for at least the current number of
16920 // elements + {additionalCapacity}. The allocation method will make sure that
16921 // there is extra room in the dictionary for additions. Don't go lower than
16922 // room for {kMinShrinkCapacity} elements.
16923 int at_least_room_for = nof + additionalCapacity;
16924 int new_capacity = ComputeCapacity(at_least_room_for);
16925 if (new_capacity < Derived::kMinShrinkCapacity) return table;
16926 if (new_capacity == capacity) return table;
16927
16928 const int kMinCapacityForPretenure = 256;
16929 bool pretenure = (at_least_room_for > kMinCapacityForPretenure) &&
16930 !Heap::InNewSpace(*table);
16931 Handle<Derived> new_table =
16932 HashTable::New(isolate, new_capacity, pretenure ? TENURED : NOT_TENURED,
16933 USE_CUSTOM_MINIMUM_CAPACITY);
16934
16935 table->Rehash(isolate, *new_table);
16936 return new_table;
16937 }
16938
16939 template <typename Derived, typename Shape>
FindInsertionEntry(uint32_t hash)16940 uint32_t HashTable<Derived, Shape>::FindInsertionEntry(uint32_t hash) {
16941 uint32_t capacity = Capacity();
16942 uint32_t entry = FirstProbe(hash, capacity);
16943 uint32_t count = 1;
16944 // EnsureCapacity will guarantee the hash table is never full.
16945 ReadOnlyRoots roots = GetReadOnlyRoots();
16946 while (true) {
16947 if (!Shape::IsLive(roots, KeyAt(entry))) break;
16948 entry = NextProbe(entry, count++, capacity);
16949 }
16950 return entry;
16951 }
16952
InvalidatePropertyCell(Handle<JSGlobalObject> global,Handle<Name> name)16953 void JSGlobalObject::InvalidatePropertyCell(Handle<JSGlobalObject> global,
16954 Handle<Name> name) {
16955 // Regardless of whether the property is there or not invalidate
16956 // Load/StoreGlobalICs that load/store through global object's prototype.
16957 JSObject::InvalidatePrototypeValidityCell(*global);
16958
16959 DCHECK(!global->HasFastProperties());
16960 auto dictionary = handle(global->global_dictionary(), global->GetIsolate());
16961 int entry = dictionary->FindEntry(global->GetIsolate(), name);
16962 if (entry == GlobalDictionary::kNotFound) return;
16963 PropertyCell::InvalidateEntry(global->GetIsolate(), dictionary, entry);
16964 }
16965
EnsureEmptyPropertyCell(Handle<JSGlobalObject> global,Handle<Name> name,PropertyCellType cell_type,int * entry_out)16966 Handle<PropertyCell> JSGlobalObject::EnsureEmptyPropertyCell(
16967 Handle<JSGlobalObject> global, Handle<Name> name,
16968 PropertyCellType cell_type, int* entry_out) {
16969 Isolate* isolate = global->GetIsolate();
16970 DCHECK(!global->HasFastProperties());
16971 Handle<GlobalDictionary> dictionary(global->global_dictionary(), isolate);
16972 int entry = dictionary->FindEntry(isolate, name);
16973 Handle<PropertyCell> cell;
16974 if (entry != GlobalDictionary::kNotFound) {
16975 if (entry_out) *entry_out = entry;
16976 cell = handle(dictionary->CellAt(entry), isolate);
16977 PropertyCellType original_cell_type = cell->property_details().cell_type();
16978 DCHECK(original_cell_type == PropertyCellType::kInvalidated ||
16979 original_cell_type == PropertyCellType::kUninitialized);
16980 DCHECK(cell->value()->IsTheHole(isolate));
16981 if (original_cell_type == PropertyCellType::kInvalidated) {
16982 cell = PropertyCell::InvalidateEntry(isolate, dictionary, entry);
16983 }
16984 PropertyDetails details(kData, NONE, cell_type);
16985 cell->set_property_details(details);
16986 return cell;
16987 }
16988 cell = isolate->factory()->NewPropertyCell(name);
16989 PropertyDetails details(kData, NONE, cell_type);
16990 dictionary = GlobalDictionary::Add(isolate, dictionary, name, cell, details,
16991 entry_out);
16992 // {*entry_out} is initialized inside GlobalDictionary::Add().
16993 global->SetProperties(*dictionary);
16994 return cell;
16995 }
16996
16997
16998 // This class is used for looking up two character strings in the string table.
16999 // If we don't have a hit we don't want to waste much time so we unroll the
17000 // string hash calculation loop here for speed. Doesn't work if the two
17001 // characters form a decimal integer, since such strings have a different hash
17002 // algorithm.
17003 class TwoCharHashTableKey : public StringTableKey {
17004 public:
TwoCharHashTableKey(uint16_t c1,uint16_t c2,uint64_t seed)17005 TwoCharHashTableKey(uint16_t c1, uint16_t c2, uint64_t seed)
17006 : StringTableKey(ComputeHashField(c1, c2, seed)), c1_(c1), c2_(c2) {}
17007
IsMatch(Object * o)17008 bool IsMatch(Object* o) override {
17009 String* other = String::cast(o);
17010 if (other->length() != 2) return false;
17011 if (other->Get(0) != c1_) return false;
17012 return other->Get(1) == c2_;
17013 }
17014
AsHandle(Isolate * isolate)17015 Handle<String> AsHandle(Isolate* isolate) override {
17016 // The TwoCharHashTableKey is only used for looking in the string
17017 // table, not for adding to it.
17018 UNREACHABLE();
17019 }
17020
17021 private:
ComputeHashField(uint16_t c1,uint16_t c2,uint64_t seed)17022 uint32_t ComputeHashField(uint16_t c1, uint16_t c2, uint64_t seed) {
17023 // Char 1.
17024 uint32_t hash = static_cast<uint32_t>(seed);
17025 hash += c1;
17026 hash += hash << 10;
17027 hash ^= hash >> 6;
17028 // Char 2.
17029 hash += c2;
17030 hash += hash << 10;
17031 hash ^= hash >> 6;
17032 // GetHash.
17033 hash += hash << 3;
17034 hash ^= hash >> 11;
17035 hash += hash << 15;
17036 if ((hash & String::kHashBitMask) == 0) hash = StringHasher::kZeroHash;
17037 hash = (hash << String::kHashShift) | String::kIsNotArrayIndexMask;
17038 #ifdef DEBUG
17039 // If this assert fails then we failed to reproduce the two-character
17040 // version of the string hashing algorithm above. One reason could be
17041 // that we were passed two digits as characters, since the hash
17042 // algorithm is different in that case.
17043 uint16_t chars[2] = {c1, c2};
17044 uint32_t check_hash = StringHasher::HashSequentialString(chars, 2, seed);
17045 DCHECK_EQ(hash, check_hash);
17046 #endif
17047 return hash;
17048 }
17049
17050 uint16_t c1_;
17051 uint16_t c2_;
17052 };
17053
LookupTwoCharsStringIfExists(Isolate * isolate,uint16_t c1,uint16_t c2)17054 MaybeHandle<String> StringTable::LookupTwoCharsStringIfExists(
17055 Isolate* isolate,
17056 uint16_t c1,
17057 uint16_t c2) {
17058 TwoCharHashTableKey key(c1, c2, isolate->heap()->HashSeed());
17059 Handle<StringTable> string_table = isolate->factory()->string_table();
17060 int entry = string_table->FindEntry(isolate, &key);
17061 if (entry == kNotFound) return MaybeHandle<String>();
17062
17063 Handle<String> result(String::cast(string_table->KeyAt(entry)), isolate);
17064 DCHECK(StringShape(*result).IsInternalized());
17065 DCHECK_EQ(result->Hash(), key.Hash());
17066 return result;
17067 }
17068
EnsureCapacityForDeserialization(Isolate * isolate,int expected)17069 void StringTable::EnsureCapacityForDeserialization(Isolate* isolate,
17070 int expected) {
17071 Handle<StringTable> table = isolate->factory()->string_table();
17072 // We need a key instance for the virtual hash function.
17073 table = StringTable::EnsureCapacity(isolate, table, expected);
17074 isolate->heap()->SetRootStringTable(*table);
17075 }
17076
17077 namespace {
17078
17079 template <class StringClass>
MigrateExternalStringResource(Isolate * isolate,String * from,String * to)17080 void MigrateExternalStringResource(Isolate* isolate, String* from, String* to) {
17081 StringClass* cast_from = StringClass::cast(from);
17082 StringClass* cast_to = StringClass::cast(to);
17083 const typename StringClass::Resource* to_resource = cast_to->resource();
17084 if (to_resource == nullptr) {
17085 // |to| is a just-created internalized copy of |from|. Migrate the resource.
17086 cast_to->SetResource(isolate, cast_from->resource());
17087 // Zap |from|'s resource pointer to reflect the fact that |from| has
17088 // relinquished ownership of its resource.
17089 isolate->heap()->UpdateExternalString(
17090 from, ExternalString::cast(from)->ExternalPayloadSize(), 0);
17091 cast_from->SetResource(isolate, nullptr);
17092 } else if (to_resource != cast_from->resource()) {
17093 // |to| already existed and has its own resource. Finalize |from|.
17094 isolate->heap()->FinalizeExternalString(from);
17095 }
17096 }
17097
MakeStringThin(String * string,String * internalized,Isolate * isolate)17098 void MakeStringThin(String* string, String* internalized, Isolate* isolate) {
17099 DCHECK_NE(string, internalized);
17100 DCHECK(internalized->IsInternalizedString());
17101
17102 if (string->IsExternalString()) {
17103 if (internalized->IsExternalOneByteString()) {
17104 MigrateExternalStringResource<ExternalOneByteString>(isolate, string,
17105 internalized);
17106 } else if (internalized->IsExternalTwoByteString()) {
17107 MigrateExternalStringResource<ExternalTwoByteString>(isolate, string,
17108 internalized);
17109 } else {
17110 // If the external string is duped into an existing non-external
17111 // internalized string, free its resource (it's about to be rewritten
17112 // into a ThinString below).
17113 isolate->heap()->FinalizeExternalString(string);
17114 }
17115 }
17116
17117 DisallowHeapAllocation no_gc;
17118 int old_size = string->Size();
17119 isolate->heap()->NotifyObjectLayoutChange(string, old_size, no_gc);
17120 bool one_byte = internalized->IsOneByteRepresentation();
17121 Handle<Map> map = one_byte ? isolate->factory()->thin_one_byte_string_map()
17122 : isolate->factory()->thin_string_map();
17123 DCHECK_GE(old_size, ThinString::kSize);
17124 string->synchronized_set_map(*map);
17125 ThinString* thin = ThinString::cast(string);
17126 thin->set_actual(internalized);
17127 Address thin_end = thin->address() + ThinString::kSize;
17128 int size_delta = old_size - ThinString::kSize;
17129 if (size_delta != 0) {
17130 Heap* heap = isolate->heap();
17131 heap->CreateFillerObjectAt(thin_end, size_delta, ClearRecordedSlots::kNo);
17132 }
17133 }
17134
17135 } // namespace
17136
17137 // static
LookupString(Isolate * isolate,Handle<String> string)17138 Handle<String> StringTable::LookupString(Isolate* isolate,
17139 Handle<String> string) {
17140 string = String::Flatten(isolate, string);
17141 if (string->IsInternalizedString()) return string;
17142
17143 InternalizedStringKey key(string);
17144 Handle<String> result = LookupKey(isolate, &key);
17145
17146 if (FLAG_thin_strings) {
17147 if (!string->IsInternalizedString()) {
17148 MakeStringThin(*string, *result, isolate);
17149 }
17150 } else { // !FLAG_thin_strings
17151 if (string->IsConsString()) {
17152 Handle<ConsString> cons = Handle<ConsString>::cast(string);
17153 cons->set_first(isolate, *result);
17154 cons->set_second(isolate, ReadOnlyRoots(isolate).empty_string());
17155 } else if (string->IsSlicedString()) {
17156 STATIC_ASSERT(ConsString::kSize == SlicedString::kSize);
17157 DisallowHeapAllocation no_gc;
17158 bool one_byte = result->IsOneByteRepresentation();
17159 Handle<Map> map = one_byte
17160 ? isolate->factory()->cons_one_byte_string_map()
17161 : isolate->factory()->cons_string_map();
17162 string->set_map(*map);
17163 Handle<ConsString> cons = Handle<ConsString>::cast(string);
17164 cons->set_first(isolate, *result);
17165 cons->set_second(isolate, ReadOnlyRoots(isolate).empty_string());
17166 }
17167 }
17168 return result;
17169 }
17170
17171 // static
LookupKey(Isolate * isolate,StringTableKey * key)17172 Handle<String> StringTable::LookupKey(Isolate* isolate, StringTableKey* key) {
17173 Handle<StringTable> table = isolate->factory()->string_table();
17174 int entry = table->FindEntry(isolate, key);
17175
17176 // String already in table.
17177 if (entry != kNotFound) {
17178 return handle(String::cast(table->KeyAt(entry)), isolate);
17179 }
17180
17181 table = StringTable::CautiousShrink(isolate, table);
17182 // Adding new string. Grow table if needed.
17183 table = StringTable::EnsureCapacity(isolate, table, 1);
17184 isolate->heap()->SetRootStringTable(*table);
17185
17186 return AddKeyNoResize(isolate, key);
17187 }
17188
AddKeyNoResize(Isolate * isolate,StringTableKey * key)17189 Handle<String> StringTable::AddKeyNoResize(Isolate* isolate,
17190 StringTableKey* key) {
17191 Handle<StringTable> table = isolate->factory()->string_table();
17192 DCHECK(table->HasSufficientCapacityToAdd(1));
17193 // Create string object.
17194 Handle<String> string = key->AsHandle(isolate);
17195 // There must be no attempts to internalize strings that could throw
17196 // InvalidStringLength error.
17197 CHECK(!string.is_null());
17198 DCHECK(string->HasHashCode());
17199 DCHECK_EQ(table->FindEntry(isolate, key), kNotFound);
17200
17201 // Add the new string and return it along with the string table.
17202 int entry = table->FindInsertionEntry(key->Hash());
17203 table->set(EntryToIndex(entry), *string);
17204 table->ElementAdded();
17205
17206 return Handle<String>::cast(string);
17207 }
17208
CautiousShrink(Isolate * isolate,Handle<StringTable> table)17209 Handle<StringTable> StringTable::CautiousShrink(Isolate* isolate,
17210 Handle<StringTable> table) {
17211 // Only shrink if the table is very empty to avoid performance penalty.
17212 int capacity = table->Capacity();
17213 int nof = table->NumberOfElements();
17214 if (capacity <= StringTable::kMinCapacity) return table;
17215 if (nof > (capacity / kMaxEmptyFactor)) return table;
17216 // Keep capacity for at least half of the current nof elements.
17217 int slack_capacity = nof >> 2;
17218 return Shrink(isolate, table, slack_capacity);
17219 }
17220
17221 namespace {
17222
17223 class StringTableNoAllocateKey : public StringTableKey {
17224 public:
StringTableNoAllocateKey(String * string,uint64_t seed)17225 StringTableNoAllocateKey(String* string, uint64_t seed)
17226 : StringTableKey(0), string_(string) {
17227 StringShape shape(string);
17228 one_byte_ = shape.HasOnlyOneByteChars();
17229 DCHECK(!shape.IsInternalized());
17230 DCHECK(!shape.IsThin());
17231 int length = string->length();
17232 if (shape.IsCons() && length <= String::kMaxHashCalcLength) {
17233 special_flattening_ = true;
17234 uint32_t hash_field = 0;
17235 if (one_byte_) {
17236 if (V8_LIKELY(length <=
17237 static_cast<int>(arraysize(one_byte_buffer_)))) {
17238 one_byte_content_ = one_byte_buffer_;
17239 } else {
17240 one_byte_content_ = new uint8_t[length];
17241 }
17242 String::WriteToFlat(string, one_byte_content_, 0, length);
17243 hash_field =
17244 StringHasher::HashSequentialString(one_byte_content_, length, seed);
17245 } else {
17246 if (V8_LIKELY(length <=
17247 static_cast<int>(arraysize(two_byte_buffer_)))) {
17248 two_byte_content_ = two_byte_buffer_;
17249 } else {
17250 two_byte_content_ = new uint16_t[length];
17251 }
17252 String::WriteToFlat(string, two_byte_content_, 0, length);
17253 hash_field =
17254 StringHasher::HashSequentialString(two_byte_content_, length, seed);
17255 }
17256 string->set_hash_field(hash_field);
17257 } else {
17258 special_flattening_ = false;
17259 one_byte_content_ = nullptr;
17260 string->Hash();
17261 }
17262
17263 DCHECK(string->HasHashCode());
17264 set_hash_field(string->hash_field());
17265 }
17266
~StringTableNoAllocateKey()17267 ~StringTableNoAllocateKey() {
17268 if (one_byte_) {
17269 if (one_byte_content_ != one_byte_buffer_) delete[] one_byte_content_;
17270 } else {
17271 if (two_byte_content_ != two_byte_buffer_) delete[] two_byte_content_;
17272 }
17273 }
17274
IsMatch(Object * otherstring)17275 bool IsMatch(Object* otherstring) override {
17276 String* other = String::cast(otherstring);
17277 DCHECK(other->IsInternalizedString());
17278 DCHECK(other->IsFlat());
17279 if (Hash() != other->Hash()) return false;
17280 int len = string_->length();
17281 if (len != other->length()) return false;
17282
17283 if (!special_flattening_) {
17284 if (string_->Get(0) != other->Get(0)) return false;
17285 if (string_->IsFlat()) {
17286 StringShape shape1(string_);
17287 StringShape shape2(other);
17288 if (shape1.encoding_tag() == kOneByteStringTag &&
17289 shape2.encoding_tag() == kOneByteStringTag) {
17290 String::FlatContent flat1 = string_->GetFlatContent();
17291 String::FlatContent flat2 = other->GetFlatContent();
17292 return CompareRawStringContents(flat1.ToOneByteVector().start(),
17293 flat2.ToOneByteVector().start(), len);
17294 }
17295 if (shape1.encoding_tag() == kTwoByteStringTag &&
17296 shape2.encoding_tag() == kTwoByteStringTag) {
17297 String::FlatContent flat1 = string_->GetFlatContent();
17298 String::FlatContent flat2 = other->GetFlatContent();
17299 return CompareRawStringContents(flat1.ToUC16Vector().start(),
17300 flat2.ToUC16Vector().start(), len);
17301 }
17302 }
17303 StringComparator comparator;
17304 return comparator.Equals(string_, other);
17305 }
17306
17307 String::FlatContent flat_content = other->GetFlatContent();
17308 if (one_byte_) {
17309 if (flat_content.IsOneByte()) {
17310 return CompareRawStringContents(
17311 one_byte_content_, flat_content.ToOneByteVector().start(), len);
17312 } else {
17313 DCHECK(flat_content.IsTwoByte());
17314 for (int i = 0; i < len; i++) {
17315 if (flat_content.Get(i) != one_byte_content_[i]) return false;
17316 }
17317 return true;
17318 }
17319 } else {
17320 if (flat_content.IsTwoByte()) {
17321 return CompareRawStringContents(
17322 two_byte_content_, flat_content.ToUC16Vector().start(), len);
17323 } else {
17324 DCHECK(flat_content.IsOneByte());
17325 for (int i = 0; i < len; i++) {
17326 if (flat_content.Get(i) != two_byte_content_[i]) return false;
17327 }
17328 return true;
17329 }
17330 }
17331 }
17332
AsHandle(Isolate * isolate)17333 V8_WARN_UNUSED_RESULT Handle<String> AsHandle(Isolate* isolate) override {
17334 UNREACHABLE();
17335 }
17336
17337 private:
17338 String* string_;
17339 bool one_byte_;
17340 bool special_flattening_;
17341 union {
17342 uint8_t* one_byte_content_;
17343 uint16_t* two_byte_content_;
17344 };
17345 union {
17346 uint8_t one_byte_buffer_[256];
17347 uint16_t two_byte_buffer_[128];
17348 };
17349 };
17350
17351 } // namespace
17352
17353 // static
LookupStringIfExists_NoAllocate(Isolate * isolate,String * string)17354 Object* StringTable::LookupStringIfExists_NoAllocate(Isolate* isolate,
17355 String* string) {
17356 DisallowHeapAllocation no_gc;
17357 Heap* heap = isolate->heap();
17358 StringTable* table = heap->string_table();
17359
17360 StringTableNoAllocateKey key(string, heap->HashSeed());
17361
17362 // String could be an array index.
17363 uint32_t hash = string->hash_field();
17364
17365 // Valid array indices are >= 0, so they cannot be mixed up with any of
17366 // the result sentinels, which are negative.
17367 STATIC_ASSERT(
17368 !String::ArrayIndexValueBits::is_valid(ResultSentinel::kUnsupported));
17369 STATIC_ASSERT(
17370 !String::ArrayIndexValueBits::is_valid(ResultSentinel::kNotFound));
17371
17372 if (Name::ContainsCachedArrayIndex(hash)) {
17373 return Smi::FromInt(String::ArrayIndexValueBits::decode(hash));
17374 }
17375 if ((hash & Name::kIsNotArrayIndexMask) == 0) {
17376 // It is an indexed, but it's not cached.
17377 return Smi::FromInt(ResultSentinel::kUnsupported);
17378 }
17379
17380 DCHECK(!string->IsInternalizedString());
17381 int entry = table->FindEntry(ReadOnlyRoots(isolate), &key, key.Hash());
17382 if (entry != kNotFound) {
17383 String* internalized = String::cast(table->KeyAt(entry));
17384 if (FLAG_thin_strings) {
17385 MakeStringThin(string, internalized, isolate);
17386 }
17387 return internalized;
17388 }
17389 // A string that's not an array index, and not in the string table,
17390 // cannot have been used as a property name before.
17391 return Smi::FromInt(ResultSentinel::kNotFound);
17392 }
17393
ForwardStringIfExists(Isolate * isolate,StringTableKey * key,String * string)17394 String* StringTable::ForwardStringIfExists(Isolate* isolate,
17395 StringTableKey* key,
17396 String* string) {
17397 Handle<StringTable> table = isolate->factory()->string_table();
17398 int entry = table->FindEntry(isolate, key);
17399 if (entry == kNotFound) return nullptr;
17400
17401 String* canonical = String::cast(table->KeyAt(entry));
17402 if (canonical != string) MakeStringThin(string, canonical, isolate);
17403 return canonical;
17404 }
17405
New(Isolate * isolate)17406 Handle<StringSet> StringSet::New(Isolate* isolate) {
17407 return HashTable::New(isolate, 0);
17408 }
17409
Add(Isolate * isolate,Handle<StringSet> stringset,Handle<String> name)17410 Handle<StringSet> StringSet::Add(Isolate* isolate, Handle<StringSet> stringset,
17411 Handle<String> name) {
17412 if (!stringset->Has(isolate, name)) {
17413 stringset = EnsureCapacity(isolate, stringset, 1);
17414 uint32_t hash = ShapeT::Hash(isolate, *name);
17415 int entry = stringset->FindInsertionEntry(hash);
17416 stringset->set(EntryToIndex(entry), *name);
17417 stringset->ElementAdded();
17418 }
17419 return stringset;
17420 }
17421
Has(Isolate * isolate,Handle<String> name)17422 bool StringSet::Has(Isolate* isolate, Handle<String> name) {
17423 return FindEntry(isolate, *name) != kNotFound;
17424 }
17425
Add(Isolate * isolate,Handle<ObjectHashSet> set,Handle<Object> key)17426 Handle<ObjectHashSet> ObjectHashSet::Add(Isolate* isolate,
17427 Handle<ObjectHashSet> set,
17428 Handle<Object> key) {
17429 int32_t hash = key->GetOrCreateHash(isolate)->value();
17430 if (!set->Has(isolate, key, hash)) {
17431 set = EnsureCapacity(isolate, set, 1);
17432 int entry = set->FindInsertionEntry(hash);
17433 set->set(EntryToIndex(entry), *key);
17434 set->ElementAdded();
17435 }
17436 return set;
17437 }
17438
Lookup(Handle<String> src,Handle<SharedFunctionInfo> shared,LanguageMode language_mode)17439 Handle<Object> CompilationCacheTable::Lookup(Handle<String> src,
17440 Handle<SharedFunctionInfo> shared,
17441 LanguageMode language_mode) {
17442 Isolate* isolate = GetIsolate();
17443 StringSharedKey key(src, shared, language_mode, kNoSourcePosition);
17444 int entry = FindEntry(isolate, &key);
17445 if (entry == kNotFound) return isolate->factory()->undefined_value();
17446 int index = EntryToIndex(entry);
17447 if (!get(index)->IsFixedArray()) return isolate->factory()->undefined_value();
17448 return Handle<Object>(get(index + 1), isolate);
17449 }
17450
17451 namespace {
17452
17453 const int kLiteralEntryLength = 2;
17454 const int kLiteralInitialLength = 2;
17455 const int kLiteralContextOffset = 0;
17456 const int kLiteralLiteralsOffset = 1;
17457
SearchLiteralsMapEntry(CompilationCacheTable * cache,int cache_entry,Context * native_context)17458 int SearchLiteralsMapEntry(CompilationCacheTable* cache, int cache_entry,
17459 Context* native_context) {
17460 DisallowHeapAllocation no_gc;
17461 DCHECK(native_context->IsNativeContext());
17462 Object* obj = cache->get(cache_entry);
17463
17464 // Check that there's no confusion between FixedArray and WeakFixedArray (the
17465 // object used to be a FixedArray here).
17466 DCHECK(!obj->IsFixedArray());
17467 if (obj->IsWeakFixedArray()) {
17468 WeakFixedArray* literals_map = WeakFixedArray::cast(obj);
17469 int length = literals_map->length();
17470 for (int i = 0; i < length; i += kLiteralEntryLength) {
17471 DCHECK(literals_map->Get(i + kLiteralContextOffset)
17472 ->IsWeakOrClearedHeapObject());
17473 if (literals_map->Get(i + kLiteralContextOffset) ==
17474 HeapObjectReference::Weak(native_context)) {
17475 return i;
17476 }
17477 }
17478 }
17479 return -1;
17480 }
17481
AddToFeedbackCellsMap(Handle<CompilationCacheTable> cache,int cache_entry,Handle<Context> native_context,Handle<FeedbackCell> feedback_cell)17482 void AddToFeedbackCellsMap(Handle<CompilationCacheTable> cache, int cache_entry,
17483 Handle<Context> native_context,
17484 Handle<FeedbackCell> feedback_cell) {
17485 Isolate* isolate = native_context->GetIsolate();
17486 DCHECK(native_context->IsNativeContext());
17487 STATIC_ASSERT(kLiteralEntryLength == 2);
17488 Handle<WeakFixedArray> new_literals_map;
17489 int entry;
17490
17491 Object* obj = cache->get(cache_entry);
17492
17493 // Check that there's no confusion between FixedArray and WeakFixedArray (the
17494 // object used to be a FixedArray here).
17495 DCHECK(!obj->IsFixedArray());
17496 if (!obj->IsWeakFixedArray() || WeakFixedArray::cast(obj)->length() == 0) {
17497 new_literals_map =
17498 isolate->factory()->NewWeakFixedArray(kLiteralInitialLength, TENURED);
17499 entry = 0;
17500 } else {
17501 Handle<WeakFixedArray> old_literals_map(WeakFixedArray::cast(obj), isolate);
17502 entry = SearchLiteralsMapEntry(*cache, cache_entry, *native_context);
17503 if (entry >= 0) {
17504 // Just set the code of the entry.
17505 old_literals_map->Set(entry + kLiteralLiteralsOffset,
17506 HeapObjectReference::Weak(*feedback_cell));
17507 return;
17508 }
17509
17510 // Can we reuse an entry?
17511 DCHECK_LT(entry, 0);
17512 int length = old_literals_map->length();
17513 for (int i = 0; i < length; i += kLiteralEntryLength) {
17514 if (old_literals_map->Get(i + kLiteralContextOffset)
17515 ->IsClearedWeakHeapObject()) {
17516 new_literals_map = old_literals_map;
17517 entry = i;
17518 break;
17519 }
17520 }
17521
17522 if (entry < 0) {
17523 // Copy old optimized code map and append one new entry.
17524 new_literals_map = isolate->factory()->CopyWeakFixedArrayAndGrow(
17525 old_literals_map, kLiteralEntryLength, TENURED);
17526 entry = old_literals_map->length();
17527 }
17528 }
17529
17530 new_literals_map->Set(entry + kLiteralContextOffset,
17531 HeapObjectReference::Weak(*native_context));
17532 new_literals_map->Set(entry + kLiteralLiteralsOffset,
17533 HeapObjectReference::Weak(*feedback_cell));
17534
17535 #ifdef DEBUG
17536 for (int i = 0; i < new_literals_map->length(); i += kLiteralEntryLength) {
17537 MaybeObject* object = new_literals_map->Get(i + kLiteralContextOffset);
17538 DCHECK(object->IsClearedWeakHeapObject() ||
17539 object->ToWeakHeapObject()->IsNativeContext());
17540 object = new_literals_map->Get(i + kLiteralLiteralsOffset);
17541 DCHECK(object->IsClearedWeakHeapObject() ||
17542 object->ToWeakHeapObject()->IsFeedbackCell());
17543 }
17544 #endif
17545
17546 Object* old_literals_map = cache->get(cache_entry);
17547 if (old_literals_map != *new_literals_map) {
17548 cache->set(cache_entry, *new_literals_map);
17549 }
17550 }
17551
SearchLiteralsMap(CompilationCacheTable * cache,int cache_entry,Context * native_context)17552 FeedbackCell* SearchLiteralsMap(CompilationCacheTable* cache, int cache_entry,
17553 Context* native_context) {
17554 FeedbackCell* result = nullptr;
17555 int entry = SearchLiteralsMapEntry(cache, cache_entry, native_context);
17556 if (entry >= 0) {
17557 WeakFixedArray* literals_map =
17558 WeakFixedArray::cast(cache->get(cache_entry));
17559 DCHECK_LE(entry + kLiteralEntryLength, literals_map->length());
17560 MaybeObject* object = literals_map->Get(entry + kLiteralLiteralsOffset);
17561
17562 result = object->IsClearedWeakHeapObject()
17563 ? nullptr
17564 : FeedbackCell::cast(object->ToWeakHeapObject());
17565 }
17566 DCHECK(result == nullptr || result->IsFeedbackCell());
17567 return result;
17568 }
17569
17570 } // namespace
17571
LookupScript(Handle<String> src,Handle<Context> native_context,LanguageMode language_mode)17572 MaybeHandle<SharedFunctionInfo> CompilationCacheTable::LookupScript(
17573 Handle<String> src, Handle<Context> native_context,
17574 LanguageMode language_mode) {
17575 // We use the empty function SFI as part of the key. Although the
17576 // empty_function is native context dependent, the SFI is de-duped on
17577 // snapshot builds by the PartialSnapshotCache, and so this does not prevent
17578 // reuse of scripts in the compilation cache across native contexts.
17579 Handle<SharedFunctionInfo> shared(native_context->empty_function()->shared(),
17580 native_context->GetIsolate());
17581 StringSharedKey key(src, shared, language_mode, kNoSourcePosition);
17582 int entry = FindEntry(GetIsolate(), &key);
17583 if (entry == kNotFound) return MaybeHandle<SharedFunctionInfo>();
17584 int index = EntryToIndex(entry);
17585 if (!get(index)->IsFixedArray()) return MaybeHandle<SharedFunctionInfo>();
17586 Object* obj = get(index + 1);
17587 if (obj->IsSharedFunctionInfo()) {
17588 return handle(SharedFunctionInfo::cast(obj), native_context->GetIsolate());
17589 }
17590 return MaybeHandle<SharedFunctionInfo>();
17591 }
17592
LookupEval(Handle<String> src,Handle<SharedFunctionInfo> outer_info,Handle<Context> native_context,LanguageMode language_mode,int position)17593 InfoCellPair CompilationCacheTable::LookupEval(
17594 Handle<String> src, Handle<SharedFunctionInfo> outer_info,
17595 Handle<Context> native_context, LanguageMode language_mode, int position) {
17596 InfoCellPair empty_result;
17597 StringSharedKey key(src, outer_info, language_mode, position);
17598 int entry = FindEntry(GetIsolate(), &key);
17599 if (entry == kNotFound) return empty_result;
17600 int index = EntryToIndex(entry);
17601 if (!get(index)->IsFixedArray()) return empty_result;
17602 Object* obj = get(EntryToIndex(entry) + 1);
17603 if (obj->IsSharedFunctionInfo()) {
17604 FeedbackCell* feedback_cell =
17605 SearchLiteralsMap(this, EntryToIndex(entry) + 2, *native_context);
17606 return InfoCellPair(SharedFunctionInfo::cast(obj), feedback_cell);
17607 }
17608 return empty_result;
17609 }
17610
LookupRegExp(Handle<String> src,JSRegExp::Flags flags)17611 Handle<Object> CompilationCacheTable::LookupRegExp(Handle<String> src,
17612 JSRegExp::Flags flags) {
17613 Isolate* isolate = GetIsolate();
17614 DisallowHeapAllocation no_allocation;
17615 RegExpKey key(src, flags);
17616 int entry = FindEntry(isolate, &key);
17617 if (entry == kNotFound) return isolate->factory()->undefined_value();
17618 return Handle<Object>(get(EntryToIndex(entry) + 1), isolate);
17619 }
17620
Put(Handle<CompilationCacheTable> cache,Handle<String> src,Handle<SharedFunctionInfo> shared,LanguageMode language_mode,Handle<Object> value)17621 Handle<CompilationCacheTable> CompilationCacheTable::Put(
17622 Handle<CompilationCacheTable> cache, Handle<String> src,
17623 Handle<SharedFunctionInfo> shared, LanguageMode language_mode,
17624 Handle<Object> value) {
17625 Isolate* isolate = cache->GetIsolate();
17626 StringSharedKey key(src, shared, language_mode, kNoSourcePosition);
17627 Handle<Object> k = key.AsHandle(isolate);
17628 cache = EnsureCapacity(isolate, cache, 1);
17629 int entry = cache->FindInsertionEntry(key.Hash());
17630 cache->set(EntryToIndex(entry), *k);
17631 cache->set(EntryToIndex(entry) + 1, *value);
17632 cache->ElementAdded();
17633 return cache;
17634 }
17635
PutScript(Handle<CompilationCacheTable> cache,Handle<String> src,Handle<Context> native_context,LanguageMode language_mode,Handle<SharedFunctionInfo> value)17636 Handle<CompilationCacheTable> CompilationCacheTable::PutScript(
17637 Handle<CompilationCacheTable> cache, Handle<String> src,
17638 Handle<Context> native_context, LanguageMode language_mode,
17639 Handle<SharedFunctionInfo> value) {
17640 Isolate* isolate = native_context->GetIsolate();
17641 // We use the empty function SFI as part of the key. Although the
17642 // empty_function is native context dependent, the SFI is de-duped on
17643 // snapshot builds by the PartialSnapshotCache, and so this does not prevent
17644 // reuse of scripts in the compilation cache across native contexts.
17645 Handle<SharedFunctionInfo> shared(native_context->empty_function()->shared(),
17646 isolate);
17647 StringSharedKey key(src, shared, language_mode, kNoSourcePosition);
17648 Handle<Object> k = key.AsHandle(isolate);
17649 cache = EnsureCapacity(isolate, cache, 1);
17650 int entry = cache->FindInsertionEntry(key.Hash());
17651 cache->set(EntryToIndex(entry), *k);
17652 cache->set(EntryToIndex(entry) + 1, *value);
17653 cache->ElementAdded();
17654 return cache;
17655 }
17656
PutEval(Handle<CompilationCacheTable> cache,Handle<String> src,Handle<SharedFunctionInfo> outer_info,Handle<SharedFunctionInfo> value,Handle<Context> native_context,Handle<FeedbackCell> feedback_cell,int position)17657 Handle<CompilationCacheTable> CompilationCacheTable::PutEval(
17658 Handle<CompilationCacheTable> cache, Handle<String> src,
17659 Handle<SharedFunctionInfo> outer_info, Handle<SharedFunctionInfo> value,
17660 Handle<Context> native_context, Handle<FeedbackCell> feedback_cell,
17661 int position) {
17662 Isolate* isolate = native_context->GetIsolate();
17663 StringSharedKey key(src, outer_info, value->language_mode(), position);
17664 {
17665 Handle<Object> k = key.AsHandle(isolate);
17666 int entry = cache->FindEntry(isolate, &key);
17667 if (entry != kNotFound) {
17668 cache->set(EntryToIndex(entry), *k);
17669 cache->set(EntryToIndex(entry) + 1, *value);
17670 // AddToFeedbackCellsMap may allocate a new sub-array to live in the
17671 // entry, but it won't change the cache array. Therefore EntryToIndex
17672 // and entry remains correct.
17673 AddToFeedbackCellsMap(cache, EntryToIndex(entry) + 2, native_context,
17674 feedback_cell);
17675 return cache;
17676 }
17677 }
17678
17679 cache = EnsureCapacity(isolate, cache, 1);
17680 int entry = cache->FindInsertionEntry(key.Hash());
17681 Handle<Object> k =
17682 isolate->factory()->NewNumber(static_cast<double>(key.Hash()));
17683 cache->set(EntryToIndex(entry), *k);
17684 cache->set(EntryToIndex(entry) + 1, Smi::FromInt(kHashGenerations));
17685 cache->ElementAdded();
17686 return cache;
17687 }
17688
PutRegExp(Isolate * isolate,Handle<CompilationCacheTable> cache,Handle<String> src,JSRegExp::Flags flags,Handle<FixedArray> value)17689 Handle<CompilationCacheTable> CompilationCacheTable::PutRegExp(
17690 Isolate* isolate, Handle<CompilationCacheTable> cache, Handle<String> src,
17691 JSRegExp::Flags flags, Handle<FixedArray> value) {
17692 RegExpKey key(src, flags);
17693 cache = EnsureCapacity(isolate, cache, 1);
17694 int entry = cache->FindInsertionEntry(key.Hash());
17695 // We store the value in the key slot, and compare the search key
17696 // to the stored value with a custon IsMatch function during lookups.
17697 cache->set(EntryToIndex(entry), *value);
17698 cache->set(EntryToIndex(entry) + 1, *value);
17699 cache->ElementAdded();
17700 return cache;
17701 }
17702
17703
Age()17704 void CompilationCacheTable::Age() {
17705 DisallowHeapAllocation no_allocation;
17706 Object* the_hole_value = GetReadOnlyRoots().the_hole_value();
17707 for (int entry = 0, size = Capacity(); entry < size; entry++) {
17708 int entry_index = EntryToIndex(entry);
17709 int value_index = entry_index + 1;
17710
17711 if (get(entry_index)->IsNumber()) {
17712 Smi* count = Smi::cast(get(value_index));
17713 count = Smi::FromInt(count->value() - 1);
17714 if (count->value() == 0) {
17715 NoWriteBarrierSet(this, entry_index, the_hole_value);
17716 NoWriteBarrierSet(this, value_index, the_hole_value);
17717 ElementRemoved();
17718 } else {
17719 NoWriteBarrierSet(this, value_index, count);
17720 }
17721 } else if (get(entry_index)->IsFixedArray()) {
17722 SharedFunctionInfo* info = SharedFunctionInfo::cast(get(value_index));
17723 if (info->IsInterpreted() && info->GetBytecodeArray()->IsOld()) {
17724 for (int i = 0; i < kEntrySize; i++) {
17725 NoWriteBarrierSet(this, entry_index + i, the_hole_value);
17726 }
17727 ElementRemoved();
17728 }
17729 }
17730 }
17731 }
17732
17733
Remove(Object * value)17734 void CompilationCacheTable::Remove(Object* value) {
17735 DisallowHeapAllocation no_allocation;
17736 Object* the_hole_value = GetReadOnlyRoots().the_hole_value();
17737 for (int entry = 0, size = Capacity(); entry < size; entry++) {
17738 int entry_index = EntryToIndex(entry);
17739 int value_index = entry_index + 1;
17740 if (get(value_index) == value) {
17741 for (int i = 0; i < kEntrySize; i++) {
17742 NoWriteBarrierSet(this, entry_index + i, the_hole_value);
17743 }
17744 ElementRemoved();
17745 }
17746 }
17747 return;
17748 }
17749
17750 template <typename Derived, typename Shape>
New(Isolate * isolate,int at_least_space_for,PretenureFlag pretenure,MinimumCapacity capacity_option)17751 Handle<Derived> BaseNameDictionary<Derived, Shape>::New(
17752 Isolate* isolate, int at_least_space_for, PretenureFlag pretenure,
17753 MinimumCapacity capacity_option) {
17754 DCHECK_LE(0, at_least_space_for);
17755 Handle<Derived> dict = Dictionary<Derived, Shape>::New(
17756 isolate, at_least_space_for, pretenure, capacity_option);
17757 dict->SetHash(PropertyArray::kNoHashSentinel);
17758 dict->SetNextEnumerationIndex(PropertyDetails::kInitialIndex);
17759 return dict;
17760 }
17761
17762 template <typename Derived, typename Shape>
EnsureCapacity(Isolate * isolate,Handle<Derived> dictionary,int n)17763 Handle<Derived> BaseNameDictionary<Derived, Shape>::EnsureCapacity(
17764 Isolate* isolate, Handle<Derived> dictionary, int n) {
17765 // Check whether there are enough enumeration indices to add n elements.
17766 if (!PropertyDetails::IsValidIndex(dictionary->NextEnumerationIndex() + n)) {
17767 // If not, we generate new indices for the properties.
17768 int length = dictionary->NumberOfElements();
17769
17770 Handle<FixedArray> iteration_order = IterationIndices(isolate, dictionary);
17771 DCHECK_EQ(length, iteration_order->length());
17772
17773 // Iterate over the dictionary using the enumeration order and update
17774 // the dictionary with new enumeration indices.
17775 for (int i = 0; i < length; i++) {
17776 int index = Smi::ToInt(iteration_order->get(i));
17777 DCHECK(dictionary->IsKey(dictionary->GetReadOnlyRoots(),
17778 dictionary->KeyAt(index)));
17779
17780 int enum_index = PropertyDetails::kInitialIndex + i;
17781
17782 PropertyDetails details = dictionary->DetailsAt(index);
17783 PropertyDetails new_details = details.set_index(enum_index);
17784 dictionary->DetailsAtPut(isolate, index, new_details);
17785 }
17786
17787 // Set the next enumeration index.
17788 dictionary->SetNextEnumerationIndex(PropertyDetails::kInitialIndex +
17789 length);
17790 }
17791 return HashTable<Derived, Shape>::EnsureCapacity(isolate, dictionary, n);
17792 }
17793
17794 template <typename Derived, typename Shape>
DeleteEntry(Isolate * isolate,Handle<Derived> dictionary,int entry)17795 Handle<Derived> Dictionary<Derived, Shape>::DeleteEntry(
17796 Isolate* isolate, Handle<Derived> dictionary, int entry) {
17797 DCHECK(Shape::kEntrySize != 3 ||
17798 dictionary->DetailsAt(entry).IsConfigurable());
17799 dictionary->ClearEntry(isolate, entry);
17800 dictionary->ElementRemoved();
17801 return Shrink(isolate, dictionary);
17802 }
17803
17804 template <typename Derived, typename Shape>
AtPut(Isolate * isolate,Handle<Derived> dictionary,Key key,Handle<Object> value,PropertyDetails details)17805 Handle<Derived> Dictionary<Derived, Shape>::AtPut(Isolate* isolate,
17806 Handle<Derived> dictionary,
17807 Key key, Handle<Object> value,
17808 PropertyDetails details) {
17809 int entry = dictionary->FindEntry(isolate, key);
17810
17811 // If the entry is present set the value;
17812 if (entry == Dictionary::kNotFound) {
17813 return Derived::Add(isolate, dictionary, key, value, details);
17814 }
17815
17816 // We don't need to copy over the enumeration index.
17817 dictionary->ValueAtPut(entry, *value);
17818 if (Shape::kEntrySize == 3) dictionary->DetailsAtPut(isolate, entry, details);
17819 return dictionary;
17820 }
17821
17822 template <typename Derived, typename Shape>
17823 Handle<Derived>
AddNoUpdateNextEnumerationIndex(Isolate * isolate,Handle<Derived> dictionary,Key key,Handle<Object> value,PropertyDetails details,int * entry_out)17824 BaseNameDictionary<Derived, Shape>::AddNoUpdateNextEnumerationIndex(
17825 Isolate* isolate, Handle<Derived> dictionary, Key key, Handle<Object> value,
17826 PropertyDetails details, int* entry_out) {
17827 // Insert element at empty or deleted entry
17828 return Dictionary<Derived, Shape>::Add(isolate, dictionary, key, value,
17829 details, entry_out);
17830 }
17831
17832 // GCC workaround: Explicitly instantiate template method for NameDictionary
17833 // to avoid "undefined reference" issues during linking.
17834 template Handle<NameDictionary>
17835 BaseNameDictionary<NameDictionary, NameDictionaryShape>::
17836 AddNoUpdateNextEnumerationIndex(Isolate* isolate, Handle<NameDictionary>,
17837 Handle<Name>, Handle<Object>,
17838 PropertyDetails, int*);
17839
17840 template <typename Derived, typename Shape>
Add(Isolate * isolate,Handle<Derived> dictionary,Key key,Handle<Object> value,PropertyDetails details,int * entry_out)17841 Handle<Derived> BaseNameDictionary<Derived, Shape>::Add(
17842 Isolate* isolate, Handle<Derived> dictionary, Key key, Handle<Object> value,
17843 PropertyDetails details, int* entry_out) {
17844 // Insert element at empty or deleted entry
17845 DCHECK_EQ(0, details.dictionary_index());
17846 // Assign an enumeration index to the property and update
17847 // SetNextEnumerationIndex.
17848 int index = dictionary->NextEnumerationIndex();
17849 details = details.set_index(index);
17850 dictionary->SetNextEnumerationIndex(index + 1);
17851 return AddNoUpdateNextEnumerationIndex(isolate, dictionary, key, value,
17852 details, entry_out);
17853 }
17854
17855 template <typename Derived, typename Shape>
Add(Isolate * isolate,Handle<Derived> dictionary,Key key,Handle<Object> value,PropertyDetails details,int * entry_out)17856 Handle<Derived> Dictionary<Derived, Shape>::Add(Isolate* isolate,
17857 Handle<Derived> dictionary,
17858 Key key, Handle<Object> value,
17859 PropertyDetails details,
17860 int* entry_out) {
17861 uint32_t hash = Shape::Hash(isolate, key);
17862 // Valdate key is absent.
17863 SLOW_DCHECK((dictionary->FindEntry(isolate, key) == Dictionary::kNotFound));
17864 // Check whether the dictionary should be extended.
17865 dictionary = Derived::EnsureCapacity(isolate, dictionary, 1);
17866
17867 // Compute the key object.
17868 Handle<Object> k = Shape::AsHandle(isolate, key);
17869
17870 uint32_t entry = dictionary->FindInsertionEntry(hash);
17871 dictionary->SetEntry(isolate, entry, *k, *value, details);
17872 DCHECK(dictionary->KeyAt(entry)->IsNumber() ||
17873 Shape::Unwrap(dictionary->KeyAt(entry))->IsUniqueName());
17874 dictionary->ElementAdded();
17875 if (entry_out) *entry_out = entry;
17876 return dictionary;
17877 }
17878
17879 // static
Set(Isolate * isolate,Handle<SimpleNumberDictionary> dictionary,uint32_t key,Handle<Object> value)17880 Handle<SimpleNumberDictionary> SimpleNumberDictionary::Set(
17881 Isolate* isolate, Handle<SimpleNumberDictionary> dictionary, uint32_t key,
17882 Handle<Object> value) {
17883 return AtPut(isolate, dictionary, key, value, PropertyDetails::Empty());
17884 }
17885
HasComplexElements()17886 bool NumberDictionary::HasComplexElements() {
17887 if (!requires_slow_elements()) return false;
17888 ReadOnlyRoots roots = GetReadOnlyRoots();
17889 int capacity = this->Capacity();
17890 for (int i = 0; i < capacity; i++) {
17891 Object* k;
17892 if (!this->ToKey(roots, i, &k)) continue;
17893 PropertyDetails details = this->DetailsAt(i);
17894 if (details.kind() == kAccessor) return true;
17895 PropertyAttributes attr = details.attributes();
17896 if (attr & ALL_ATTRIBUTES_MASK) return true;
17897 }
17898 return false;
17899 }
17900
UpdateMaxNumberKey(uint32_t key,Handle<JSObject> dictionary_holder)17901 void NumberDictionary::UpdateMaxNumberKey(uint32_t key,
17902 Handle<JSObject> dictionary_holder) {
17903 DisallowHeapAllocation no_allocation;
17904 // If the dictionary requires slow elements an element has already
17905 // been added at a high index.
17906 if (requires_slow_elements()) return;
17907 // Check if this index is high enough that we should require slow
17908 // elements.
17909 if (key > kRequiresSlowElementsLimit) {
17910 if (!dictionary_holder.is_null()) {
17911 dictionary_holder->RequireSlowElements(this);
17912 }
17913 set_requires_slow_elements();
17914 return;
17915 }
17916 // Update max key value.
17917 Object* max_index_object = get(kMaxNumberKeyIndex);
17918 if (!max_index_object->IsSmi() || max_number_key() < key) {
17919 FixedArray::set(kMaxNumberKeyIndex,
17920 Smi::FromInt(key << kRequiresSlowElementsTagSize));
17921 }
17922 }
17923
Set(Isolate * isolate,Handle<NumberDictionary> dictionary,uint32_t key,Handle<Object> value,Handle<JSObject> dictionary_holder,PropertyDetails details)17924 Handle<NumberDictionary> NumberDictionary::Set(
17925 Isolate* isolate, Handle<NumberDictionary> dictionary, uint32_t key,
17926 Handle<Object> value, Handle<JSObject> dictionary_holder,
17927 PropertyDetails details) {
17928 dictionary->UpdateMaxNumberKey(key, dictionary_holder);
17929 return AtPut(isolate, dictionary, key, value, details);
17930 }
17931
CopyValuesTo(FixedArray * elements)17932 void NumberDictionary::CopyValuesTo(FixedArray* elements) {
17933 ReadOnlyRoots roots = GetReadOnlyRoots();
17934 int pos = 0;
17935 int capacity = this->Capacity();
17936 DisallowHeapAllocation no_gc;
17937 WriteBarrierMode mode = elements->GetWriteBarrierMode(no_gc);
17938 for (int i = 0; i < capacity; i++) {
17939 Object* k;
17940 if (this->ToKey(roots, i, &k)) {
17941 elements->set(pos++, this->ValueAt(i), mode);
17942 }
17943 }
17944 DCHECK_EQ(pos, elements->length());
17945 }
17946
17947 template <typename Derived, typename Shape>
NumberOfEnumerableProperties()17948 int Dictionary<Derived, Shape>::NumberOfEnumerableProperties() {
17949 ReadOnlyRoots roots = this->GetReadOnlyRoots();
17950 int capacity = this->Capacity();
17951 int result = 0;
17952 for (int i = 0; i < capacity; i++) {
17953 Object* k;
17954 if (!this->ToKey(roots, i, &k)) continue;
17955 if (k->FilterKey(ENUMERABLE_STRINGS)) continue;
17956 PropertyDetails details = this->DetailsAt(i);
17957 PropertyAttributes attr = details.attributes();
17958 if ((attr & ONLY_ENUMERABLE) == 0) result++;
17959 }
17960 return result;
17961 }
17962
17963
17964 template <typename Dictionary>
17965 struct EnumIndexComparator {
EnumIndexComparatorv8::internal::EnumIndexComparator17966 explicit EnumIndexComparator(Dictionary* dict) : dict(dict) {}
operator ()v8::internal::EnumIndexComparator17967 bool operator()(const base::AtomicElement<Smi*>& a,
17968 const base::AtomicElement<Smi*>& b) {
17969 PropertyDetails da(dict->DetailsAt(a.value()->value()));
17970 PropertyDetails db(dict->DetailsAt(b.value()->value()));
17971 return da.dictionary_index() < db.dictionary_index();
17972 }
17973 Dictionary* dict;
17974 };
17975
17976 template <typename Derived, typename Shape>
CopyEnumKeysTo(Isolate * isolate,Handle<Derived> dictionary,Handle<FixedArray> storage,KeyCollectionMode mode,KeyAccumulator * accumulator)17977 void BaseNameDictionary<Derived, Shape>::CopyEnumKeysTo(
17978 Isolate* isolate, Handle<Derived> dictionary, Handle<FixedArray> storage,
17979 KeyCollectionMode mode, KeyAccumulator* accumulator) {
17980 DCHECK_IMPLIES(mode != KeyCollectionMode::kOwnOnly, accumulator != nullptr);
17981 int length = storage->length();
17982 int capacity = dictionary->Capacity();
17983 int properties = 0;
17984 ReadOnlyRoots roots(isolate);
17985 for (int i = 0; i < capacity; i++) {
17986 Object* key;
17987 if (!dictionary->ToKey(roots, i, &key)) continue;
17988 bool is_shadowing_key = false;
17989 if (key->IsSymbol()) continue;
17990 PropertyDetails details = dictionary->DetailsAt(i);
17991 if (details.IsDontEnum()) {
17992 if (mode == KeyCollectionMode::kIncludePrototypes) {
17993 is_shadowing_key = true;
17994 } else {
17995 continue;
17996 }
17997 }
17998 if (is_shadowing_key) {
17999 accumulator->AddShadowingKey(key);
18000 continue;
18001 } else {
18002 storage->set(properties, Smi::FromInt(i));
18003 }
18004 properties++;
18005 if (mode == KeyCollectionMode::kOwnOnly && properties == length) break;
18006 }
18007
18008 CHECK_EQ(length, properties);
18009 DisallowHeapAllocation no_gc;
18010 Derived* raw_dictionary = *dictionary;
18011 FixedArray* raw_storage = *storage;
18012 EnumIndexComparator<Derived> cmp(raw_dictionary);
18013 // Use AtomicElement wrapper to ensure that std::sort uses atomic load and
18014 // store operations that are safe for concurrent marking.
18015 base::AtomicElement<Smi*>* start =
18016 reinterpret_cast<base::AtomicElement<Smi*>*>(
18017 storage->GetFirstElementAddress());
18018 std::sort(start, start + length, cmp);
18019 for (int i = 0; i < length; i++) {
18020 int index = Smi::ToInt(raw_storage->get(i));
18021 raw_storage->set(i, raw_dictionary->NameAt(index));
18022 }
18023 }
18024
18025 template <typename Derived, typename Shape>
IterationIndices(Isolate * isolate,Handle<Derived> dictionary)18026 Handle<FixedArray> BaseNameDictionary<Derived, Shape>::IterationIndices(
18027 Isolate* isolate, Handle<Derived> dictionary) {
18028 int capacity = dictionary->Capacity();
18029 int length = dictionary->NumberOfElements();
18030 Handle<FixedArray> array = isolate->factory()->NewFixedArray(length);
18031 ReadOnlyRoots roots(isolate);
18032 int array_size = 0;
18033 {
18034 DisallowHeapAllocation no_gc;
18035 Derived* raw_dictionary = *dictionary;
18036 for (int i = 0; i < capacity; i++) {
18037 Object* k;
18038 if (!raw_dictionary->ToKey(roots, i, &k)) continue;
18039 array->set(array_size++, Smi::FromInt(i));
18040 }
18041
18042 DCHECK_EQ(array_size, length);
18043
18044 EnumIndexComparator<Derived> cmp(raw_dictionary);
18045 // Use AtomicElement wrapper to ensure that std::sort uses atomic load and
18046 // store operations that are safe for concurrent marking.
18047 base::AtomicElement<Smi*>* start =
18048 reinterpret_cast<base::AtomicElement<Smi*>*>(
18049 array->GetFirstElementAddress());
18050 std::sort(start, start + array_size, cmp);
18051 }
18052 return FixedArray::ShrinkOrEmpty(isolate, array, array_size);
18053 }
18054
18055 template <typename Derived, typename Shape>
CollectKeysTo(Handle<Derived> dictionary,KeyAccumulator * keys)18056 void BaseNameDictionary<Derived, Shape>::CollectKeysTo(
18057 Handle<Derived> dictionary, KeyAccumulator* keys) {
18058 Isolate* isolate = keys->isolate();
18059 ReadOnlyRoots roots(isolate);
18060 int capacity = dictionary->Capacity();
18061 Handle<FixedArray> array =
18062 isolate->factory()->NewFixedArray(dictionary->NumberOfElements());
18063 int array_size = 0;
18064 PropertyFilter filter = keys->filter();
18065 {
18066 DisallowHeapAllocation no_gc;
18067 Derived* raw_dictionary = *dictionary;
18068 for (int i = 0; i < capacity; i++) {
18069 Object* k;
18070 if (!raw_dictionary->ToKey(roots, i, &k)) continue;
18071 if (k->FilterKey(filter)) continue;
18072 PropertyDetails details = raw_dictionary->DetailsAt(i);
18073 if ((details.attributes() & filter) != 0) {
18074 keys->AddShadowingKey(k);
18075 continue;
18076 }
18077 if (filter & ONLY_ALL_CAN_READ) {
18078 if (details.kind() != kAccessor) continue;
18079 Object* accessors = raw_dictionary->ValueAt(i);
18080 if (!accessors->IsAccessorInfo()) continue;
18081 if (!AccessorInfo::cast(accessors)->all_can_read()) continue;
18082 }
18083 array->set(array_size++, Smi::FromInt(i));
18084 }
18085
18086 EnumIndexComparator<Derived> cmp(raw_dictionary);
18087 // Use AtomicElement wrapper to ensure that std::sort uses atomic load and
18088 // store operations that are safe for concurrent marking.
18089 base::AtomicElement<Smi*>* start =
18090 reinterpret_cast<base::AtomicElement<Smi*>*>(
18091 array->GetFirstElementAddress());
18092 std::sort(start, start + array_size, cmp);
18093 }
18094
18095 bool has_seen_symbol = false;
18096 for (int i = 0; i < array_size; i++) {
18097 int index = Smi::ToInt(array->get(i));
18098 Object* key = dictionary->NameAt(index);
18099 if (key->IsSymbol()) {
18100 has_seen_symbol = true;
18101 continue;
18102 }
18103 keys->AddKey(key, DO_NOT_CONVERT);
18104 }
18105 if (has_seen_symbol) {
18106 for (int i = 0; i < array_size; i++) {
18107 int index = Smi::ToInt(array->get(i));
18108 Object* key = dictionary->NameAt(index);
18109 if (!key->IsSymbol()) continue;
18110 keys->AddKey(key, DO_NOT_CONVERT);
18111 }
18112 }
18113 }
18114
18115 // Backwards lookup (slow).
18116 template <typename Derived, typename Shape>
SlowReverseLookup(Object * value)18117 Object* Dictionary<Derived, Shape>::SlowReverseLookup(Object* value) {
18118 Derived* dictionary = Derived::cast(this);
18119 ReadOnlyRoots roots = dictionary->GetReadOnlyRoots();
18120 int capacity = dictionary->Capacity();
18121 for (int i = 0; i < capacity; i++) {
18122 Object* k;
18123 if (!dictionary->ToKey(roots, i, &k)) continue;
18124 Object* e = dictionary->ValueAt(i);
18125 if (e == value) return k;
18126 }
18127 return roots.undefined_value();
18128 }
18129
18130 template <typename Derived, typename Shape>
FillEntriesWithHoles(Handle<Derived> table)18131 void ObjectHashTableBase<Derived, Shape>::FillEntriesWithHoles(
18132 Handle<Derived> table) {
18133 int length = table->length();
18134 for (int i = Derived::EntryToIndex(0); i < length; i++) {
18135 table->set_the_hole(i);
18136 }
18137 }
18138
18139 template <typename Derived, typename Shape>
Lookup(ReadOnlyRoots roots,Handle<Object> key,int32_t hash)18140 Object* ObjectHashTableBase<Derived, Shape>::Lookup(ReadOnlyRoots roots,
18141 Handle<Object> key,
18142 int32_t hash) {
18143 DisallowHeapAllocation no_gc;
18144 DCHECK(this->IsKey(roots, *key));
18145
18146 int entry = this->FindEntry(roots, key, hash);
18147 if (entry == kNotFound) return roots.the_hole_value();
18148 return this->get(Derived::EntryToIndex(entry) + 1);
18149 }
18150
18151 template <typename Derived, typename Shape>
Lookup(Handle<Object> key)18152 Object* ObjectHashTableBase<Derived, Shape>::Lookup(Handle<Object> key) {
18153 DisallowHeapAllocation no_gc;
18154
18155 ReadOnlyRoots roots = this->GetReadOnlyRoots();
18156 DCHECK(this->IsKey(roots, *key));
18157
18158 // If the object does not have an identity hash, it was never used as a key.
18159 Object* hash = key->GetHash();
18160 if (hash->IsUndefined(roots)) {
18161 return roots.the_hole_value();
18162 }
18163 return Lookup(roots, key, Smi::ToInt(hash));
18164 }
18165
18166 template <typename Derived, typename Shape>
Lookup(Handle<Object> key,int32_t hash)18167 Object* ObjectHashTableBase<Derived, Shape>::Lookup(Handle<Object> key,
18168 int32_t hash) {
18169 return Lookup(this->GetReadOnlyRoots(), key, hash);
18170 }
18171
18172 template <typename Derived, typename Shape>
ValueAt(int entry)18173 Object* ObjectHashTableBase<Derived, Shape>::ValueAt(int entry) {
18174 return this->get(EntryToValueIndex(entry));
18175 }
18176
18177 template <typename Derived, typename Shape>
Put(Handle<Derived> table,Handle<Object> key,Handle<Object> value)18178 Handle<Derived> ObjectHashTableBase<Derived, Shape>::Put(Handle<Derived> table,
18179 Handle<Object> key,
18180 Handle<Object> value) {
18181 Isolate* isolate = Heap::FromWritableHeapObject(*table)->isolate();
18182 DCHECK(table->IsKey(ReadOnlyRoots(isolate), *key));
18183 DCHECK(!value->IsTheHole(ReadOnlyRoots(isolate)));
18184
18185 // Make sure the key object has an identity hash code.
18186 int32_t hash = key->GetOrCreateHash(isolate)->value();
18187
18188 return ObjectHashTableBase<Derived, Shape>::Put(isolate, table, key, value,
18189 hash);
18190 }
18191
18192 template <typename Derived, typename Shape>
Put(Isolate * isolate,Handle<Derived> table,Handle<Object> key,Handle<Object> value,int32_t hash)18193 Handle<Derived> ObjectHashTableBase<Derived, Shape>::Put(Isolate* isolate,
18194 Handle<Derived> table,
18195 Handle<Object> key,
18196 Handle<Object> value,
18197 int32_t hash) {
18198 ReadOnlyRoots roots(isolate);
18199 DCHECK(table->IsKey(roots, *key));
18200 DCHECK(!value->IsTheHole(roots));
18201
18202 int entry = table->FindEntry(roots, key, hash);
18203
18204 // Key is already in table, just overwrite value.
18205 if (entry != kNotFound) {
18206 table->set(Derived::EntryToIndex(entry) + 1, *value);
18207 return table;
18208 }
18209
18210 // Rehash if more than 33% of the entries are deleted entries.
18211 // TODO(jochen): Consider to shrink the fixed array in place.
18212 if ((table->NumberOfDeletedElements() << 1) > table->NumberOfElements()) {
18213 table->Rehash(isolate);
18214 }
18215 // If we're out of luck, we didn't get a GC recently, and so rehashing
18216 // isn't enough to avoid a crash.
18217 if (!table->HasSufficientCapacityToAdd(1)) {
18218 int nof = table->NumberOfElements() + 1;
18219 int capacity = ObjectHashTable::ComputeCapacity(nof * 2);
18220 if (capacity > ObjectHashTable::kMaxCapacity) {
18221 for (size_t i = 0; i < 2; ++i) {
18222 isolate->heap()->CollectAllGarbage(
18223 Heap::kFinalizeIncrementalMarkingMask,
18224 GarbageCollectionReason::kFullHashtable);
18225 }
18226 table->Rehash(isolate);
18227 }
18228 }
18229
18230 // Check whether the hash table should be extended.
18231 table = Derived::EnsureCapacity(isolate, table, 1);
18232 table->AddEntry(table->FindInsertionEntry(hash), *key, *value);
18233 return table;
18234 }
18235
18236 template <typename Derived, typename Shape>
Remove(Isolate * isolate,Handle<Derived> table,Handle<Object> key,bool * was_present)18237 Handle<Derived> ObjectHashTableBase<Derived, Shape>::Remove(
18238 Isolate* isolate, Handle<Derived> table, Handle<Object> key,
18239 bool* was_present) {
18240 DCHECK(table->IsKey(table->GetReadOnlyRoots(), *key));
18241
18242 Object* hash = key->GetHash();
18243 if (hash->IsUndefined()) {
18244 *was_present = false;
18245 return table;
18246 }
18247
18248 return Remove(isolate, table, key, was_present, Smi::ToInt(hash));
18249 }
18250
18251 template <typename Derived, typename Shape>
Remove(Isolate * isolate,Handle<Derived> table,Handle<Object> key,bool * was_present,int32_t hash)18252 Handle<Derived> ObjectHashTableBase<Derived, Shape>::Remove(
18253 Isolate* isolate, Handle<Derived> table, Handle<Object> key,
18254 bool* was_present, int32_t hash) {
18255 ReadOnlyRoots roots = table->GetReadOnlyRoots();
18256 DCHECK(table->IsKey(roots, *key));
18257
18258 int entry = table->FindEntry(roots, key, hash);
18259 if (entry == kNotFound) {
18260 *was_present = false;
18261 return table;
18262 }
18263
18264 *was_present = true;
18265 table->RemoveEntry(entry);
18266 return Derived::Shrink(isolate, table);
18267 }
18268
18269 template <typename Derived, typename Shape>
AddEntry(int entry,Object * key,Object * value)18270 void ObjectHashTableBase<Derived, Shape>::AddEntry(int entry, Object* key,
18271 Object* value) {
18272 this->set(Derived::EntryToIndex(entry), key);
18273 this->set(Derived::EntryToIndex(entry) + 1, value);
18274 this->ElementAdded();
18275 }
18276
18277 template <typename Derived, typename Shape>
RemoveEntry(int entry)18278 void ObjectHashTableBase<Derived, Shape>::RemoveEntry(int entry) {
18279 this->set_the_hole(Derived::EntryToIndex(entry));
18280 this->set_the_hole(Derived::EntryToIndex(entry) + 1);
18281 this->ElementRemoved();
18282 }
18283
18284
Initialize(Handle<JSSet> set,Isolate * isolate)18285 void JSSet::Initialize(Handle<JSSet> set, Isolate* isolate) {
18286 Handle<OrderedHashSet> table = isolate->factory()->NewOrderedHashSet();
18287 set->set_table(*table);
18288 }
18289
Clear(Isolate * isolate,Handle<JSSet> set)18290 void JSSet::Clear(Isolate* isolate, Handle<JSSet> set) {
18291 Handle<OrderedHashSet> table(OrderedHashSet::cast(set->table()), isolate);
18292 table = OrderedHashSet::Clear(isolate, table);
18293 set->set_table(*table);
18294 }
18295
18296
Initialize(Handle<JSMap> map,Isolate * isolate)18297 void JSMap::Initialize(Handle<JSMap> map, Isolate* isolate) {
18298 Handle<OrderedHashMap> table = isolate->factory()->NewOrderedHashMap();
18299 map->set_table(*table);
18300 }
18301
Clear(Isolate * isolate,Handle<JSMap> map)18302 void JSMap::Clear(Isolate* isolate, Handle<JSMap> map) {
18303 Handle<OrderedHashMap> table(OrderedHashMap::cast(map->table()), isolate);
18304 table = OrderedHashMap::Clear(isolate, table);
18305 map->set_table(*table);
18306 }
18307
18308
Initialize(Handle<JSWeakCollection> weak_collection,Isolate * isolate)18309 void JSWeakCollection::Initialize(Handle<JSWeakCollection> weak_collection,
18310 Isolate* isolate) {
18311 Handle<EphemeronHashTable> table = EphemeronHashTable::New(isolate, 0);
18312 weak_collection->set_table(*table);
18313 }
18314
18315
Set(Handle<JSWeakCollection> weak_collection,Handle<Object> key,Handle<Object> value,int32_t hash)18316 void JSWeakCollection::Set(Handle<JSWeakCollection> weak_collection,
18317 Handle<Object> key, Handle<Object> value,
18318 int32_t hash) {
18319 DCHECK(key->IsJSReceiver() || key->IsSymbol());
18320 Handle<EphemeronHashTable> table(
18321 EphemeronHashTable::cast(weak_collection->table()),
18322 weak_collection->GetIsolate());
18323 DCHECK(table->IsKey(weak_collection->GetReadOnlyRoots(), *key));
18324 Handle<EphemeronHashTable> new_table = EphemeronHashTable::Put(
18325 weak_collection->GetIsolate(), table, key, value, hash);
18326 weak_collection->set_table(*new_table);
18327 if (*table != *new_table) {
18328 // Zap the old table since we didn't record slots for its elements.
18329 EphemeronHashTable::FillEntriesWithHoles(table);
18330 }
18331 }
18332
18333
Delete(Handle<JSWeakCollection> weak_collection,Handle<Object> key,int32_t hash)18334 bool JSWeakCollection::Delete(Handle<JSWeakCollection> weak_collection,
18335 Handle<Object> key, int32_t hash) {
18336 DCHECK(key->IsJSReceiver() || key->IsSymbol());
18337 Handle<EphemeronHashTable> table(
18338 EphemeronHashTable::cast(weak_collection->table()),
18339 weak_collection->GetIsolate());
18340 DCHECK(table->IsKey(weak_collection->GetReadOnlyRoots(), *key));
18341 bool was_present = false;
18342 Handle<EphemeronHashTable> new_table = EphemeronHashTable::Remove(
18343 weak_collection->GetIsolate(), table, key, &was_present, hash);
18344 weak_collection->set_table(*new_table);
18345 if (*table != *new_table) {
18346 // Zap the old table since we didn't record slots for its elements.
18347 EphemeronHashTable::FillEntriesWithHoles(table);
18348 }
18349 return was_present;
18350 }
18351
GetEntries(Handle<JSWeakCollection> holder,int max_entries)18352 Handle<JSArray> JSWeakCollection::GetEntries(Handle<JSWeakCollection> holder,
18353 int max_entries) {
18354 Isolate* isolate = holder->GetIsolate();
18355 Handle<EphemeronHashTable> table(EphemeronHashTable::cast(holder->table()),
18356 isolate);
18357 if (max_entries == 0 || max_entries > table->NumberOfElements()) {
18358 max_entries = table->NumberOfElements();
18359 }
18360 int values_per_entry = holder->IsJSWeakMap() ? 2 : 1;
18361 Handle<FixedArray> entries =
18362 isolate->factory()->NewFixedArray(max_entries * values_per_entry);
18363 // Recompute max_values because GC could have removed elements from the table.
18364 if (max_entries > table->NumberOfElements()) {
18365 max_entries = table->NumberOfElements();
18366 }
18367
18368 {
18369 DisallowHeapAllocation no_gc;
18370 ReadOnlyRoots roots = ReadOnlyRoots(isolate);
18371 int count = 0;
18372 for (int i = 0;
18373 count / values_per_entry < max_entries && i < table->Capacity(); i++) {
18374 Object* key;
18375 if (table->ToKey(roots, i, &key)) {
18376 entries->set(count++, key);
18377 if (values_per_entry > 1) {
18378 Object* value = table->Lookup(handle(key, isolate));
18379 entries->set(count++, value);
18380 }
18381 }
18382 }
18383 DCHECK_EQ(max_entries * values_per_entry, count);
18384 }
18385 return isolate->factory()->NewJSArrayWithElements(entries);
18386 }
18387
18388 // static
New(Handle<JSFunction> constructor,Handle<JSReceiver> new_target,double tv)18389 MaybeHandle<JSDate> JSDate::New(Handle<JSFunction> constructor,
18390 Handle<JSReceiver> new_target, double tv) {
18391 Isolate* const isolate = constructor->GetIsolate();
18392 Handle<JSObject> result;
18393 ASSIGN_RETURN_ON_EXCEPTION(isolate, result,
18394 JSObject::New(constructor, new_target), JSDate);
18395 if (-DateCache::kMaxTimeInMs <= tv && tv <= DateCache::kMaxTimeInMs) {
18396 tv = DoubleToInteger(tv) + 0.0;
18397 } else {
18398 tv = std::numeric_limits<double>::quiet_NaN();
18399 }
18400 Handle<Object> value = isolate->factory()->NewNumber(tv);
18401 Handle<JSDate>::cast(result)->SetValue(*value, std::isnan(tv));
18402 return Handle<JSDate>::cast(result);
18403 }
18404
18405
18406 // static
CurrentTimeValue(Isolate * isolate)18407 double JSDate::CurrentTimeValue(Isolate* isolate) {
18408 if (FLAG_log_internal_timer_events) LOG(isolate, CurrentTimeEvent());
18409
18410 // According to ECMA-262, section 15.9.1, page 117, the precision of
18411 // the number in a Date object representing a particular instant in
18412 // time is milliseconds. Therefore, we floor the result of getting
18413 // the OS time.
18414 return Floor(V8::GetCurrentPlatform()->CurrentClockTimeMillis());
18415 }
18416
18417
18418 // static
GetField(Object * object,Smi * index)18419 Object* JSDate::GetField(Object* object, Smi* index) {
18420 return JSDate::cast(object)->DoGetField(
18421 static_cast<FieldIndex>(index->value()));
18422 }
18423
18424
DoGetField(FieldIndex index)18425 Object* JSDate::DoGetField(FieldIndex index) {
18426 DCHECK_NE(index, kDateValue);
18427
18428 DateCache* date_cache = GetIsolate()->date_cache();
18429
18430 if (index < kFirstUncachedField) {
18431 Object* stamp = cache_stamp();
18432 if (stamp != date_cache->stamp() && stamp->IsSmi()) {
18433 // Since the stamp is not NaN, the value is also not NaN.
18434 int64_t local_time_ms =
18435 date_cache->ToLocal(static_cast<int64_t>(value()->Number()));
18436 SetCachedFields(local_time_ms, date_cache);
18437 }
18438 switch (index) {
18439 case kYear: return year();
18440 case kMonth: return month();
18441 case kDay: return day();
18442 case kWeekday: return weekday();
18443 case kHour: return hour();
18444 case kMinute: return min();
18445 case kSecond: return sec();
18446 default: UNREACHABLE();
18447 }
18448 }
18449
18450 if (index >= kFirstUTCField) {
18451 return GetUTCField(index, value()->Number(), date_cache);
18452 }
18453
18454 double time = value()->Number();
18455 if (std::isnan(time)) return GetReadOnlyRoots().nan_value();
18456
18457 int64_t local_time_ms = date_cache->ToLocal(static_cast<int64_t>(time));
18458 int days = DateCache::DaysFromTime(local_time_ms);
18459
18460 if (index == kDays) return Smi::FromInt(days);
18461
18462 int time_in_day_ms = DateCache::TimeInDay(local_time_ms, days);
18463 if (index == kMillisecond) return Smi::FromInt(time_in_day_ms % 1000);
18464 DCHECK_EQ(index, kTimeInDay);
18465 return Smi::FromInt(time_in_day_ms);
18466 }
18467
18468
GetUTCField(FieldIndex index,double value,DateCache * date_cache)18469 Object* JSDate::GetUTCField(FieldIndex index,
18470 double value,
18471 DateCache* date_cache) {
18472 DCHECK_GE(index, kFirstUTCField);
18473
18474 if (std::isnan(value)) return GetReadOnlyRoots().nan_value();
18475
18476 int64_t time_ms = static_cast<int64_t>(value);
18477
18478 if (index == kTimezoneOffset) {
18479 return Smi::FromInt(date_cache->TimezoneOffset(time_ms));
18480 }
18481
18482 int days = DateCache::DaysFromTime(time_ms);
18483
18484 if (index == kWeekdayUTC) return Smi::FromInt(date_cache->Weekday(days));
18485
18486 if (index <= kDayUTC) {
18487 int year, month, day;
18488 date_cache->YearMonthDayFromDays(days, &year, &month, &day);
18489 if (index == kYearUTC) return Smi::FromInt(year);
18490 if (index == kMonthUTC) return Smi::FromInt(month);
18491 DCHECK_EQ(index, kDayUTC);
18492 return Smi::FromInt(day);
18493 }
18494
18495 int time_in_day_ms = DateCache::TimeInDay(time_ms, days);
18496 switch (index) {
18497 case kHourUTC: return Smi::FromInt(time_in_day_ms / (60 * 60 * 1000));
18498 case kMinuteUTC: return Smi::FromInt((time_in_day_ms / (60 * 1000)) % 60);
18499 case kSecondUTC: return Smi::FromInt((time_in_day_ms / 1000) % 60);
18500 case kMillisecondUTC: return Smi::FromInt(time_in_day_ms % 1000);
18501 case kDaysUTC: return Smi::FromInt(days);
18502 case kTimeInDayUTC: return Smi::FromInt(time_in_day_ms);
18503 default: UNREACHABLE();
18504 }
18505
18506 UNREACHABLE();
18507 }
18508
18509
18510 // static
SetValue(Handle<JSDate> date,double v)18511 Handle<Object> JSDate::SetValue(Handle<JSDate> date, double v) {
18512 Isolate* const isolate = date->GetIsolate();
18513 Handle<Object> value = isolate->factory()->NewNumber(v);
18514 bool value_is_nan = std::isnan(v);
18515 date->SetValue(*value, value_is_nan);
18516 return value;
18517 }
18518
18519
SetValue(Object * value,bool is_value_nan)18520 void JSDate::SetValue(Object* value, bool is_value_nan) {
18521 set_value(value);
18522 if (is_value_nan) {
18523 HeapNumber* nan = GetReadOnlyRoots().nan_value();
18524 set_cache_stamp(nan, SKIP_WRITE_BARRIER);
18525 set_year(nan, SKIP_WRITE_BARRIER);
18526 set_month(nan, SKIP_WRITE_BARRIER);
18527 set_day(nan, SKIP_WRITE_BARRIER);
18528 set_hour(nan, SKIP_WRITE_BARRIER);
18529 set_min(nan, SKIP_WRITE_BARRIER);
18530 set_sec(nan, SKIP_WRITE_BARRIER);
18531 set_weekday(nan, SKIP_WRITE_BARRIER);
18532 } else {
18533 set_cache_stamp(Smi::FromInt(DateCache::kInvalidStamp), SKIP_WRITE_BARRIER);
18534 }
18535 }
18536
18537
SetCachedFields(int64_t local_time_ms,DateCache * date_cache)18538 void JSDate::SetCachedFields(int64_t local_time_ms, DateCache* date_cache) {
18539 int days = DateCache::DaysFromTime(local_time_ms);
18540 int time_in_day_ms = DateCache::TimeInDay(local_time_ms, days);
18541 int year, month, day;
18542 date_cache->YearMonthDayFromDays(days, &year, &month, &day);
18543 int weekday = date_cache->Weekday(days);
18544 int hour = time_in_day_ms / (60 * 60 * 1000);
18545 int min = (time_in_day_ms / (60 * 1000)) % 60;
18546 int sec = (time_in_day_ms / 1000) % 60;
18547 set_cache_stamp(date_cache->stamp());
18548 set_year(Smi::FromInt(year), SKIP_WRITE_BARRIER);
18549 set_month(Smi::FromInt(month), SKIP_WRITE_BARRIER);
18550 set_day(Smi::FromInt(day), SKIP_WRITE_BARRIER);
18551 set_weekday(Smi::FromInt(weekday), SKIP_WRITE_BARRIER);
18552 set_hour(Smi::FromInt(hour), SKIP_WRITE_BARRIER);
18553 set_min(Smi::FromInt(min), SKIP_WRITE_BARRIER);
18554 set_sec(Smi::FromInt(sec), SKIP_WRITE_BARRIER);
18555 }
18556
GetLineNumber() const18557 int JSMessageObject::GetLineNumber() const {
18558 if (start_position() == -1) return Message::kNoLineNumberInfo;
18559
18560 Handle<Script> the_script(script(), GetIsolate());
18561
18562 Script::PositionInfo info;
18563 const Script::OffsetFlag offset_flag = Script::WITH_OFFSET;
18564 if (!Script::GetPositionInfo(the_script, start_position(), &info,
18565 offset_flag)) {
18566 return Message::kNoLineNumberInfo;
18567 }
18568
18569 return info.line + 1;
18570 }
18571
GetColumnNumber() const18572 int JSMessageObject::GetColumnNumber() const {
18573 if (start_position() == -1) return -1;
18574
18575 Handle<Script> the_script(script(), GetIsolate());
18576
18577 Script::PositionInfo info;
18578 const Script::OffsetFlag offset_flag = Script::WITH_OFFSET;
18579 if (!Script::GetPositionInfo(the_script, start_position(), &info,
18580 offset_flag)) {
18581 return -1;
18582 }
18583
18584 return info.column; // Note: No '+1' in contrast to GetLineNumber.
18585 }
18586
GetSourceLine() const18587 Handle<String> JSMessageObject::GetSourceLine() const {
18588 Isolate* isolate = GetIsolate();
18589 Handle<Script> the_script(script(), isolate);
18590
18591 if (the_script->type() == Script::TYPE_WASM) {
18592 return isolate->factory()->empty_string();
18593 }
18594
18595 Script::PositionInfo info;
18596 const Script::OffsetFlag offset_flag = Script::WITH_OFFSET;
18597 if (!Script::GetPositionInfo(the_script, start_position(), &info,
18598 offset_flag)) {
18599 return isolate->factory()->empty_string();
18600 }
18601
18602 Handle<String> src = handle(String::cast(the_script->source()), isolate);
18603 return isolate->factory()->NewSubString(src, info.line_start, info.line_end);
18604 }
18605
InvalidateEntry(Isolate * isolate,Handle<GlobalDictionary> dictionary,int entry)18606 Handle<PropertyCell> PropertyCell::InvalidateEntry(
18607 Isolate* isolate, Handle<GlobalDictionary> dictionary, int entry) {
18608 // Swap with a copy.
18609 Handle<PropertyCell> cell(dictionary->CellAt(entry), isolate);
18610 Handle<Name> name(cell->name(), isolate);
18611 Handle<PropertyCell> new_cell = isolate->factory()->NewPropertyCell(name);
18612 new_cell->set_value(cell->value());
18613 dictionary->ValueAtPut(entry, *new_cell);
18614 bool is_the_hole = cell->value()->IsTheHole(isolate);
18615 // Cell is officially mutable henceforth.
18616 PropertyDetails details = cell->property_details();
18617 details = details.set_cell_type(is_the_hole ? PropertyCellType::kUninitialized
18618 : PropertyCellType::kMutable);
18619 new_cell->set_property_details(details);
18620 // Old cell is ready for invalidation.
18621 if (is_the_hole) {
18622 cell->set_value(ReadOnlyRoots(isolate).undefined_value());
18623 } else {
18624 cell->set_value(ReadOnlyRoots(isolate).the_hole_value());
18625 }
18626 details = details.set_cell_type(PropertyCellType::kInvalidated);
18627 cell->set_property_details(details);
18628 cell->dependent_code()->DeoptimizeDependentCodeGroup(
18629 isolate, DependentCode::kPropertyCellChangedGroup);
18630 return new_cell;
18631 }
18632
18633
GetConstantType()18634 PropertyCellConstantType PropertyCell::GetConstantType() {
18635 if (value()->IsSmi()) return PropertyCellConstantType::kSmi;
18636 return PropertyCellConstantType::kStableMap;
18637 }
18638
18639
RemainsConstantType(Handle<PropertyCell> cell,Handle<Object> value)18640 static bool RemainsConstantType(Handle<PropertyCell> cell,
18641 Handle<Object> value) {
18642 // TODO(dcarney): double->smi and smi->double transition from kConstant
18643 if (cell->value()->IsSmi() && value->IsSmi()) {
18644 return true;
18645 } else if (cell->value()->IsHeapObject() && value->IsHeapObject()) {
18646 return HeapObject::cast(cell->value())->map() ==
18647 HeapObject::cast(*value)->map() &&
18648 HeapObject::cast(*value)->map()->is_stable();
18649 }
18650 return false;
18651 }
18652
UpdatedType(Isolate * isolate,Handle<PropertyCell> cell,Handle<Object> value,PropertyDetails details)18653 PropertyCellType PropertyCell::UpdatedType(Isolate* isolate,
18654 Handle<PropertyCell> cell,
18655 Handle<Object> value,
18656 PropertyDetails details) {
18657 PropertyCellType type = details.cell_type();
18658 DCHECK(!value->IsTheHole(isolate));
18659 if (cell->value()->IsTheHole(isolate)) {
18660 switch (type) {
18661 // Only allow a cell to transition once into constant state.
18662 case PropertyCellType::kUninitialized:
18663 if (value->IsUndefined(isolate)) return PropertyCellType::kUndefined;
18664 return PropertyCellType::kConstant;
18665 case PropertyCellType::kInvalidated:
18666 return PropertyCellType::kMutable;
18667 default:
18668 UNREACHABLE();
18669 }
18670 }
18671 switch (type) {
18672 case PropertyCellType::kUndefined:
18673 return PropertyCellType::kConstant;
18674 case PropertyCellType::kConstant:
18675 if (*value == cell->value()) return PropertyCellType::kConstant;
18676 V8_FALLTHROUGH;
18677 case PropertyCellType::kConstantType:
18678 if (RemainsConstantType(cell, value)) {
18679 return PropertyCellType::kConstantType;
18680 }
18681 V8_FALLTHROUGH;
18682 case PropertyCellType::kMutable:
18683 return PropertyCellType::kMutable;
18684 }
18685 UNREACHABLE();
18686 }
18687
PrepareForValue(Isolate * isolate,Handle<GlobalDictionary> dictionary,int entry,Handle<Object> value,PropertyDetails details)18688 Handle<PropertyCell> PropertyCell::PrepareForValue(
18689 Isolate* isolate, Handle<GlobalDictionary> dictionary, int entry,
18690 Handle<Object> value, PropertyDetails details) {
18691 DCHECK(!value->IsTheHole(isolate));
18692 Handle<PropertyCell> cell(dictionary->CellAt(entry), isolate);
18693 const PropertyDetails original_details = cell->property_details();
18694 // Data accesses could be cached in ics or optimized code.
18695 bool invalidate =
18696 (original_details.kind() == kData && details.kind() == kAccessor) ||
18697 (!original_details.IsReadOnly() && details.IsReadOnly());
18698 int index;
18699 PropertyCellType old_type = original_details.cell_type();
18700 // Preserve the enumeration index unless the property was deleted or never
18701 // initialized.
18702 if (cell->value()->IsTheHole(isolate)) {
18703 index = dictionary->NextEnumerationIndex();
18704 dictionary->SetNextEnumerationIndex(index + 1);
18705 } else {
18706 index = original_details.dictionary_index();
18707 }
18708 DCHECK_LT(0, index);
18709 details = details.set_index(index);
18710
18711 PropertyCellType new_type =
18712 UpdatedType(isolate, cell, value, original_details);
18713 if (invalidate) {
18714 cell = PropertyCell::InvalidateEntry(isolate, dictionary, entry);
18715 }
18716
18717 // Install new property details.
18718 details = details.set_cell_type(new_type);
18719 cell->set_property_details(details);
18720
18721 if (new_type == PropertyCellType::kConstant ||
18722 new_type == PropertyCellType::kConstantType) {
18723 // Store the value now to ensure that the cell contains the constant or
18724 // type information. Otherwise subsequent store operation will turn
18725 // the cell to mutable.
18726 cell->set_value(*value);
18727 }
18728
18729 // Deopt when transitioning from a constant type.
18730 if (!invalidate && (old_type != new_type ||
18731 original_details.IsReadOnly() != details.IsReadOnly())) {
18732 cell->dependent_code()->DeoptimizeDependentCodeGroup(
18733 isolate, DependentCode::kPropertyCellChangedGroup);
18734 }
18735 return cell;
18736 }
18737
18738
18739 // static
SetValueWithInvalidation(Isolate * isolate,Handle<PropertyCell> cell,Handle<Object> new_value)18740 void PropertyCell::SetValueWithInvalidation(Isolate* isolate,
18741 Handle<PropertyCell> cell,
18742 Handle<Object> new_value) {
18743 if (cell->value() != *new_value) {
18744 cell->set_value(*new_value);
18745 cell->dependent_code()->DeoptimizeDependentCodeGroup(
18746 isolate, DependentCode::kPropertyCellChangedGroup);
18747 }
18748 }
18749
source_position() const18750 int JSGeneratorObject::source_position() const {
18751 CHECK(is_suspended());
18752 DCHECK(function()->shared()->HasBytecodeArray());
18753
18754 int code_offset = Smi::ToInt(input_or_debug_pos());
18755
18756 // The stored bytecode offset is relative to a different base than what
18757 // is used in the source position table, hence the subtraction.
18758 code_offset -= BytecodeArray::kHeaderSize - kHeapObjectTag;
18759 AbstractCode* code =
18760 AbstractCode::cast(function()->shared()->GetBytecodeArray());
18761 return code->SourcePosition(code_offset);
18762 }
18763
18764 // static
Get(Isolate * isolate,Handle<JSObject> receiver)18765 AccessCheckInfo* AccessCheckInfo::Get(Isolate* isolate,
18766 Handle<JSObject> receiver) {
18767 DisallowHeapAllocation no_gc;
18768 DCHECK(receiver->map()->is_access_check_needed());
18769 Object* maybe_constructor = receiver->map()->GetConstructor();
18770 if (maybe_constructor->IsFunctionTemplateInfo()) {
18771 Object* data_obj =
18772 FunctionTemplateInfo::cast(maybe_constructor)->access_check_info();
18773 if (data_obj->IsUndefined(isolate)) return nullptr;
18774 return AccessCheckInfo::cast(data_obj);
18775 }
18776 // Might happen for a detached context.
18777 if (!maybe_constructor->IsJSFunction()) return nullptr;
18778 JSFunction* constructor = JSFunction::cast(maybe_constructor);
18779 // Might happen for the debug context.
18780 if (!constructor->shared()->IsApiFunction()) return nullptr;
18781
18782 Object* data_obj =
18783 constructor->shared()->get_api_func_data()->access_check_info();
18784 if (data_obj->IsUndefined(isolate)) return nullptr;
18785
18786 return AccessCheckInfo::cast(data_obj);
18787 }
18788
HasProxyInPrototype(Isolate * isolate)18789 bool JSReceiver::HasProxyInPrototype(Isolate* isolate) {
18790 for (PrototypeIterator iter(isolate, this, kStartAtReceiver,
18791 PrototypeIterator::END_AT_NULL);
18792 !iter.IsAtEnd(); iter.AdvanceIgnoringProxies()) {
18793 if (iter.GetCurrent<Object>()->IsJSProxy()) return true;
18794 }
18795 return false;
18796 }
18797
HasComplexElements()18798 bool JSReceiver::HasComplexElements() {
18799 if (IsJSProxy()) return true;
18800 JSObject* this_object = JSObject::cast(this);
18801 if (this_object->HasIndexedInterceptor()) {
18802 return true;
18803 }
18804 if (!this_object->HasDictionaryElements()) return false;
18805 return this_object->element_dictionary()->HasComplexElements();
18806 }
18807
TryGetCachedPropertyName(Isolate * isolate,Handle<Object> getter)18808 MaybeHandle<Name> FunctionTemplateInfo::TryGetCachedPropertyName(
18809 Isolate* isolate, Handle<Object> getter) {
18810 if (getter->IsFunctionTemplateInfo()) {
18811 Handle<FunctionTemplateInfo> fti =
18812 Handle<FunctionTemplateInfo>::cast(getter);
18813 // Check if the accessor uses a cached property.
18814 if (!fti->cached_property_name()->IsTheHole(isolate)) {
18815 return handle(Name::cast(fti->cached_property_name()), isolate);
18816 }
18817 }
18818 return MaybeHandle<Name>();
18819 }
18820
18821 // Force instantiation of template instances class.
18822 // Please note this list is compiler dependent.
18823 // Keep this at the end of this file
18824
18825 template class HashTable<StringTable, StringTableShape>;
18826
18827 template class HashTable<CompilationCacheTable, CompilationCacheShape>;
18828
18829 template class HashTable<ObjectHashTable, ObjectHashTableShape>;
18830
18831 template class HashTable<EphemeronHashTable, EphemeronHashTableShape>;
18832
18833 template class ObjectHashTableBase<ObjectHashTable, ObjectHashTableShape>;
18834
18835 template class ObjectHashTableBase<EphemeronHashTable, EphemeronHashTableShape>;
18836
18837 template class Dictionary<NameDictionary, NameDictionaryShape>;
18838
18839 template class Dictionary<GlobalDictionary, GlobalDictionaryShape>;
18840
18841 template class EXPORT_TEMPLATE_DEFINE(
18842 V8_EXPORT_PRIVATE) HashTable<NumberDictionary, NumberDictionaryShape>;
18843
18844 template class EXPORT_TEMPLATE_DEFINE(V8_EXPORT_PRIVATE)
18845 Dictionary<NumberDictionary, NumberDictionaryShape>;
18846
18847 template class EXPORT_TEMPLATE_DEFINE(V8_EXPORT_PRIVATE)
18848 HashTable<SimpleNumberDictionary, SimpleNumberDictionaryShape>;
18849
18850 template class EXPORT_TEMPLATE_DEFINE(V8_EXPORT_PRIVATE)
18851 Dictionary<SimpleNumberDictionary, SimpleNumberDictionaryShape>;
18852
18853 template Handle<NameDictionary>
18854 BaseNameDictionary<NameDictionary, NameDictionaryShape>::New(
18855 Isolate*, int n, PretenureFlag pretenure, MinimumCapacity capacity_option);
18856
18857 template Handle<GlobalDictionary>
18858 BaseNameDictionary<GlobalDictionary, GlobalDictionaryShape>::New(
18859 Isolate*, int n, PretenureFlag pretenure, MinimumCapacity capacity_option);
18860
18861 template Handle<NameDictionary>
18862 HashTable<NameDictionary, NameDictionaryShape>::New(Isolate*, int,
18863 PretenureFlag,
18864 MinimumCapacity);
18865
18866 template Handle<ObjectHashSet>
18867 HashTable<ObjectHashSet, ObjectHashSetShape>::New(Isolate*, int n,
18868 PretenureFlag,
18869 MinimumCapacity);
18870
18871 template Handle<NameDictionary>
18872 HashTable<NameDictionary, NameDictionaryShape>::Shrink(Isolate* isolate,
18873 Handle<NameDictionary>,
18874 int additionalCapacity);
18875
18876 template Handle<NameDictionary>
18877 BaseNameDictionary<NameDictionary, NameDictionaryShape>::Add(
18878 Isolate* isolate, Handle<NameDictionary>, Handle<Name>, Handle<Object>,
18879 PropertyDetails, int*);
18880
18881 template Handle<GlobalDictionary>
18882 BaseNameDictionary<GlobalDictionary, GlobalDictionaryShape>::Add(
18883 Isolate* isolate, Handle<GlobalDictionary>, Handle<Name>, Handle<Object>,
18884 PropertyDetails, int*);
18885
18886 template void HashTable<GlobalDictionary, GlobalDictionaryShape>::Rehash(
18887 Isolate* isolate);
18888
18889 template Handle<NameDictionary>
18890 BaseNameDictionary<NameDictionary, NameDictionaryShape>::EnsureCapacity(
18891 Isolate* isolate, Handle<NameDictionary>, int);
18892
18893 template void
18894 BaseNameDictionary<GlobalDictionary, GlobalDictionaryShape>::CopyEnumKeysTo(
18895 Isolate* isolate, Handle<GlobalDictionary> dictionary,
18896 Handle<FixedArray> storage, KeyCollectionMode mode,
18897 KeyAccumulator* accumulator);
18898
18899 template void
18900 BaseNameDictionary<NameDictionary, NameDictionaryShape>::CopyEnumKeysTo(
18901 Isolate* isolate, Handle<NameDictionary> dictionary,
18902 Handle<FixedArray> storage, KeyCollectionMode mode,
18903 KeyAccumulator* accumulator);
18904
18905 template Handle<FixedArray>
18906 BaseNameDictionary<GlobalDictionary, GlobalDictionaryShape>::IterationIndices(
18907 Isolate* isolate, Handle<GlobalDictionary> dictionary);
18908 template void
18909 BaseNameDictionary<GlobalDictionary, GlobalDictionaryShape>::CollectKeysTo(
18910 Handle<GlobalDictionary> dictionary, KeyAccumulator* keys);
18911
18912 template Handle<FixedArray>
18913 BaseNameDictionary<NameDictionary, NameDictionaryShape>::IterationIndices(
18914 Isolate* isolate, Handle<NameDictionary> dictionary);
18915 template void
18916 BaseNameDictionary<NameDictionary, NameDictionaryShape>::CollectKeysTo(
18917 Handle<NameDictionary> dictionary, KeyAccumulator* keys);
18918
18919 } // namespace internal
18920 } // namespace v8
18921