1 // Copyright 2015 the V8 project authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "src/objects.h"
6
7 #include <cmath>
8 #include <iomanip>
9 #include <memory>
10 #include <sstream>
11 #include <unordered_map>
12 #include <unordered_set>
13
14 #include "src/objects-inl.h"
15
16 #include "src/accessors.h"
17 #include "src/allocation-site-scopes.h"
18 #include "src/api-arguments-inl.h"
19 #include "src/api-natives.h"
20 #include "src/api.h"
21 #include "src/base/bits.h"
22 #include "src/base/utils/random-number-generator.h"
23 #include "src/bootstrapper.h"
24 #include "src/code-stubs.h"
25 #include "src/codegen.h"
26 #include "src/compilation-dependencies.h"
27 #include "src/compiler.h"
28 #include "src/counters-inl.h"
29 #include "src/counters.h"
30 #include "src/date.h"
31 #include "src/debug/debug.h"
32 #include "src/deoptimizer.h"
33 #include "src/elements.h"
34 #include "src/execution.h"
35 #include "src/field-index-inl.h"
36 #include "src/field-index.h"
37 #include "src/field-type.h"
38 #include "src/frames-inl.h"
39 #include "src/full-codegen/full-codegen.h"
40 #include "src/globals.h"
41 #include "src/ic/ic.h"
42 #include "src/identity-map.h"
43 #include "src/interpreter/bytecode-array-iterator.h"
44 #include "src/interpreter/bytecode-decoder.h"
45 #include "src/interpreter/interpreter.h"
46 #include "src/isolate-inl.h"
47 #include "src/keys.h"
48 #include "src/list.h"
49 #include "src/log.h"
50 #include "src/lookup.h"
51 #include "src/macro-assembler.h"
52 #include "src/messages.h"
53 #include "src/objects-body-descriptors-inl.h"
54 #include "src/property-descriptor.h"
55 #include "src/prototype.h"
56 #include "src/regexp/jsregexp.h"
57 #include "src/safepoint-table.h"
58 #include "src/snapshot/code-serializer.h"
59 #include "src/source-position-table.h"
60 #include "src/string-builder.h"
61 #include "src/string-search.h"
62 #include "src/string-stream.h"
63 #include "src/utils.h"
64 #include "src/wasm/wasm-module.h"
65 #include "src/wasm/wasm-objects.h"
66 #include "src/zone/zone.h"
67
68 #ifdef ENABLE_DISASSEMBLER
69 #include "src/disasm.h"
70 #include "src/disassembler.h"
71 #include "src/eh-frame.h"
72 #endif
73
74 namespace v8 {
75 namespace internal {
76
operator <<(std::ostream & os,InstanceType instance_type)77 std::ostream& operator<<(std::ostream& os, InstanceType instance_type) {
78 switch (instance_type) {
79 #define WRITE_TYPE(TYPE) \
80 case TYPE: \
81 return os << #TYPE;
82 INSTANCE_TYPE_LIST(WRITE_TYPE)
83 #undef WRITE_TYPE
84 }
85 UNREACHABLE();
86 return os << "UNKNOWN"; // Keep the compiler happy.
87 }
88
OptimalType(Isolate * isolate,Representation representation)89 Handle<FieldType> Object::OptimalType(Isolate* isolate,
90 Representation representation) {
91 if (representation.IsNone()) return FieldType::None(isolate);
92 if (FLAG_track_field_types) {
93 if (representation.IsHeapObject() && IsHeapObject()) {
94 // We can track only JavaScript objects with stable maps.
95 Handle<Map> map(HeapObject::cast(this)->map(), isolate);
96 if (map->is_stable() && map->IsJSReceiverMap()) {
97 return FieldType::Class(map, isolate);
98 }
99 }
100 }
101 return FieldType::Any(isolate);
102 }
103
104
ToObject(Isolate * isolate,Handle<Object> object,Handle<Context> native_context)105 MaybeHandle<JSReceiver> Object::ToObject(Isolate* isolate,
106 Handle<Object> object,
107 Handle<Context> native_context) {
108 if (object->IsJSReceiver()) return Handle<JSReceiver>::cast(object);
109 Handle<JSFunction> constructor;
110 if (object->IsSmi()) {
111 constructor = handle(native_context->number_function(), isolate);
112 } else {
113 int constructor_function_index =
114 Handle<HeapObject>::cast(object)->map()->GetConstructorFunctionIndex();
115 if (constructor_function_index == Map::kNoConstructorFunctionIndex) {
116 THROW_NEW_ERROR(isolate,
117 NewTypeError(MessageTemplate::kUndefinedOrNullToObject),
118 JSReceiver);
119 }
120 constructor = handle(
121 JSFunction::cast(native_context->get(constructor_function_index)),
122 isolate);
123 }
124 Handle<JSObject> result = isolate->factory()->NewJSObject(constructor);
125 Handle<JSValue>::cast(result)->set_value(*object);
126 return result;
127 }
128
129 // ES6 section 9.2.1.2, OrdinaryCallBindThis for sloppy callee.
130 // static
ConvertReceiver(Isolate * isolate,Handle<Object> object)131 MaybeHandle<JSReceiver> Object::ConvertReceiver(Isolate* isolate,
132 Handle<Object> object) {
133 if (object->IsJSReceiver()) return Handle<JSReceiver>::cast(object);
134 if (*object == isolate->heap()->null_value() ||
135 object->IsUndefined(isolate)) {
136 return isolate->global_proxy();
137 }
138 return Object::ToObject(isolate, object);
139 }
140
141 // static
ToNumber(Handle<Object> input)142 MaybeHandle<Object> Object::ToNumber(Handle<Object> input) {
143 while (true) {
144 if (input->IsNumber()) {
145 return input;
146 }
147 if (input->IsString()) {
148 return String::ToNumber(Handle<String>::cast(input));
149 }
150 if (input->IsOddball()) {
151 return Oddball::ToNumber(Handle<Oddball>::cast(input));
152 }
153 Isolate* const isolate = Handle<HeapObject>::cast(input)->GetIsolate();
154 if (input->IsSymbol()) {
155 THROW_NEW_ERROR(isolate, NewTypeError(MessageTemplate::kSymbolToNumber),
156 Object);
157 }
158 if (input->IsSimd128Value()) {
159 THROW_NEW_ERROR(isolate, NewTypeError(MessageTemplate::kSimdToNumber),
160 Object);
161 }
162 ASSIGN_RETURN_ON_EXCEPTION(
163 isolate, input, JSReceiver::ToPrimitive(Handle<JSReceiver>::cast(input),
164 ToPrimitiveHint::kNumber),
165 Object);
166 }
167 }
168
169
170 // static
ToInteger(Isolate * isolate,Handle<Object> input)171 MaybeHandle<Object> Object::ToInteger(Isolate* isolate, Handle<Object> input) {
172 ASSIGN_RETURN_ON_EXCEPTION(isolate, input, ToNumber(input), Object);
173 return isolate->factory()->NewNumber(DoubleToInteger(input->Number()));
174 }
175
176
177 // static
ToInt32(Isolate * isolate,Handle<Object> input)178 MaybeHandle<Object> Object::ToInt32(Isolate* isolate, Handle<Object> input) {
179 ASSIGN_RETURN_ON_EXCEPTION(isolate, input, ToNumber(input), Object);
180 return isolate->factory()->NewNumberFromInt(DoubleToInt32(input->Number()));
181 }
182
183
184 // static
ToUint32(Isolate * isolate,Handle<Object> input)185 MaybeHandle<Object> Object::ToUint32(Isolate* isolate, Handle<Object> input) {
186 ASSIGN_RETURN_ON_EXCEPTION(isolate, input, ToNumber(input), Object);
187 return isolate->factory()->NewNumberFromUint(DoubleToUint32(input->Number()));
188 }
189
190
191 // static
ConvertToName(Isolate * isolate,Handle<Object> input)192 MaybeHandle<Name> Object::ConvertToName(Isolate* isolate,
193 Handle<Object> input) {
194 ASSIGN_RETURN_ON_EXCEPTION(
195 isolate, input, Object::ToPrimitive(input, ToPrimitiveHint::kString),
196 Name);
197 if (input->IsName()) return Handle<Name>::cast(input);
198 return ToString(isolate, input);
199 }
200
201 // static
ToString(Isolate * isolate,Handle<Object> input)202 MaybeHandle<String> Object::ToString(Isolate* isolate, Handle<Object> input) {
203 while (true) {
204 if (input->IsString()) {
205 return Handle<String>::cast(input);
206 }
207 if (input->IsOddball()) {
208 return handle(Handle<Oddball>::cast(input)->to_string(), isolate);
209 }
210 if (input->IsNumber()) {
211 return isolate->factory()->NumberToString(input);
212 }
213 if (input->IsSymbol()) {
214 THROW_NEW_ERROR(isolate, NewTypeError(MessageTemplate::kSymbolToString),
215 String);
216 }
217 if (input->IsSimd128Value()) {
218 return Simd128Value::ToString(Handle<Simd128Value>::cast(input));
219 }
220 ASSIGN_RETURN_ON_EXCEPTION(
221 isolate, input, JSReceiver::ToPrimitive(Handle<JSReceiver>::cast(input),
222 ToPrimitiveHint::kString),
223 String);
224 }
225 }
226
227 namespace {
228
IsErrorObject(Isolate * isolate,Handle<Object> object)229 bool IsErrorObject(Isolate* isolate, Handle<Object> object) {
230 if (!object->IsJSReceiver()) return false;
231 Handle<Symbol> symbol = isolate->factory()->stack_trace_symbol();
232 return JSReceiver::HasOwnProperty(Handle<JSReceiver>::cast(object), symbol)
233 .FromMaybe(false);
234 }
235
AsStringOrEmpty(Isolate * isolate,Handle<Object> object)236 Handle<String> AsStringOrEmpty(Isolate* isolate, Handle<Object> object) {
237 return object->IsString() ? Handle<String>::cast(object)
238 : isolate->factory()->empty_string();
239 }
240
NoSideEffectsErrorToString(Isolate * isolate,Handle<Object> input)241 Handle<String> NoSideEffectsErrorToString(Isolate* isolate,
242 Handle<Object> input) {
243 Handle<JSReceiver> receiver = Handle<JSReceiver>::cast(input);
244
245 Handle<Name> name_key = isolate->factory()->name_string();
246 Handle<Object> name = JSReceiver::GetDataProperty(receiver, name_key);
247 Handle<String> name_str = AsStringOrEmpty(isolate, name);
248
249 Handle<Name> msg_key = isolate->factory()->message_string();
250 Handle<Object> msg = JSReceiver::GetDataProperty(receiver, msg_key);
251 Handle<String> msg_str = AsStringOrEmpty(isolate, msg);
252
253 if (name_str->length() == 0) return msg_str;
254 if (msg_str->length() == 0) return name_str;
255
256 IncrementalStringBuilder builder(isolate);
257 builder.AppendString(name_str);
258 builder.AppendCString(": ");
259 builder.AppendString(msg_str);
260
261 return builder.Finish().ToHandleChecked();
262 }
263
264 } // namespace
265
266 // static
NoSideEffectsToString(Isolate * isolate,Handle<Object> input)267 Handle<String> Object::NoSideEffectsToString(Isolate* isolate,
268 Handle<Object> input) {
269 DisallowJavascriptExecution no_js(isolate);
270
271 if (input->IsString() || input->IsNumber() || input->IsOddball() ||
272 input->IsSimd128Value()) {
273 return Object::ToString(isolate, input).ToHandleChecked();
274 } else if (input->IsFunction()) {
275 // -- F u n c t i o n
276 Handle<String> fun_str;
277 if (input->IsJSBoundFunction()) {
278 fun_str = JSBoundFunction::ToString(Handle<JSBoundFunction>::cast(input));
279 } else {
280 DCHECK(input->IsJSFunction());
281 fun_str = JSFunction::ToString(Handle<JSFunction>::cast(input));
282 }
283
284 if (fun_str->length() > 128) {
285 IncrementalStringBuilder builder(isolate);
286 builder.AppendString(isolate->factory()->NewSubString(fun_str, 0, 111));
287 builder.AppendCString("...<omitted>...");
288 builder.AppendString(isolate->factory()->NewSubString(
289 fun_str, fun_str->length() - 2, fun_str->length()));
290
291 return builder.Finish().ToHandleChecked();
292 }
293 return fun_str;
294 } else if (input->IsSymbol()) {
295 // -- S y m b o l
296 Handle<Symbol> symbol = Handle<Symbol>::cast(input);
297
298 IncrementalStringBuilder builder(isolate);
299 builder.AppendCString("Symbol(");
300 if (symbol->name()->IsString()) {
301 builder.AppendString(handle(String::cast(symbol->name()), isolate));
302 }
303 builder.AppendCharacter(')');
304
305 return builder.Finish().ToHandleChecked();
306 } else if (input->IsJSReceiver()) {
307 // -- J S R e c e i v e r
308 Handle<JSReceiver> receiver = Handle<JSReceiver>::cast(input);
309 Handle<Object> to_string = JSReceiver::GetDataProperty(
310 receiver, isolate->factory()->toString_string());
311
312 if (IsErrorObject(isolate, input) ||
313 *to_string == *isolate->error_to_string()) {
314 // When internally formatting error objects, use a side-effects-free
315 // version of Error.prototype.toString independent of the actually
316 // installed toString method.
317 return NoSideEffectsErrorToString(isolate, input);
318 } else if (*to_string == *isolate->object_to_string()) {
319 Handle<Object> ctor = JSReceiver::GetDataProperty(
320 receiver, isolate->factory()->constructor_string());
321 if (ctor->IsFunction()) {
322 Handle<String> ctor_name;
323 if (ctor->IsJSBoundFunction()) {
324 ctor_name = JSBoundFunction::GetName(
325 isolate, Handle<JSBoundFunction>::cast(ctor))
326 .ToHandleChecked();
327 } else if (ctor->IsJSFunction()) {
328 Handle<Object> ctor_name_obj =
329 JSFunction::GetName(isolate, Handle<JSFunction>::cast(ctor));
330 ctor_name = AsStringOrEmpty(isolate, ctor_name_obj);
331 }
332
333 if (ctor_name->length() != 0) {
334 IncrementalStringBuilder builder(isolate);
335 builder.AppendCString("#<");
336 builder.AppendString(ctor_name);
337 builder.AppendCString(">");
338
339 return builder.Finish().ToHandleChecked();
340 }
341 }
342 }
343 }
344
345 // At this point, input is either none of the above or a JSReceiver.
346
347 Handle<JSReceiver> receiver;
348 if (input->IsJSReceiver()) {
349 receiver = Handle<JSReceiver>::cast(input);
350 } else {
351 // This is the only case where Object::ToObject throws.
352 DCHECK(!input->IsSmi());
353 int constructor_function_index =
354 Handle<HeapObject>::cast(input)->map()->GetConstructorFunctionIndex();
355 if (constructor_function_index == Map::kNoConstructorFunctionIndex) {
356 return isolate->factory()->NewStringFromAsciiChecked("[object Unknown]");
357 }
358
359 receiver = Object::ToObject(isolate, input, isolate->native_context())
360 .ToHandleChecked();
361 }
362
363 Handle<String> builtin_tag = handle(receiver->class_name(), isolate);
364 Handle<Object> tag_obj = JSReceiver::GetDataProperty(
365 receiver, isolate->factory()->to_string_tag_symbol());
366 Handle<String> tag =
367 tag_obj->IsString() ? Handle<String>::cast(tag_obj) : builtin_tag;
368
369 IncrementalStringBuilder builder(isolate);
370 builder.AppendCString("[object ");
371 builder.AppendString(tag);
372 builder.AppendCString("]");
373
374 return builder.Finish().ToHandleChecked();
375 }
376
377 // static
ToLength(Isolate * isolate,Handle<Object> input)378 MaybeHandle<Object> Object::ToLength(Isolate* isolate, Handle<Object> input) {
379 ASSIGN_RETURN_ON_EXCEPTION(isolate, input, ToNumber(input), Object);
380 double len = DoubleToInteger(input->Number());
381 if (len <= 0.0) {
382 len = 0.0;
383 } else if (len >= kMaxSafeInteger) {
384 len = kMaxSafeInteger;
385 }
386 return isolate->factory()->NewNumber(len);
387 }
388
389 // static
ToIndex(Isolate * isolate,Handle<Object> input,MessageTemplate::Template error_index)390 MaybeHandle<Object> Object::ToIndex(Isolate* isolate, Handle<Object> input,
391 MessageTemplate::Template error_index) {
392 if (input->IsUndefined(isolate)) return isolate->factory()->NewNumber(0.0);
393 ASSIGN_RETURN_ON_EXCEPTION(isolate, input, ToNumber(input), Object);
394 double len = DoubleToInteger(input->Number()) + 0.0;
395 auto js_len = isolate->factory()->NewNumber(len);
396 if (len < 0.0 || len > kMaxSafeInteger) {
397 THROW_NEW_ERROR(isolate, NewRangeError(error_index, js_len), Object);
398 }
399 return js_len;
400 }
401
BooleanValue()402 bool Object::BooleanValue() {
403 if (IsSmi()) return Smi::cast(this)->value() != 0;
404 DCHECK(IsHeapObject());
405 Isolate* isolate = HeapObject::cast(this)->GetIsolate();
406 if (IsBoolean()) return IsTrue(isolate);
407 if (IsUndefined(isolate) || IsNull(isolate)) return false;
408 if (IsUndetectable()) return false; // Undetectable object is false.
409 if (IsString()) return String::cast(this)->length() != 0;
410 if (IsHeapNumber()) return HeapNumber::cast(this)->HeapNumberBooleanValue();
411 return true;
412 }
413
414
415 namespace {
416
417 // TODO(bmeurer): Maybe we should introduce a marker interface Number,
418 // where we put all these methods at some point?
NumberCompare(double x,double y)419 ComparisonResult NumberCompare(double x, double y) {
420 if (std::isnan(x) || std::isnan(y)) {
421 return ComparisonResult::kUndefined;
422 } else if (x < y) {
423 return ComparisonResult::kLessThan;
424 } else if (x > y) {
425 return ComparisonResult::kGreaterThan;
426 } else {
427 return ComparisonResult::kEqual;
428 }
429 }
430
431
NumberEquals(double x,double y)432 bool NumberEquals(double x, double y) {
433 // Must check explicitly for NaN's on Windows, but -0 works fine.
434 if (std::isnan(x)) return false;
435 if (std::isnan(y)) return false;
436 return x == y;
437 }
438
439
NumberEquals(const Object * x,const Object * y)440 bool NumberEquals(const Object* x, const Object* y) {
441 return NumberEquals(x->Number(), y->Number());
442 }
443
444
NumberEquals(Handle<Object> x,Handle<Object> y)445 bool NumberEquals(Handle<Object> x, Handle<Object> y) {
446 return NumberEquals(*x, *y);
447 }
448
449 } // namespace
450
451
452 // static
Compare(Handle<Object> x,Handle<Object> y)453 Maybe<ComparisonResult> Object::Compare(Handle<Object> x, Handle<Object> y) {
454 // ES6 section 7.2.11 Abstract Relational Comparison step 3 and 4.
455 if (!Object::ToPrimitive(x, ToPrimitiveHint::kNumber).ToHandle(&x) ||
456 !Object::ToPrimitive(y, ToPrimitiveHint::kNumber).ToHandle(&y)) {
457 return Nothing<ComparisonResult>();
458 }
459 if (x->IsString() && y->IsString()) {
460 // ES6 section 7.2.11 Abstract Relational Comparison step 5.
461 return Just(
462 String::Compare(Handle<String>::cast(x), Handle<String>::cast(y)));
463 }
464 // ES6 section 7.2.11 Abstract Relational Comparison step 6.
465 if (!Object::ToNumber(x).ToHandle(&x) || !Object::ToNumber(y).ToHandle(&y)) {
466 return Nothing<ComparisonResult>();
467 }
468 return Just(NumberCompare(x->Number(), y->Number()));
469 }
470
471
472 // static
Equals(Handle<Object> x,Handle<Object> y)473 Maybe<bool> Object::Equals(Handle<Object> x, Handle<Object> y) {
474 // This is the generic version of Abstract Equality Comparison; a version in
475 // JavaScript land is available in the EqualStub and NotEqualStub. Whenever
476 // you change something functionality wise in here, remember to update the
477 // TurboFan code stubs as well.
478 while (true) {
479 if (x->IsNumber()) {
480 if (y->IsNumber()) {
481 return Just(NumberEquals(x, y));
482 } else if (y->IsBoolean()) {
483 return Just(NumberEquals(*x, Handle<Oddball>::cast(y)->to_number()));
484 } else if (y->IsString()) {
485 return Just(NumberEquals(x, String::ToNumber(Handle<String>::cast(y))));
486 } else if (y->IsJSReceiver()) {
487 if (!JSReceiver::ToPrimitive(Handle<JSReceiver>::cast(y))
488 .ToHandle(&y)) {
489 return Nothing<bool>();
490 }
491 } else {
492 return Just(false);
493 }
494 } else if (x->IsString()) {
495 if (y->IsString()) {
496 return Just(
497 String::Equals(Handle<String>::cast(x), Handle<String>::cast(y)));
498 } else if (y->IsNumber()) {
499 x = String::ToNumber(Handle<String>::cast(x));
500 return Just(NumberEquals(x, y));
501 } else if (y->IsBoolean()) {
502 x = String::ToNumber(Handle<String>::cast(x));
503 return Just(NumberEquals(*x, Handle<Oddball>::cast(y)->to_number()));
504 } else if (y->IsJSReceiver()) {
505 if (!JSReceiver::ToPrimitive(Handle<JSReceiver>::cast(y))
506 .ToHandle(&y)) {
507 return Nothing<bool>();
508 }
509 } else {
510 return Just(false);
511 }
512 } else if (x->IsBoolean()) {
513 if (y->IsOddball()) {
514 return Just(x.is_identical_to(y));
515 } else if (y->IsNumber()) {
516 return Just(NumberEquals(Handle<Oddball>::cast(x)->to_number(), *y));
517 } else if (y->IsString()) {
518 y = String::ToNumber(Handle<String>::cast(y));
519 return Just(NumberEquals(Handle<Oddball>::cast(x)->to_number(), *y));
520 } else if (y->IsJSReceiver()) {
521 if (!JSReceiver::ToPrimitive(Handle<JSReceiver>::cast(y))
522 .ToHandle(&y)) {
523 return Nothing<bool>();
524 }
525 x = Oddball::ToNumber(Handle<Oddball>::cast(x));
526 } else {
527 return Just(false);
528 }
529 } else if (x->IsSymbol()) {
530 if (y->IsSymbol()) {
531 return Just(x.is_identical_to(y));
532 } else if (y->IsJSReceiver()) {
533 if (!JSReceiver::ToPrimitive(Handle<JSReceiver>::cast(y))
534 .ToHandle(&y)) {
535 return Nothing<bool>();
536 }
537 } else {
538 return Just(false);
539 }
540 } else if (x->IsSimd128Value()) {
541 if (y->IsSimd128Value()) {
542 return Just(Simd128Value::Equals(Handle<Simd128Value>::cast(x),
543 Handle<Simd128Value>::cast(y)));
544 } else if (y->IsJSReceiver()) {
545 if (!JSReceiver::ToPrimitive(Handle<JSReceiver>::cast(y))
546 .ToHandle(&y)) {
547 return Nothing<bool>();
548 }
549 } else {
550 return Just(false);
551 }
552 } else if (x->IsJSReceiver()) {
553 if (y->IsJSReceiver()) {
554 return Just(x.is_identical_to(y));
555 } else if (y->IsUndetectable()) {
556 return Just(x->IsUndetectable());
557 } else if (y->IsBoolean()) {
558 y = Oddball::ToNumber(Handle<Oddball>::cast(y));
559 } else if (!JSReceiver::ToPrimitive(Handle<JSReceiver>::cast(x))
560 .ToHandle(&x)) {
561 return Nothing<bool>();
562 }
563 } else {
564 return Just(x->IsUndetectable() && y->IsUndetectable());
565 }
566 }
567 }
568
569
StrictEquals(Object * that)570 bool Object::StrictEquals(Object* that) {
571 if (this->IsNumber()) {
572 if (!that->IsNumber()) return false;
573 return NumberEquals(this, that);
574 } else if (this->IsString()) {
575 if (!that->IsString()) return false;
576 return String::cast(this)->Equals(String::cast(that));
577 } else if (this->IsSimd128Value()) {
578 if (!that->IsSimd128Value()) return false;
579 return Simd128Value::cast(this)->Equals(Simd128Value::cast(that));
580 }
581 return this == that;
582 }
583
584
585 // static
TypeOf(Isolate * isolate,Handle<Object> object)586 Handle<String> Object::TypeOf(Isolate* isolate, Handle<Object> object) {
587 if (object->IsNumber()) return isolate->factory()->number_string();
588 if (object->IsOddball()) return handle(Oddball::cast(*object)->type_of());
589 if (object->IsUndetectable()) {
590 return isolate->factory()->undefined_string();
591 }
592 if (object->IsString()) return isolate->factory()->string_string();
593 if (object->IsSymbol()) return isolate->factory()->symbol_string();
594 if (object->IsString()) return isolate->factory()->string_string();
595 #define SIMD128_TYPE(TYPE, Type, type, lane_count, lane_type) \
596 if (object->Is##Type()) return isolate->factory()->type##_string();
597 SIMD128_TYPES(SIMD128_TYPE)
598 #undef SIMD128_TYPE
599 if (object->IsCallable()) return isolate->factory()->function_string();
600 return isolate->factory()->object_string();
601 }
602
603
604 // static
Multiply(Isolate * isolate,Handle<Object> lhs,Handle<Object> rhs)605 MaybeHandle<Object> Object::Multiply(Isolate* isolate, Handle<Object> lhs,
606 Handle<Object> rhs) {
607 if (!lhs->IsNumber() || !rhs->IsNumber()) {
608 ASSIGN_RETURN_ON_EXCEPTION(isolate, lhs, Object::ToNumber(lhs), Object);
609 ASSIGN_RETURN_ON_EXCEPTION(isolate, rhs, Object::ToNumber(rhs), Object);
610 }
611 return isolate->factory()->NewNumber(lhs->Number() * rhs->Number());
612 }
613
614
615 // static
Divide(Isolate * isolate,Handle<Object> lhs,Handle<Object> rhs)616 MaybeHandle<Object> Object::Divide(Isolate* isolate, Handle<Object> lhs,
617 Handle<Object> rhs) {
618 if (!lhs->IsNumber() || !rhs->IsNumber()) {
619 ASSIGN_RETURN_ON_EXCEPTION(isolate, lhs, Object::ToNumber(lhs), Object);
620 ASSIGN_RETURN_ON_EXCEPTION(isolate, rhs, Object::ToNumber(rhs), Object);
621 }
622 return isolate->factory()->NewNumber(lhs->Number() / rhs->Number());
623 }
624
625
626 // static
Modulus(Isolate * isolate,Handle<Object> lhs,Handle<Object> rhs)627 MaybeHandle<Object> Object::Modulus(Isolate* isolate, Handle<Object> lhs,
628 Handle<Object> rhs) {
629 if (!lhs->IsNumber() || !rhs->IsNumber()) {
630 ASSIGN_RETURN_ON_EXCEPTION(isolate, lhs, Object::ToNumber(lhs), Object);
631 ASSIGN_RETURN_ON_EXCEPTION(isolate, rhs, Object::ToNumber(rhs), Object);
632 }
633 return isolate->factory()->NewNumber(modulo(lhs->Number(), rhs->Number()));
634 }
635
636
637 // static
Add(Isolate * isolate,Handle<Object> lhs,Handle<Object> rhs)638 MaybeHandle<Object> Object::Add(Isolate* isolate, Handle<Object> lhs,
639 Handle<Object> rhs) {
640 if (lhs->IsNumber() && rhs->IsNumber()) {
641 return isolate->factory()->NewNumber(lhs->Number() + rhs->Number());
642 } else if (lhs->IsString() && rhs->IsString()) {
643 return isolate->factory()->NewConsString(Handle<String>::cast(lhs),
644 Handle<String>::cast(rhs));
645 }
646 ASSIGN_RETURN_ON_EXCEPTION(isolate, lhs, Object::ToPrimitive(lhs), Object);
647 ASSIGN_RETURN_ON_EXCEPTION(isolate, rhs, Object::ToPrimitive(rhs), Object);
648 if (lhs->IsString() || rhs->IsString()) {
649 ASSIGN_RETURN_ON_EXCEPTION(isolate, rhs, Object::ToString(isolate, rhs),
650 Object);
651 ASSIGN_RETURN_ON_EXCEPTION(isolate, lhs, Object::ToString(isolate, lhs),
652 Object);
653 return isolate->factory()->NewConsString(Handle<String>::cast(lhs),
654 Handle<String>::cast(rhs));
655 }
656 ASSIGN_RETURN_ON_EXCEPTION(isolate, rhs, Object::ToNumber(rhs), Object);
657 ASSIGN_RETURN_ON_EXCEPTION(isolate, lhs, Object::ToNumber(lhs), Object);
658 return isolate->factory()->NewNumber(lhs->Number() + rhs->Number());
659 }
660
661
662 // static
Subtract(Isolate * isolate,Handle<Object> lhs,Handle<Object> rhs)663 MaybeHandle<Object> Object::Subtract(Isolate* isolate, Handle<Object> lhs,
664 Handle<Object> rhs) {
665 if (!lhs->IsNumber() || !rhs->IsNumber()) {
666 ASSIGN_RETURN_ON_EXCEPTION(isolate, lhs, Object::ToNumber(lhs), Object);
667 ASSIGN_RETURN_ON_EXCEPTION(isolate, rhs, Object::ToNumber(rhs), Object);
668 }
669 return isolate->factory()->NewNumber(lhs->Number() - rhs->Number());
670 }
671
672
673 // static
ShiftLeft(Isolate * isolate,Handle<Object> lhs,Handle<Object> rhs)674 MaybeHandle<Object> Object::ShiftLeft(Isolate* isolate, Handle<Object> lhs,
675 Handle<Object> rhs) {
676 if (!lhs->IsNumber() || !rhs->IsNumber()) {
677 ASSIGN_RETURN_ON_EXCEPTION(isolate, lhs, Object::ToNumber(lhs), Object);
678 ASSIGN_RETURN_ON_EXCEPTION(isolate, rhs, Object::ToNumber(rhs), Object);
679 }
680 return isolate->factory()->NewNumberFromInt(NumberToInt32(*lhs)
681 << (NumberToUint32(*rhs) & 0x1F));
682 }
683
684
685 // static
ShiftRight(Isolate * isolate,Handle<Object> lhs,Handle<Object> rhs)686 MaybeHandle<Object> Object::ShiftRight(Isolate* isolate, Handle<Object> lhs,
687 Handle<Object> rhs) {
688 if (!lhs->IsNumber() || !rhs->IsNumber()) {
689 ASSIGN_RETURN_ON_EXCEPTION(isolate, lhs, Object::ToNumber(lhs), Object);
690 ASSIGN_RETURN_ON_EXCEPTION(isolate, rhs, Object::ToNumber(rhs), Object);
691 }
692 return isolate->factory()->NewNumberFromInt(NumberToInt32(*lhs) >>
693 (NumberToUint32(*rhs) & 0x1F));
694 }
695
696
697 // static
ShiftRightLogical(Isolate * isolate,Handle<Object> lhs,Handle<Object> rhs)698 MaybeHandle<Object> Object::ShiftRightLogical(Isolate* isolate,
699 Handle<Object> lhs,
700 Handle<Object> rhs) {
701 if (!lhs->IsNumber() || !rhs->IsNumber()) {
702 ASSIGN_RETURN_ON_EXCEPTION(isolate, lhs, Object::ToNumber(lhs), Object);
703 ASSIGN_RETURN_ON_EXCEPTION(isolate, rhs, Object::ToNumber(rhs), Object);
704 }
705 return isolate->factory()->NewNumberFromUint(NumberToUint32(*lhs) >>
706 (NumberToUint32(*rhs) & 0x1F));
707 }
708
709
710 // static
BitwiseAnd(Isolate * isolate,Handle<Object> lhs,Handle<Object> rhs)711 MaybeHandle<Object> Object::BitwiseAnd(Isolate* isolate, Handle<Object> lhs,
712 Handle<Object> rhs) {
713 if (!lhs->IsNumber() || !rhs->IsNumber()) {
714 ASSIGN_RETURN_ON_EXCEPTION(isolate, lhs, Object::ToNumber(lhs), Object);
715 ASSIGN_RETURN_ON_EXCEPTION(isolate, rhs, Object::ToNumber(rhs), Object);
716 }
717 return isolate->factory()->NewNumberFromInt(NumberToInt32(*lhs) &
718 NumberToInt32(*rhs));
719 }
720
721
722 // static
BitwiseOr(Isolate * isolate,Handle<Object> lhs,Handle<Object> rhs)723 MaybeHandle<Object> Object::BitwiseOr(Isolate* isolate, Handle<Object> lhs,
724 Handle<Object> rhs) {
725 if (!lhs->IsNumber() || !rhs->IsNumber()) {
726 ASSIGN_RETURN_ON_EXCEPTION(isolate, lhs, Object::ToNumber(lhs), Object);
727 ASSIGN_RETURN_ON_EXCEPTION(isolate, rhs, Object::ToNumber(rhs), Object);
728 }
729 return isolate->factory()->NewNumberFromInt(NumberToInt32(*lhs) |
730 NumberToInt32(*rhs));
731 }
732
733
734 // static
BitwiseXor(Isolate * isolate,Handle<Object> lhs,Handle<Object> rhs)735 MaybeHandle<Object> Object::BitwiseXor(Isolate* isolate, Handle<Object> lhs,
736 Handle<Object> rhs) {
737 if (!lhs->IsNumber() || !rhs->IsNumber()) {
738 ASSIGN_RETURN_ON_EXCEPTION(isolate, lhs, Object::ToNumber(lhs), Object);
739 ASSIGN_RETURN_ON_EXCEPTION(isolate, rhs, Object::ToNumber(rhs), Object);
740 }
741 return isolate->factory()->NewNumberFromInt(NumberToInt32(*lhs) ^
742 NumberToInt32(*rhs));
743 }
744
745 // static
OrdinaryHasInstance(Isolate * isolate,Handle<Object> callable,Handle<Object> object)746 MaybeHandle<Object> Object::OrdinaryHasInstance(Isolate* isolate,
747 Handle<Object> callable,
748 Handle<Object> object) {
749 // The {callable} must have a [[Call]] internal method.
750 if (!callable->IsCallable()) return isolate->factory()->false_value();
751
752 // Check if {callable} is a bound function, and if so retrieve its
753 // [[BoundTargetFunction]] and use that instead of {callable}.
754 if (callable->IsJSBoundFunction()) {
755 Handle<Object> bound_callable(
756 Handle<JSBoundFunction>::cast(callable)->bound_target_function(),
757 isolate);
758 return Object::InstanceOf(isolate, object, bound_callable);
759 }
760
761 // If {object} is not a receiver, return false.
762 if (!object->IsJSReceiver()) return isolate->factory()->false_value();
763
764 // Get the "prototype" of {callable}; raise an error if it's not a receiver.
765 Handle<Object> prototype;
766 ASSIGN_RETURN_ON_EXCEPTION(
767 isolate, prototype,
768 Object::GetProperty(callable, isolate->factory()->prototype_string()),
769 Object);
770 if (!prototype->IsJSReceiver()) {
771 THROW_NEW_ERROR(
772 isolate,
773 NewTypeError(MessageTemplate::kInstanceofNonobjectProto, prototype),
774 Object);
775 }
776
777 // Return whether or not {prototype} is in the prototype chain of {object}.
778 Maybe<bool> result = JSReceiver::HasInPrototypeChain(
779 isolate, Handle<JSReceiver>::cast(object), prototype);
780 if (result.IsNothing()) return MaybeHandle<Object>();
781 return isolate->factory()->ToBoolean(result.FromJust());
782 }
783
784 // static
InstanceOf(Isolate * isolate,Handle<Object> object,Handle<Object> callable)785 MaybeHandle<Object> Object::InstanceOf(Isolate* isolate, Handle<Object> object,
786 Handle<Object> callable) {
787 // The {callable} must be a receiver.
788 if (!callable->IsJSReceiver()) {
789 THROW_NEW_ERROR(isolate,
790 NewTypeError(MessageTemplate::kNonObjectInInstanceOfCheck),
791 Object);
792 }
793
794 // Lookup the @@hasInstance method on {callable}.
795 Handle<Object> inst_of_handler;
796 ASSIGN_RETURN_ON_EXCEPTION(
797 isolate, inst_of_handler,
798 JSReceiver::GetMethod(Handle<JSReceiver>::cast(callable),
799 isolate->factory()->has_instance_symbol()),
800 Object);
801 if (!inst_of_handler->IsUndefined(isolate)) {
802 // Call the {inst_of_handler} on the {callable}.
803 Handle<Object> result;
804 ASSIGN_RETURN_ON_EXCEPTION(
805 isolate, result,
806 Execution::Call(isolate, inst_of_handler, callable, 1, &object),
807 Object);
808 return isolate->factory()->ToBoolean(result->BooleanValue());
809 }
810
811 // The {callable} must have a [[Call]] internal method.
812 if (!callable->IsCallable()) {
813 THROW_NEW_ERROR(
814 isolate, NewTypeError(MessageTemplate::kNonCallableInInstanceOfCheck),
815 Object);
816 }
817
818 // Fall back to OrdinaryHasInstance with {callable} and {object}.
819 Handle<Object> result;
820 ASSIGN_RETURN_ON_EXCEPTION(
821 isolate, result,
822 JSReceiver::OrdinaryHasInstance(isolate, callable, object), Object);
823 return result;
824 }
825
IsArray(Handle<Object> object)826 Maybe<bool> Object::IsArray(Handle<Object> object) {
827 if (object->IsJSArray()) return Just(true);
828 if (object->IsJSProxy()) {
829 Handle<JSProxy> proxy = Handle<JSProxy>::cast(object);
830 Isolate* isolate = proxy->GetIsolate();
831 if (proxy->IsRevoked()) {
832 isolate->Throw(*isolate->factory()->NewTypeError(
833 MessageTemplate::kProxyRevoked,
834 isolate->factory()->NewStringFromAsciiChecked("IsArray")));
835 return Nothing<bool>();
836 }
837 return Object::IsArray(handle(proxy->target(), isolate));
838 }
839 return Just(false);
840 }
841
842
843 // static
GetMethod(Handle<JSReceiver> receiver,Handle<Name> name)844 MaybeHandle<Object> Object::GetMethod(Handle<JSReceiver> receiver,
845 Handle<Name> name) {
846 Handle<Object> func;
847 Isolate* isolate = receiver->GetIsolate();
848 ASSIGN_RETURN_ON_EXCEPTION(isolate, func,
849 JSReceiver::GetProperty(receiver, name), Object);
850 if (func->IsNull(isolate) || func->IsUndefined(isolate)) {
851 return isolate->factory()->undefined_value();
852 }
853 if (!func->IsCallable()) {
854 THROW_NEW_ERROR(isolate, NewTypeError(MessageTemplate::kPropertyNotFunction,
855 func, name, receiver),
856 Object);
857 }
858 return func;
859 }
860
861
862 // static
CreateListFromArrayLike(Isolate * isolate,Handle<Object> object,ElementTypes element_types)863 MaybeHandle<FixedArray> Object::CreateListFromArrayLike(
864 Isolate* isolate, Handle<Object> object, ElementTypes element_types) {
865 // 1. ReturnIfAbrupt(object).
866 // 2. (default elementTypes -- not applicable.)
867 // 3. If Type(obj) is not Object, throw a TypeError exception.
868 if (!object->IsJSReceiver()) {
869 THROW_NEW_ERROR(isolate,
870 NewTypeError(MessageTemplate::kCalledOnNonObject,
871 isolate->factory()->NewStringFromAsciiChecked(
872 "CreateListFromArrayLike")),
873 FixedArray);
874 }
875 // 4. Let len be ? ToLength(? Get(obj, "length")).
876 Handle<JSReceiver> receiver = Handle<JSReceiver>::cast(object);
877 Handle<Object> raw_length_number;
878 ASSIGN_RETURN_ON_EXCEPTION(isolate, raw_length_number,
879 Object::GetLengthFromArrayLike(isolate, receiver),
880 FixedArray);
881 uint32_t len;
882 if (!raw_length_number->ToUint32(&len) ||
883 len > static_cast<uint32_t>(FixedArray::kMaxLength)) {
884 THROW_NEW_ERROR(isolate,
885 NewRangeError(MessageTemplate::kInvalidArrayLength),
886 FixedArray);
887 }
888 // 5. Let list be an empty List.
889 Handle<FixedArray> list = isolate->factory()->NewFixedArray(len);
890 // 6. Let index be 0.
891 // 7. Repeat while index < len:
892 for (uint32_t index = 0; index < len; ++index) {
893 // 7a. Let indexName be ToString(index).
894 // 7b. Let next be ? Get(obj, indexName).
895 Handle<Object> next;
896 ASSIGN_RETURN_ON_EXCEPTION(isolate, next,
897 JSReceiver::GetElement(isolate, receiver, index),
898 FixedArray);
899 switch (element_types) {
900 case ElementTypes::kAll:
901 // Nothing to do.
902 break;
903 case ElementTypes::kStringAndSymbol: {
904 // 7c. If Type(next) is not an element of elementTypes, throw a
905 // TypeError exception.
906 if (!next->IsName()) {
907 THROW_NEW_ERROR(isolate,
908 NewTypeError(MessageTemplate::kNotPropertyName, next),
909 FixedArray);
910 }
911 // 7d. Append next as the last element of list.
912 // Internalize on the fly so we can use pointer identity later.
913 next = isolate->factory()->InternalizeName(Handle<Name>::cast(next));
914 break;
915 }
916 }
917 list->set(index, *next);
918 // 7e. Set index to index + 1. (See loop header.)
919 }
920 // 8. Return list.
921 return list;
922 }
923
924
925 // static
GetLengthFromArrayLike(Isolate * isolate,Handle<Object> object)926 MaybeHandle<Object> Object::GetLengthFromArrayLike(Isolate* isolate,
927 Handle<Object> object) {
928 Handle<Object> val;
929 Handle<Object> key = isolate->factory()->length_string();
930 ASSIGN_RETURN_ON_EXCEPTION(
931 isolate, val, Runtime::GetObjectProperty(isolate, object, key), Object);
932 return Object::ToLength(isolate, val);
933 }
934
935 // static
HasProperty(LookupIterator * it)936 Maybe<bool> JSReceiver::HasProperty(LookupIterator* it) {
937 for (; it->IsFound(); it->Next()) {
938 switch (it->state()) {
939 case LookupIterator::NOT_FOUND:
940 case LookupIterator::TRANSITION:
941 UNREACHABLE();
942 case LookupIterator::JSPROXY:
943 return JSProxy::HasProperty(it->isolate(), it->GetHolder<JSProxy>(),
944 it->GetName());
945 case LookupIterator::INTERCEPTOR: {
946 Maybe<PropertyAttributes> result =
947 JSObject::GetPropertyAttributesWithInterceptor(it);
948 if (result.IsNothing()) return Nothing<bool>();
949 if (result.FromJust() != ABSENT) return Just(true);
950 break;
951 }
952 case LookupIterator::ACCESS_CHECK: {
953 if (it->HasAccess()) break;
954 Maybe<PropertyAttributes> result =
955 JSObject::GetPropertyAttributesWithFailedAccessCheck(it);
956 if (result.IsNothing()) return Nothing<bool>();
957 return Just(result.FromJust() != ABSENT);
958 }
959 case LookupIterator::INTEGER_INDEXED_EXOTIC:
960 // TypedArray out-of-bounds access.
961 return Just(false);
962 case LookupIterator::ACCESSOR:
963 case LookupIterator::DATA:
964 return Just(true);
965 }
966 }
967 return Just(false);
968 }
969
970
971 // static
GetProperty(LookupIterator * it)972 MaybeHandle<Object> Object::GetProperty(LookupIterator* it) {
973 for (; it->IsFound(); it->Next()) {
974 switch (it->state()) {
975 case LookupIterator::NOT_FOUND:
976 case LookupIterator::TRANSITION:
977 UNREACHABLE();
978 case LookupIterator::JSPROXY: {
979 bool was_found;
980 MaybeHandle<Object> result =
981 JSProxy::GetProperty(it->isolate(), it->GetHolder<JSProxy>(),
982 it->GetName(), it->GetReceiver(), &was_found);
983 if (!was_found) it->NotFound();
984 return result;
985 }
986 case LookupIterator::INTERCEPTOR: {
987 bool done;
988 Handle<Object> result;
989 ASSIGN_RETURN_ON_EXCEPTION(
990 it->isolate(), result,
991 JSObject::GetPropertyWithInterceptor(it, &done), Object);
992 if (done) return result;
993 break;
994 }
995 case LookupIterator::ACCESS_CHECK:
996 if (it->HasAccess()) break;
997 return JSObject::GetPropertyWithFailedAccessCheck(it);
998 case LookupIterator::ACCESSOR:
999 return GetPropertyWithAccessor(it);
1000 case LookupIterator::INTEGER_INDEXED_EXOTIC:
1001 return it->isolate()->factory()->undefined_value();
1002 case LookupIterator::DATA:
1003 return it->GetDataValue();
1004 }
1005 }
1006 return it->isolate()->factory()->undefined_value();
1007 }
1008
1009
1010 // static
GetProperty(Isolate * isolate,Handle<JSProxy> proxy,Handle<Name> name,Handle<Object> receiver,bool * was_found)1011 MaybeHandle<Object> JSProxy::GetProperty(Isolate* isolate,
1012 Handle<JSProxy> proxy,
1013 Handle<Name> name,
1014 Handle<Object> receiver,
1015 bool* was_found) {
1016 *was_found = true;
1017 if (receiver->IsJSGlobalObject()) {
1018 THROW_NEW_ERROR(
1019 isolate,
1020 NewTypeError(MessageTemplate::kReadGlobalReferenceThroughProxy, name),
1021 Object);
1022 }
1023
1024 DCHECK(!name->IsPrivate());
1025 STACK_CHECK(isolate, MaybeHandle<Object>());
1026 Handle<Name> trap_name = isolate->factory()->get_string();
1027 // 1. Assert: IsPropertyKey(P) is true.
1028 // 2. Let handler be the value of the [[ProxyHandler]] internal slot of O.
1029 Handle<Object> handler(proxy->handler(), isolate);
1030 // 3. If handler is null, throw a TypeError exception.
1031 // 4. Assert: Type(handler) is Object.
1032 if (proxy->IsRevoked()) {
1033 THROW_NEW_ERROR(isolate,
1034 NewTypeError(MessageTemplate::kProxyRevoked, trap_name),
1035 Object);
1036 }
1037 // 5. Let target be the value of the [[ProxyTarget]] internal slot of O.
1038 Handle<JSReceiver> target(proxy->target(), isolate);
1039 // 6. Let trap be ? GetMethod(handler, "get").
1040 Handle<Object> trap;
1041 ASSIGN_RETURN_ON_EXCEPTION(
1042 isolate, trap,
1043 Object::GetMethod(Handle<JSReceiver>::cast(handler), trap_name), Object);
1044 // 7. If trap is undefined, then
1045 if (trap->IsUndefined(isolate)) {
1046 // 7.a Return target.[[Get]](P, Receiver).
1047 LookupIterator it =
1048 LookupIterator::PropertyOrElement(isolate, receiver, name, target);
1049 MaybeHandle<Object> result = Object::GetProperty(&it);
1050 *was_found = it.IsFound();
1051 return result;
1052 }
1053 // 8. Let trapResult be ? Call(trap, handler, «target, P, Receiver»).
1054 Handle<Object> trap_result;
1055 Handle<Object> args[] = {target, name, receiver};
1056 ASSIGN_RETURN_ON_EXCEPTION(
1057 isolate, trap_result,
1058 Execution::Call(isolate, trap, handler, arraysize(args), args), Object);
1059 // 9. Let targetDesc be ? target.[[GetOwnProperty]](P).
1060 PropertyDescriptor target_desc;
1061 Maybe<bool> target_found =
1062 JSReceiver::GetOwnPropertyDescriptor(isolate, target, name, &target_desc);
1063 MAYBE_RETURN_NULL(target_found);
1064 // 10. If targetDesc is not undefined, then
1065 if (target_found.FromJust()) {
1066 // 10.a. If IsDataDescriptor(targetDesc) and targetDesc.[[Configurable]] is
1067 // false and targetDesc.[[Writable]] is false, then
1068 // 10.a.i. If SameValue(trapResult, targetDesc.[[Value]]) is false,
1069 // throw a TypeError exception.
1070 bool inconsistent = PropertyDescriptor::IsDataDescriptor(&target_desc) &&
1071 !target_desc.configurable() &&
1072 !target_desc.writable() &&
1073 !trap_result->SameValue(*target_desc.value());
1074 if (inconsistent) {
1075 THROW_NEW_ERROR(
1076 isolate, NewTypeError(MessageTemplate::kProxyGetNonConfigurableData,
1077 name, target_desc.value(), trap_result),
1078 Object);
1079 }
1080 // 10.b. If IsAccessorDescriptor(targetDesc) and targetDesc.[[Configurable]]
1081 // is false and targetDesc.[[Get]] is undefined, then
1082 // 10.b.i. If trapResult is not undefined, throw a TypeError exception.
1083 inconsistent = PropertyDescriptor::IsAccessorDescriptor(&target_desc) &&
1084 !target_desc.configurable() &&
1085 target_desc.get()->IsUndefined(isolate) &&
1086 !trap_result->IsUndefined(isolate);
1087 if (inconsistent) {
1088 THROW_NEW_ERROR(
1089 isolate,
1090 NewTypeError(MessageTemplate::kProxyGetNonConfigurableAccessor, name,
1091 trap_result),
1092 Object);
1093 }
1094 }
1095 // 11. Return trap_result
1096 return trap_result;
1097 }
1098
1099
GetDataProperty(LookupIterator * it)1100 Handle<Object> JSReceiver::GetDataProperty(LookupIterator* it) {
1101 for (; it->IsFound(); it->Next()) {
1102 switch (it->state()) {
1103 case LookupIterator::INTERCEPTOR:
1104 case LookupIterator::NOT_FOUND:
1105 case LookupIterator::TRANSITION:
1106 UNREACHABLE();
1107 case LookupIterator::ACCESS_CHECK:
1108 // Support calling this method without an active context, but refuse
1109 // access to access-checked objects in that case.
1110 if (it->isolate()->context() != nullptr && it->HasAccess()) continue;
1111 // Fall through.
1112 case LookupIterator::JSPROXY:
1113 it->NotFound();
1114 return it->isolate()->factory()->undefined_value();
1115 case LookupIterator::ACCESSOR:
1116 // TODO(verwaest): For now this doesn't call into AccessorInfo, since
1117 // clients don't need it. Update once relevant.
1118 it->NotFound();
1119 return it->isolate()->factory()->undefined_value();
1120 case LookupIterator::INTEGER_INDEXED_EXOTIC:
1121 return it->isolate()->factory()->undefined_value();
1122 case LookupIterator::DATA:
1123 return it->GetDataValue();
1124 }
1125 }
1126 return it->isolate()->factory()->undefined_value();
1127 }
1128
1129
ToInt32(int32_t * value)1130 bool Object::ToInt32(int32_t* value) {
1131 if (IsSmi()) {
1132 *value = Smi::cast(this)->value();
1133 return true;
1134 }
1135 if (IsHeapNumber()) {
1136 double num = HeapNumber::cast(this)->value();
1137 if (FastI2D(FastD2I(num)) == num) {
1138 *value = FastD2I(num);
1139 return true;
1140 }
1141 }
1142 return false;
1143 }
1144
GetOrCreateSharedFunctionInfo(Isolate * isolate,Handle<FunctionTemplateInfo> info)1145 Handle<SharedFunctionInfo> FunctionTemplateInfo::GetOrCreateSharedFunctionInfo(
1146 Isolate* isolate, Handle<FunctionTemplateInfo> info) {
1147 Object* current_info = info->shared_function_info();
1148 if (current_info->IsSharedFunctionInfo()) {
1149 return handle(SharedFunctionInfo::cast(current_info), isolate);
1150 }
1151
1152 Handle<Object> class_name(info->class_name(), isolate);
1153 Handle<String> name = class_name->IsString()
1154 ? Handle<String>::cast(class_name)
1155 : isolate->factory()->empty_string();
1156 Handle<Code> code;
1157 if (info->call_code()->IsCallHandlerInfo() &&
1158 CallHandlerInfo::cast(info->call_code())->fast_handler()->IsCode()) {
1159 code = isolate->builtins()->HandleFastApiCall();
1160 } else {
1161 code = isolate->builtins()->HandleApiCall();
1162 }
1163 bool is_constructor = !info->remove_prototype();
1164 Handle<SharedFunctionInfo> result =
1165 isolate->factory()->NewSharedFunctionInfo(name, code, is_constructor);
1166 if (is_constructor) {
1167 result->SetConstructStub(*isolate->builtins()->JSConstructStubApi());
1168 }
1169
1170 result->set_length(info->length());
1171 if (class_name->IsString()) result->set_instance_class_name(*class_name);
1172 result->set_api_func_data(*info);
1173 result->DontAdaptArguments();
1174 DCHECK(result->IsApiFunction());
1175
1176 info->set_shared_function_info(*result);
1177 return result;
1178 }
1179
IsTemplateFor(Map * map)1180 bool FunctionTemplateInfo::IsTemplateFor(Map* map) {
1181 // There is a constraint on the object; check.
1182 if (!map->IsJSObjectMap()) return false;
1183 // Fetch the constructor function of the object.
1184 Object* cons_obj = map->GetConstructor();
1185 if (!cons_obj->IsJSFunction()) return false;
1186 JSFunction* fun = JSFunction::cast(cons_obj);
1187 // Iterate through the chain of inheriting function templates to
1188 // see if the required one occurs.
1189 for (Object* type = fun->shared()->function_data();
1190 type->IsFunctionTemplateInfo();
1191 type = FunctionTemplateInfo::cast(type)->parent_template()) {
1192 if (type == this) return true;
1193 }
1194 // Didn't find the required type in the inheritance chain.
1195 return false;
1196 }
1197
1198
1199 // static
New(Isolate * isolate,int size)1200 Handle<TemplateList> TemplateList::New(Isolate* isolate, int size) {
1201 Handle<FixedArray> list =
1202 isolate->factory()->NewFixedArray(kLengthIndex + size);
1203 list->set(kLengthIndex, Smi::kZero);
1204 return Handle<TemplateList>::cast(list);
1205 }
1206
1207 // static
Add(Isolate * isolate,Handle<TemplateList> list,Handle<i::Object> value)1208 Handle<TemplateList> TemplateList::Add(Isolate* isolate,
1209 Handle<TemplateList> list,
1210 Handle<i::Object> value) {
1211 STATIC_ASSERT(kFirstElementIndex == 1);
1212 int index = list->length() + 1;
1213 Handle<i::FixedArray> fixed_array = Handle<FixedArray>::cast(list);
1214 fixed_array = FixedArray::SetAndGrow(fixed_array, index, value);
1215 fixed_array->set(kLengthIndex, Smi::FromInt(index));
1216 return Handle<TemplateList>::cast(fixed_array);
1217 }
1218
1219 // static
New(Handle<JSFunction> constructor,Handle<JSReceiver> new_target,Handle<AllocationSite> site)1220 MaybeHandle<JSObject> JSObject::New(Handle<JSFunction> constructor,
1221 Handle<JSReceiver> new_target,
1222 Handle<AllocationSite> site) {
1223 // If called through new, new.target can be:
1224 // - a subclass of constructor,
1225 // - a proxy wrapper around constructor, or
1226 // - the constructor itself.
1227 // If called through Reflect.construct, it's guaranteed to be a constructor.
1228 Isolate* const isolate = constructor->GetIsolate();
1229 DCHECK(constructor->IsConstructor());
1230 DCHECK(new_target->IsConstructor());
1231 DCHECK(!constructor->has_initial_map() ||
1232 constructor->initial_map()->instance_type() != JS_FUNCTION_TYPE);
1233
1234 Handle<Map> initial_map;
1235 ASSIGN_RETURN_ON_EXCEPTION(
1236 isolate, initial_map,
1237 JSFunction::GetDerivedMap(isolate, constructor, new_target), JSObject);
1238 Handle<JSObject> result =
1239 isolate->factory()->NewJSObjectFromMap(initial_map, NOT_TENURED, site);
1240 isolate->counters()->constructed_objects()->Increment();
1241 isolate->counters()->constructed_objects_runtime()->Increment();
1242 return result;
1243 }
1244
EnsureWritableFastElements(Handle<JSObject> object)1245 void JSObject::EnsureWritableFastElements(Handle<JSObject> object) {
1246 DCHECK(object->HasFastSmiOrObjectElements() ||
1247 object->HasFastStringWrapperElements());
1248 FixedArray* raw_elems = FixedArray::cast(object->elements());
1249 Heap* heap = object->GetHeap();
1250 if (raw_elems->map() != heap->fixed_cow_array_map()) return;
1251 Isolate* isolate = heap->isolate();
1252 Handle<FixedArray> elems(raw_elems, isolate);
1253 Handle<FixedArray> writable_elems = isolate->factory()->CopyFixedArrayWithMap(
1254 elems, isolate->factory()->fixed_array_map());
1255 object->set_elements(*writable_elems);
1256 isolate->counters()->cow_arrays_converted()->Increment();
1257 }
1258
1259
1260 // ES6 9.5.1
1261 // static
GetPrototype(Handle<JSProxy> proxy)1262 MaybeHandle<Object> JSProxy::GetPrototype(Handle<JSProxy> proxy) {
1263 Isolate* isolate = proxy->GetIsolate();
1264 Handle<String> trap_name = isolate->factory()->getPrototypeOf_string();
1265
1266 STACK_CHECK(isolate, MaybeHandle<Object>());
1267
1268 // 1. Let handler be the value of the [[ProxyHandler]] internal slot.
1269 // 2. If handler is null, throw a TypeError exception.
1270 // 3. Assert: Type(handler) is Object.
1271 // 4. Let target be the value of the [[ProxyTarget]] internal slot.
1272 if (proxy->IsRevoked()) {
1273 THROW_NEW_ERROR(isolate,
1274 NewTypeError(MessageTemplate::kProxyRevoked, trap_name),
1275 Object);
1276 }
1277 Handle<JSReceiver> target(proxy->target(), isolate);
1278 Handle<JSReceiver> handler(JSReceiver::cast(proxy->handler()), isolate);
1279
1280 // 5. Let trap be ? GetMethod(handler, "getPrototypeOf").
1281 Handle<Object> trap;
1282 ASSIGN_RETURN_ON_EXCEPTION(isolate, trap, GetMethod(handler, trap_name),
1283 Object);
1284 // 6. If trap is undefined, then return target.[[GetPrototypeOf]]().
1285 if (trap->IsUndefined(isolate)) {
1286 return JSReceiver::GetPrototype(isolate, target);
1287 }
1288 // 7. Let handlerProto be ? Call(trap, handler, «target»).
1289 Handle<Object> argv[] = {target};
1290 Handle<Object> handler_proto;
1291 ASSIGN_RETURN_ON_EXCEPTION(
1292 isolate, handler_proto,
1293 Execution::Call(isolate, trap, handler, arraysize(argv), argv), Object);
1294 // 8. If Type(handlerProto) is neither Object nor Null, throw a TypeError.
1295 if (!(handler_proto->IsJSReceiver() || handler_proto->IsNull(isolate))) {
1296 THROW_NEW_ERROR(isolate,
1297 NewTypeError(MessageTemplate::kProxyGetPrototypeOfInvalid),
1298 Object);
1299 }
1300 // 9. Let extensibleTarget be ? IsExtensible(target).
1301 Maybe<bool> is_extensible = JSReceiver::IsExtensible(target);
1302 MAYBE_RETURN_NULL(is_extensible);
1303 // 10. If extensibleTarget is true, return handlerProto.
1304 if (is_extensible.FromJust()) return handler_proto;
1305 // 11. Let targetProto be ? target.[[GetPrototypeOf]]().
1306 Handle<Object> target_proto;
1307 ASSIGN_RETURN_ON_EXCEPTION(isolate, target_proto,
1308 JSReceiver::GetPrototype(isolate, target), Object);
1309 // 12. If SameValue(handlerProto, targetProto) is false, throw a TypeError.
1310 if (!handler_proto->SameValue(*target_proto)) {
1311 THROW_NEW_ERROR(
1312 isolate,
1313 NewTypeError(MessageTemplate::kProxyGetPrototypeOfNonExtensible),
1314 Object);
1315 }
1316 // 13. Return handlerProto.
1317 return handler_proto;
1318 }
1319
GetPropertyWithAccessor(LookupIterator * it)1320 MaybeHandle<Object> Object::GetPropertyWithAccessor(LookupIterator* it) {
1321 Isolate* isolate = it->isolate();
1322 Handle<Object> structure = it->GetAccessors();
1323 Handle<Object> receiver = it->GetReceiver();
1324
1325 // We should never get here to initialize a const with the hole value since a
1326 // const declaration would conflict with the getter.
1327 DCHECK(!structure->IsForeign());
1328
1329 // API style callbacks.
1330 if (structure->IsAccessorInfo()) {
1331 Handle<JSObject> holder = it->GetHolder<JSObject>();
1332 Handle<Name> name = it->GetName();
1333 Handle<AccessorInfo> info = Handle<AccessorInfo>::cast(structure);
1334 if (!info->IsCompatibleReceiver(*receiver)) {
1335 THROW_NEW_ERROR(isolate,
1336 NewTypeError(MessageTemplate::kIncompatibleMethodReceiver,
1337 name, receiver),
1338 Object);
1339 }
1340
1341 v8::AccessorNameGetterCallback call_fun =
1342 v8::ToCData<v8::AccessorNameGetterCallback>(info->getter());
1343 if (call_fun == nullptr) return isolate->factory()->undefined_value();
1344
1345 if (info->is_sloppy() && !receiver->IsJSReceiver()) {
1346 ASSIGN_RETURN_ON_EXCEPTION(isolate, receiver,
1347 Object::ConvertReceiver(isolate, receiver),
1348 Object);
1349 }
1350
1351 PropertyCallbackArguments args(isolate, info->data(), *receiver, *holder,
1352 Object::DONT_THROW);
1353 Handle<Object> result = args.Call(call_fun, name);
1354 RETURN_EXCEPTION_IF_SCHEDULED_EXCEPTION(isolate, Object);
1355 if (result.is_null()) return isolate->factory()->undefined_value();
1356 Handle<Object> reboxed_result = handle(*result, isolate);
1357 if (info->replace_on_access() && receiver->IsJSReceiver()) {
1358 args.Call(reinterpret_cast<GenericNamedPropertySetterCallback>(
1359 &Accessors::ReconfigureToDataProperty),
1360 name, result);
1361 RETURN_EXCEPTION_IF_SCHEDULED_EXCEPTION(isolate, Object);
1362 }
1363 return reboxed_result;
1364 }
1365
1366 // AccessorPair with 'cached' private property.
1367 if (it->TryLookupCachedProperty()) {
1368 return Object::GetProperty(it);
1369 }
1370
1371 // Regular accessor.
1372 Handle<Object> getter(AccessorPair::cast(*structure)->getter(), isolate);
1373 if (getter->IsFunctionTemplateInfo()) {
1374 return Builtins::InvokeApiFunction(
1375 isolate, false, Handle<FunctionTemplateInfo>::cast(getter), receiver, 0,
1376 nullptr, isolate->factory()->undefined_value());
1377 } else if (getter->IsCallable()) {
1378 // TODO(rossberg): nicer would be to cast to some JSCallable here...
1379 return Object::GetPropertyWithDefinedGetter(
1380 receiver, Handle<JSReceiver>::cast(getter));
1381 }
1382 // Getter is not a function.
1383 return isolate->factory()->undefined_value();
1384 }
1385
1386 // static
redirect(Isolate * isolate,Address address,AccessorComponent component)1387 Address AccessorInfo::redirect(Isolate* isolate, Address address,
1388 AccessorComponent component) {
1389 ApiFunction fun(address);
1390 DCHECK_EQ(ACCESSOR_GETTER, component);
1391 ExternalReference::Type type = ExternalReference::DIRECT_GETTER_CALL;
1392 return ExternalReference(&fun, type, isolate).address();
1393 }
1394
redirected_getter() const1395 Address AccessorInfo::redirected_getter() const {
1396 Address accessor = v8::ToCData<Address>(getter());
1397 if (accessor == nullptr) return nullptr;
1398 return redirect(GetIsolate(), accessor, ACCESSOR_GETTER);
1399 }
1400
IsCompatibleReceiverMap(Isolate * isolate,Handle<AccessorInfo> info,Handle<Map> map)1401 bool AccessorInfo::IsCompatibleReceiverMap(Isolate* isolate,
1402 Handle<AccessorInfo> info,
1403 Handle<Map> map) {
1404 if (!info->HasExpectedReceiverType()) return true;
1405 if (!map->IsJSObjectMap()) return false;
1406 return FunctionTemplateInfo::cast(info->expected_receiver_type())
1407 ->IsTemplateFor(*map);
1408 }
1409
SetPropertyWithAccessor(LookupIterator * it,Handle<Object> value,ShouldThrow should_throw)1410 Maybe<bool> Object::SetPropertyWithAccessor(LookupIterator* it,
1411 Handle<Object> value,
1412 ShouldThrow should_throw) {
1413 Isolate* isolate = it->isolate();
1414 Handle<Object> structure = it->GetAccessors();
1415 Handle<Object> receiver = it->GetReceiver();
1416
1417 // We should never get here to initialize a const with the hole value since a
1418 // const declaration would conflict with the setter.
1419 DCHECK(!structure->IsForeign());
1420
1421 // API style callbacks.
1422 if (structure->IsAccessorInfo()) {
1423 Handle<JSObject> holder = it->GetHolder<JSObject>();
1424 Handle<Name> name = it->GetName();
1425 Handle<AccessorInfo> info = Handle<AccessorInfo>::cast(structure);
1426 if (!info->IsCompatibleReceiver(*receiver)) {
1427 isolate->Throw(*isolate->factory()->NewTypeError(
1428 MessageTemplate::kIncompatibleMethodReceiver, name, receiver));
1429 return Nothing<bool>();
1430 }
1431
1432 // The actual type of call_fun is either v8::AccessorNameSetterCallback or
1433 // i::Accesors::AccessorNameBooleanSetterCallback, depending on whether the
1434 // AccessorInfo was created by the API or internally (see accessors.cc).
1435 // Here we handle both cases using GenericNamedPropertySetterCallback and
1436 // its Call method.
1437 GenericNamedPropertySetterCallback call_fun =
1438 v8::ToCData<GenericNamedPropertySetterCallback>(info->setter());
1439
1440 if (call_fun == nullptr) {
1441 // TODO(verwaest): We should not get here anymore once all AccessorInfos
1442 // are marked as special_data_property. They cannot both be writable and
1443 // not have a setter.
1444 return Just(true);
1445 }
1446
1447 if (info->is_sloppy() && !receiver->IsJSReceiver()) {
1448 ASSIGN_RETURN_ON_EXCEPTION_VALUE(
1449 isolate, receiver, Object::ConvertReceiver(isolate, receiver),
1450 Nothing<bool>());
1451 }
1452
1453 PropertyCallbackArguments args(isolate, info->data(), *receiver, *holder,
1454 should_throw);
1455 Handle<Object> result = args.Call(call_fun, name, value);
1456 // In the case of AccessorNameSetterCallback, we know that the result value
1457 // cannot have been set, so the result of Call will be null. In the case of
1458 // AccessorNameBooleanSetterCallback, the result will either be null
1459 // (signalling an exception) or a boolean Oddball.
1460 RETURN_VALUE_IF_SCHEDULED_EXCEPTION(isolate, Nothing<bool>());
1461 if (result.is_null()) return Just(true);
1462 DCHECK(result->BooleanValue() || should_throw == DONT_THROW);
1463 return Just(result->BooleanValue());
1464 }
1465
1466 // Regular accessor.
1467 Handle<Object> setter(AccessorPair::cast(*structure)->setter(), isolate);
1468 if (setter->IsFunctionTemplateInfo()) {
1469 Handle<Object> argv[] = {value};
1470 RETURN_ON_EXCEPTION_VALUE(
1471 isolate, Builtins::InvokeApiFunction(
1472 isolate, false, Handle<FunctionTemplateInfo>::cast(setter),
1473 receiver, arraysize(argv), argv,
1474 isolate->factory()->undefined_value()),
1475 Nothing<bool>());
1476 return Just(true);
1477 } else if (setter->IsCallable()) {
1478 // TODO(rossberg): nicer would be to cast to some JSCallable here...
1479 return SetPropertyWithDefinedSetter(
1480 receiver, Handle<JSReceiver>::cast(setter), value, should_throw);
1481 }
1482
1483 RETURN_FAILURE(isolate, should_throw,
1484 NewTypeError(MessageTemplate::kNoSetterInCallback,
1485 it->GetName(), it->GetHolder<JSObject>()));
1486 }
1487
1488
GetPropertyWithDefinedGetter(Handle<Object> receiver,Handle<JSReceiver> getter)1489 MaybeHandle<Object> Object::GetPropertyWithDefinedGetter(
1490 Handle<Object> receiver,
1491 Handle<JSReceiver> getter) {
1492 Isolate* isolate = getter->GetIsolate();
1493
1494 // Platforms with simulators like arm/arm64 expose a funny issue. If the
1495 // simulator has a separate JS stack pointer from the C++ stack pointer, it
1496 // can miss C++ stack overflows in the stack guard at the start of JavaScript
1497 // functions. It would be very expensive to check the C++ stack pointer at
1498 // that location. The best solution seems to be to break the impasse by
1499 // adding checks at possible recursion points. What's more, we don't put
1500 // this stack check behind the USE_SIMULATOR define in order to keep
1501 // behavior the same between hardware and simulators.
1502 StackLimitCheck check(isolate);
1503 if (check.JsHasOverflowed()) {
1504 isolate->StackOverflow();
1505 return MaybeHandle<Object>();
1506 }
1507
1508 return Execution::Call(isolate, getter, receiver, 0, NULL);
1509 }
1510
1511
SetPropertyWithDefinedSetter(Handle<Object> receiver,Handle<JSReceiver> setter,Handle<Object> value,ShouldThrow should_throw)1512 Maybe<bool> Object::SetPropertyWithDefinedSetter(Handle<Object> receiver,
1513 Handle<JSReceiver> setter,
1514 Handle<Object> value,
1515 ShouldThrow should_throw) {
1516 Isolate* isolate = setter->GetIsolate();
1517
1518 Handle<Object> argv[] = { value };
1519 RETURN_ON_EXCEPTION_VALUE(isolate, Execution::Call(isolate, setter, receiver,
1520 arraysize(argv), argv),
1521 Nothing<bool>());
1522 return Just(true);
1523 }
1524
1525
1526 // static
AllCanRead(LookupIterator * it)1527 bool JSObject::AllCanRead(LookupIterator* it) {
1528 // Skip current iteration, it's in state ACCESS_CHECK or INTERCEPTOR, both of
1529 // which have already been checked.
1530 DCHECK(it->state() == LookupIterator::ACCESS_CHECK ||
1531 it->state() == LookupIterator::INTERCEPTOR);
1532 for (it->Next(); it->IsFound(); it->Next()) {
1533 if (it->state() == LookupIterator::ACCESSOR) {
1534 auto accessors = it->GetAccessors();
1535 if (accessors->IsAccessorInfo()) {
1536 if (AccessorInfo::cast(*accessors)->all_can_read()) return true;
1537 }
1538 } else if (it->state() == LookupIterator::INTERCEPTOR) {
1539 if (it->GetInterceptor()->all_can_read()) return true;
1540 } else if (it->state() == LookupIterator::JSPROXY) {
1541 // Stop lookupiterating. And no, AllCanNotRead.
1542 return false;
1543 }
1544 }
1545 return false;
1546 }
1547
1548 namespace {
1549
GetPropertyWithInterceptorInternal(LookupIterator * it,Handle<InterceptorInfo> interceptor,bool * done)1550 MaybeHandle<Object> GetPropertyWithInterceptorInternal(
1551 LookupIterator* it, Handle<InterceptorInfo> interceptor, bool* done) {
1552 *done = false;
1553 Isolate* isolate = it->isolate();
1554 // Make sure that the top context does not change when doing callbacks or
1555 // interceptor calls.
1556 AssertNoContextChange ncc(isolate);
1557
1558 if (interceptor->getter()->IsUndefined(isolate)) {
1559 return isolate->factory()->undefined_value();
1560 }
1561
1562 Handle<JSObject> holder = it->GetHolder<JSObject>();
1563 Handle<Object> result;
1564 Handle<Object> receiver = it->GetReceiver();
1565 if (!receiver->IsJSReceiver()) {
1566 ASSIGN_RETURN_ON_EXCEPTION(
1567 isolate, receiver, Object::ConvertReceiver(isolate, receiver), Object);
1568 }
1569 PropertyCallbackArguments args(isolate, interceptor->data(), *receiver,
1570 *holder, Object::DONT_THROW);
1571
1572 if (it->IsElement()) {
1573 uint32_t index = it->index();
1574 v8::IndexedPropertyGetterCallback getter =
1575 v8::ToCData<v8::IndexedPropertyGetterCallback>(interceptor->getter());
1576 result = args.Call(getter, index);
1577 } else {
1578 Handle<Name> name = it->name();
1579 DCHECK(!name->IsPrivate());
1580
1581 if (name->IsSymbol() && !interceptor->can_intercept_symbols()) {
1582 return isolate->factory()->undefined_value();
1583 }
1584
1585 v8::GenericNamedPropertyGetterCallback getter =
1586 v8::ToCData<v8::GenericNamedPropertyGetterCallback>(
1587 interceptor->getter());
1588 result = args.Call(getter, name);
1589 }
1590
1591 RETURN_EXCEPTION_IF_SCHEDULED_EXCEPTION(isolate, Object);
1592 if (result.is_null()) return isolate->factory()->undefined_value();
1593 *done = true;
1594 // Rebox handle before return
1595 return handle(*result, isolate);
1596 }
1597
GetPropertyAttributesWithInterceptorInternal(LookupIterator * it,Handle<InterceptorInfo> interceptor)1598 Maybe<PropertyAttributes> GetPropertyAttributesWithInterceptorInternal(
1599 LookupIterator* it, Handle<InterceptorInfo> interceptor) {
1600 Isolate* isolate = it->isolate();
1601 // Make sure that the top context does not change when doing
1602 // callbacks or interceptor calls.
1603 AssertNoContextChange ncc(isolate);
1604 HandleScope scope(isolate);
1605
1606 Handle<JSObject> holder = it->GetHolder<JSObject>();
1607 if (!it->IsElement() && it->name()->IsSymbol() &&
1608 !interceptor->can_intercept_symbols()) {
1609 return Just(ABSENT);
1610 }
1611 Handle<Object> receiver = it->GetReceiver();
1612 if (!receiver->IsJSReceiver()) {
1613 ASSIGN_RETURN_ON_EXCEPTION_VALUE(isolate, receiver,
1614 Object::ConvertReceiver(isolate, receiver),
1615 Nothing<PropertyAttributes>());
1616 }
1617 PropertyCallbackArguments args(isolate, interceptor->data(), *receiver,
1618 *holder, Object::DONT_THROW);
1619 if (!interceptor->query()->IsUndefined(isolate)) {
1620 Handle<Object> result;
1621 if (it->IsElement()) {
1622 uint32_t index = it->index();
1623 v8::IndexedPropertyQueryCallback query =
1624 v8::ToCData<v8::IndexedPropertyQueryCallback>(interceptor->query());
1625 result = args.Call(query, index);
1626 } else {
1627 Handle<Name> name = it->name();
1628 DCHECK(!name->IsPrivate());
1629 v8::GenericNamedPropertyQueryCallback query =
1630 v8::ToCData<v8::GenericNamedPropertyQueryCallback>(
1631 interceptor->query());
1632 result = args.Call(query, name);
1633 }
1634 if (!result.is_null()) {
1635 int32_t value;
1636 CHECK(result->ToInt32(&value));
1637 return Just(static_cast<PropertyAttributes>(value));
1638 }
1639 } else if (!interceptor->getter()->IsUndefined(isolate)) {
1640 // TODO(verwaest): Use GetPropertyWithInterceptor?
1641 Handle<Object> result;
1642 if (it->IsElement()) {
1643 uint32_t index = it->index();
1644 v8::IndexedPropertyGetterCallback getter =
1645 v8::ToCData<v8::IndexedPropertyGetterCallback>(interceptor->getter());
1646 result = args.Call(getter, index);
1647 } else {
1648 Handle<Name> name = it->name();
1649 DCHECK(!name->IsPrivate());
1650 v8::GenericNamedPropertyGetterCallback getter =
1651 v8::ToCData<v8::GenericNamedPropertyGetterCallback>(
1652 interceptor->getter());
1653 result = args.Call(getter, name);
1654 }
1655 if (!result.is_null()) return Just(DONT_ENUM);
1656 }
1657
1658 RETURN_VALUE_IF_SCHEDULED_EXCEPTION(isolate, Nothing<PropertyAttributes>());
1659 return Just(ABSENT);
1660 }
1661
SetPropertyWithInterceptorInternal(LookupIterator * it,Handle<InterceptorInfo> interceptor,Object::ShouldThrow should_throw,Handle<Object> value)1662 Maybe<bool> SetPropertyWithInterceptorInternal(
1663 LookupIterator* it, Handle<InterceptorInfo> interceptor,
1664 Object::ShouldThrow should_throw, Handle<Object> value) {
1665 Isolate* isolate = it->isolate();
1666 // Make sure that the top context does not change when doing callbacks or
1667 // interceptor calls.
1668 AssertNoContextChange ncc(isolate);
1669
1670 if (interceptor->setter()->IsUndefined(isolate)) return Just(false);
1671
1672 Handle<JSObject> holder = it->GetHolder<JSObject>();
1673 bool result;
1674 Handle<Object> receiver = it->GetReceiver();
1675 if (!receiver->IsJSReceiver()) {
1676 ASSIGN_RETURN_ON_EXCEPTION_VALUE(isolate, receiver,
1677 Object::ConvertReceiver(isolate, receiver),
1678 Nothing<bool>());
1679 }
1680 PropertyCallbackArguments args(isolate, interceptor->data(), *receiver,
1681 *holder, should_throw);
1682
1683 if (it->IsElement()) {
1684 uint32_t index = it->index();
1685 v8::IndexedPropertySetterCallback setter =
1686 v8::ToCData<v8::IndexedPropertySetterCallback>(interceptor->setter());
1687 // TODO(neis): In the future, we may want to actually return the
1688 // interceptor's result, which then should be a boolean.
1689 result = !args.Call(setter, index, value).is_null();
1690 } else {
1691 Handle<Name> name = it->name();
1692 DCHECK(!name->IsPrivate());
1693
1694 if (name->IsSymbol() && !interceptor->can_intercept_symbols()) {
1695 return Just(false);
1696 }
1697
1698 v8::GenericNamedPropertySetterCallback setter =
1699 v8::ToCData<v8::GenericNamedPropertySetterCallback>(
1700 interceptor->setter());
1701 result = !args.Call(setter, name, value).is_null();
1702 }
1703
1704 RETURN_VALUE_IF_SCHEDULED_EXCEPTION(it->isolate(), Nothing<bool>());
1705 return Just(result);
1706 }
1707
DefinePropertyWithInterceptorInternal(LookupIterator * it,Handle<InterceptorInfo> interceptor,Object::ShouldThrow should_throw,PropertyDescriptor & desc)1708 Maybe<bool> DefinePropertyWithInterceptorInternal(
1709 LookupIterator* it, Handle<InterceptorInfo> interceptor,
1710 Object::ShouldThrow should_throw, PropertyDescriptor& desc) {
1711 Isolate* isolate = it->isolate();
1712 // Make sure that the top context does not change when doing callbacks or
1713 // interceptor calls.
1714 AssertNoContextChange ncc(isolate);
1715
1716 if (interceptor->definer()->IsUndefined(isolate)) return Just(false);
1717
1718 Handle<JSObject> holder = it->GetHolder<JSObject>();
1719 bool result;
1720 Handle<Object> receiver = it->GetReceiver();
1721 if (!receiver->IsJSReceiver()) {
1722 ASSIGN_RETURN_ON_EXCEPTION_VALUE(isolate, receiver,
1723 Object::ConvertReceiver(isolate, receiver),
1724 Nothing<bool>());
1725 }
1726 PropertyCallbackArguments args(isolate, interceptor->data(), *receiver,
1727 *holder, should_throw);
1728
1729 std::unique_ptr<v8::PropertyDescriptor> descriptor(
1730 new v8::PropertyDescriptor());
1731 if (PropertyDescriptor::IsAccessorDescriptor(&desc)) {
1732 descriptor.reset(new v8::PropertyDescriptor(
1733 v8::Utils::ToLocal(desc.get()), v8::Utils::ToLocal(desc.set())));
1734 } else if (PropertyDescriptor::IsDataDescriptor(&desc)) {
1735 if (desc.has_writable()) {
1736 descriptor.reset(new v8::PropertyDescriptor(
1737 v8::Utils::ToLocal(desc.value()), desc.writable()));
1738 } else {
1739 descriptor.reset(
1740 new v8::PropertyDescriptor(v8::Utils::ToLocal(desc.value())));
1741 }
1742 }
1743 if (desc.has_enumerable()) {
1744 descriptor->set_enumerable(desc.enumerable());
1745 }
1746 if (desc.has_configurable()) {
1747 descriptor->set_configurable(desc.configurable());
1748 }
1749
1750 if (it->IsElement()) {
1751 uint32_t index = it->index();
1752 v8::IndexedPropertyDefinerCallback definer =
1753 v8::ToCData<v8::IndexedPropertyDefinerCallback>(interceptor->definer());
1754 result = !args.Call(definer, index, *descriptor).is_null();
1755 } else {
1756 Handle<Name> name = it->name();
1757 DCHECK(!name->IsPrivate());
1758
1759 if (name->IsSymbol() && !interceptor->can_intercept_symbols()) {
1760 return Just(false);
1761 }
1762
1763 v8::GenericNamedPropertyDefinerCallback definer =
1764 v8::ToCData<v8::GenericNamedPropertyDefinerCallback>(
1765 interceptor->definer());
1766 result = !args.Call(definer, name, *descriptor).is_null();
1767 }
1768
1769 RETURN_VALUE_IF_SCHEDULED_EXCEPTION(it->isolate(), Nothing<bool>());
1770 return Just(result);
1771 }
1772
1773 } // namespace
1774
GetPropertyWithFailedAccessCheck(LookupIterator * it)1775 MaybeHandle<Object> JSObject::GetPropertyWithFailedAccessCheck(
1776 LookupIterator* it) {
1777 Isolate* isolate = it->isolate();
1778 Handle<JSObject> checked = it->GetHolder<JSObject>();
1779 Handle<InterceptorInfo> interceptor =
1780 it->GetInterceptorForFailedAccessCheck();
1781 if (interceptor.is_null()) {
1782 while (AllCanRead(it)) {
1783 if (it->state() == LookupIterator::ACCESSOR) {
1784 return GetPropertyWithAccessor(it);
1785 }
1786 DCHECK_EQ(LookupIterator::INTERCEPTOR, it->state());
1787 bool done;
1788 Handle<Object> result;
1789 ASSIGN_RETURN_ON_EXCEPTION(isolate, result,
1790 GetPropertyWithInterceptor(it, &done), Object);
1791 if (done) return result;
1792 }
1793 } else {
1794 MaybeHandle<Object> result;
1795 bool done;
1796 result = GetPropertyWithInterceptorInternal(it, interceptor, &done);
1797 RETURN_EXCEPTION_IF_SCHEDULED_EXCEPTION(isolate, Object);
1798 if (done) return result;
1799 }
1800
1801 // Cross-Origin [[Get]] of Well-Known Symbols does not throw, and returns
1802 // undefined.
1803 Handle<Name> name = it->GetName();
1804 if (name->IsSymbol() && Symbol::cast(*name)->is_well_known_symbol()) {
1805 return it->factory()->undefined_value();
1806 }
1807
1808 isolate->ReportFailedAccessCheck(checked);
1809 RETURN_EXCEPTION_IF_SCHEDULED_EXCEPTION(isolate, Object);
1810 return it->factory()->undefined_value();
1811 }
1812
1813
GetPropertyAttributesWithFailedAccessCheck(LookupIterator * it)1814 Maybe<PropertyAttributes> JSObject::GetPropertyAttributesWithFailedAccessCheck(
1815 LookupIterator* it) {
1816 Isolate* isolate = it->isolate();
1817 Handle<JSObject> checked = it->GetHolder<JSObject>();
1818 Handle<InterceptorInfo> interceptor =
1819 it->GetInterceptorForFailedAccessCheck();
1820 if (interceptor.is_null()) {
1821 while (AllCanRead(it)) {
1822 if (it->state() == LookupIterator::ACCESSOR) {
1823 return Just(it->property_attributes());
1824 }
1825 DCHECK_EQ(LookupIterator::INTERCEPTOR, it->state());
1826 auto result = GetPropertyAttributesWithInterceptor(it);
1827 if (isolate->has_scheduled_exception()) break;
1828 if (result.IsJust() && result.FromJust() != ABSENT) return result;
1829 }
1830 } else {
1831 Maybe<PropertyAttributes> result =
1832 GetPropertyAttributesWithInterceptorInternal(it, interceptor);
1833 RETURN_VALUE_IF_SCHEDULED_EXCEPTION(isolate, Nothing<PropertyAttributes>());
1834 if (result.FromMaybe(ABSENT) != ABSENT) return result;
1835 }
1836 isolate->ReportFailedAccessCheck(checked);
1837 RETURN_VALUE_IF_SCHEDULED_EXCEPTION(isolate, Nothing<PropertyAttributes>());
1838 return Just(ABSENT);
1839 }
1840
1841
1842 // static
AllCanWrite(LookupIterator * it)1843 bool JSObject::AllCanWrite(LookupIterator* it) {
1844 for (; it->IsFound() && it->state() != LookupIterator::JSPROXY; it->Next()) {
1845 if (it->state() == LookupIterator::ACCESSOR) {
1846 Handle<Object> accessors = it->GetAccessors();
1847 if (accessors->IsAccessorInfo()) {
1848 if (AccessorInfo::cast(*accessors)->all_can_write()) return true;
1849 }
1850 }
1851 }
1852 return false;
1853 }
1854
1855
SetPropertyWithFailedAccessCheck(LookupIterator * it,Handle<Object> value,ShouldThrow should_throw)1856 Maybe<bool> JSObject::SetPropertyWithFailedAccessCheck(
1857 LookupIterator* it, Handle<Object> value, ShouldThrow should_throw) {
1858 Isolate* isolate = it->isolate();
1859 Handle<JSObject> checked = it->GetHolder<JSObject>();
1860 Handle<InterceptorInfo> interceptor =
1861 it->GetInterceptorForFailedAccessCheck();
1862 if (interceptor.is_null()) {
1863 if (AllCanWrite(it)) {
1864 return SetPropertyWithAccessor(it, value, should_throw);
1865 }
1866 } else {
1867 Maybe<bool> result = SetPropertyWithInterceptorInternal(
1868 it, interceptor, should_throw, value);
1869 RETURN_VALUE_IF_SCHEDULED_EXCEPTION(isolate, Nothing<bool>());
1870 if (result.IsJust()) return result;
1871 }
1872
1873 isolate->ReportFailedAccessCheck(checked);
1874 RETURN_VALUE_IF_SCHEDULED_EXCEPTION(isolate, Nothing<bool>());
1875 return Just(true);
1876 }
1877
1878
SetNormalizedProperty(Handle<JSObject> object,Handle<Name> name,Handle<Object> value,PropertyDetails details)1879 void JSObject::SetNormalizedProperty(Handle<JSObject> object,
1880 Handle<Name> name,
1881 Handle<Object> value,
1882 PropertyDetails details) {
1883 DCHECK(!object->HasFastProperties());
1884 if (!name->IsUniqueName()) {
1885 name = object->GetIsolate()->factory()->InternalizeString(
1886 Handle<String>::cast(name));
1887 }
1888
1889 if (object->IsJSGlobalObject()) {
1890 Handle<GlobalDictionary> dictionary(object->global_dictionary());
1891
1892 int entry = dictionary->FindEntry(name);
1893 if (entry == GlobalDictionary::kNotFound) {
1894 Isolate* isolate = object->GetIsolate();
1895 auto cell = isolate->factory()->NewPropertyCell();
1896 cell->set_value(*value);
1897 auto cell_type = value->IsUndefined(isolate)
1898 ? PropertyCellType::kUndefined
1899 : PropertyCellType::kConstant;
1900 details = details.set_cell_type(cell_type);
1901 value = cell;
1902 dictionary = GlobalDictionary::Add(dictionary, name, value, details);
1903 object->set_properties(*dictionary);
1904 } else {
1905 Handle<PropertyCell> cell =
1906 PropertyCell::PrepareForValue(dictionary, entry, value, details);
1907 cell->set_value(*value);
1908 }
1909 } else {
1910 Handle<NameDictionary> dictionary(object->property_dictionary());
1911
1912 int entry = dictionary->FindEntry(name);
1913 if (entry == NameDictionary::kNotFound) {
1914 dictionary = NameDictionary::Add(dictionary, name, value, details);
1915 object->set_properties(*dictionary);
1916 } else {
1917 PropertyDetails original_details = dictionary->DetailsAt(entry);
1918 int enumeration_index = original_details.dictionary_index();
1919 DCHECK(enumeration_index > 0);
1920 details = details.set_index(enumeration_index);
1921 dictionary->SetEntry(entry, name, value, details);
1922 }
1923 }
1924 }
1925
1926 // static
HasInPrototypeChain(Isolate * isolate,Handle<JSReceiver> object,Handle<Object> proto)1927 Maybe<bool> JSReceiver::HasInPrototypeChain(Isolate* isolate,
1928 Handle<JSReceiver> object,
1929 Handle<Object> proto) {
1930 PrototypeIterator iter(isolate, object, kStartAtReceiver);
1931 while (true) {
1932 if (!iter.AdvanceFollowingProxies()) return Nothing<bool>();
1933 if (iter.IsAtEnd()) return Just(false);
1934 if (PrototypeIterator::GetCurrent(iter).is_identical_to(proto)) {
1935 return Just(true);
1936 }
1937 }
1938 }
1939
GetPrototypeChainRootMap(Isolate * isolate)1940 Map* Object::GetPrototypeChainRootMap(Isolate* isolate) {
1941 DisallowHeapAllocation no_alloc;
1942 if (IsSmi()) {
1943 Context* native_context = isolate->context()->native_context();
1944 return native_context->number_function()->initial_map();
1945 }
1946
1947 // The object is either a number, a string, a symbol, a boolean, a SIMD value,
1948 // a real JS object, or a Harmony proxy.
1949 HeapObject* heap_object = HeapObject::cast(this);
1950 return heap_object->map()->GetPrototypeChainRootMap(isolate);
1951 }
1952
GetPrototypeChainRootMap(Isolate * isolate)1953 Map* Map::GetPrototypeChainRootMap(Isolate* isolate) {
1954 DisallowHeapAllocation no_alloc;
1955 if (IsJSReceiverMap()) {
1956 return this;
1957 }
1958 int constructor_function_index = GetConstructorFunctionIndex();
1959 if (constructor_function_index != Map::kNoConstructorFunctionIndex) {
1960 Context* native_context = isolate->context()->native_context();
1961 JSFunction* constructor_function =
1962 JSFunction::cast(native_context->get(constructor_function_index));
1963 return constructor_function->initial_map();
1964 }
1965 return isolate->heap()->null_value()->map();
1966 }
1967
1968 namespace {
1969
1970 // Returns a non-SMI for JSObjects, but returns the hash code for simple
1971 // objects. This avoids a double lookup in the cases where we know we will
1972 // add the hash to the JSObject if it does not already exist.
GetSimpleHash(Object * object)1973 Object* GetSimpleHash(Object* object) {
1974 // The object is either a Smi, a HeapNumber, a name, an odd-ball,
1975 // a SIMD value type, a real JS object, or a Harmony proxy.
1976 if (object->IsSmi()) {
1977 uint32_t hash =
1978 ComputeIntegerHash(Smi::cast(object)->value(), kZeroHashSeed);
1979 return Smi::FromInt(hash & Smi::kMaxValue);
1980 }
1981 if (object->IsHeapNumber()) {
1982 double num = HeapNumber::cast(object)->value();
1983 if (std::isnan(num)) return Smi::FromInt(Smi::kMaxValue);
1984 if (i::IsMinusZero(num)) num = 0;
1985 if (IsSmiDouble(num)) {
1986 return Smi::FromInt(FastD2I(num))->GetHash();
1987 }
1988 uint32_t hash = ComputeLongHash(double_to_uint64(num));
1989 return Smi::FromInt(hash & Smi::kMaxValue);
1990 }
1991 if (object->IsName()) {
1992 uint32_t hash = Name::cast(object)->Hash();
1993 return Smi::FromInt(hash);
1994 }
1995 if (object->IsOddball()) {
1996 uint32_t hash = Oddball::cast(object)->to_string()->Hash();
1997 return Smi::FromInt(hash);
1998 }
1999 if (object->IsSimd128Value()) {
2000 uint32_t hash = Simd128Value::cast(object)->Hash();
2001 return Smi::FromInt(hash & Smi::kMaxValue);
2002 }
2003 DCHECK(object->IsJSReceiver());
2004 // Simply return the receiver as it is guaranteed to not be a SMI.
2005 return object;
2006 }
2007
2008 } // namespace
2009
GetHash()2010 Object* Object::GetHash() {
2011 Object* hash = GetSimpleHash(this);
2012 if (hash->IsSmi()) return hash;
2013
2014 DisallowHeapAllocation no_gc;
2015 DCHECK(IsJSReceiver());
2016 JSReceiver* receiver = JSReceiver::cast(this);
2017 Isolate* isolate = receiver->GetIsolate();
2018 return JSReceiver::GetIdentityHash(isolate, handle(receiver, isolate));
2019 }
2020
GetOrCreateHash(Isolate * isolate,Handle<Object> object)2021 Smi* Object::GetOrCreateHash(Isolate* isolate, Handle<Object> object) {
2022 Object* hash = GetSimpleHash(*object);
2023 if (hash->IsSmi()) return Smi::cast(hash);
2024
2025 DCHECK(object->IsJSReceiver());
2026 return JSReceiver::GetOrCreateIdentityHash(isolate,
2027 Handle<JSReceiver>::cast(object));
2028 }
2029
2030
SameValue(Object * other)2031 bool Object::SameValue(Object* other) {
2032 if (other == this) return true;
2033
2034 // The object is either a number, a name, an odd-ball,
2035 // a real JS object, or a Harmony proxy.
2036 if (IsNumber() && other->IsNumber()) {
2037 double this_value = Number();
2038 double other_value = other->Number();
2039 // SameValue(NaN, NaN) is true.
2040 if (this_value != other_value) {
2041 return std::isnan(this_value) && std::isnan(other_value);
2042 }
2043 // SameValue(0.0, -0.0) is false.
2044 return (std::signbit(this_value) == std::signbit(other_value));
2045 }
2046 if (IsString() && other->IsString()) {
2047 return String::cast(this)->Equals(String::cast(other));
2048 }
2049 if (IsFloat32x4() && other->IsFloat32x4()) {
2050 Float32x4* a = Float32x4::cast(this);
2051 Float32x4* b = Float32x4::cast(other);
2052 for (int i = 0; i < 4; i++) {
2053 float x = a->get_lane(i);
2054 float y = b->get_lane(i);
2055 // Implements the ES5 SameValue operation for floating point types.
2056 // http://www.ecma-international.org/ecma-262/6.0/#sec-samevalue
2057 if (x != y && !(std::isnan(x) && std::isnan(y))) return false;
2058 if (std::signbit(x) != std::signbit(y)) return false;
2059 }
2060 return true;
2061 } else if (IsSimd128Value() && other->IsSimd128Value()) {
2062 Simd128Value* a = Simd128Value::cast(this);
2063 Simd128Value* b = Simd128Value::cast(other);
2064 return a->map() == b->map() && a->BitwiseEquals(b);
2065 }
2066 return false;
2067 }
2068
2069
SameValueZero(Object * other)2070 bool Object::SameValueZero(Object* other) {
2071 if (other == this) return true;
2072
2073 // The object is either a number, a name, an odd-ball,
2074 // a real JS object, or a Harmony proxy.
2075 if (IsNumber() && other->IsNumber()) {
2076 double this_value = Number();
2077 double other_value = other->Number();
2078 // +0 == -0 is true
2079 return this_value == other_value ||
2080 (std::isnan(this_value) && std::isnan(other_value));
2081 }
2082 if (IsString() && other->IsString()) {
2083 return String::cast(this)->Equals(String::cast(other));
2084 }
2085 if (IsFloat32x4() && other->IsFloat32x4()) {
2086 Float32x4* a = Float32x4::cast(this);
2087 Float32x4* b = Float32x4::cast(other);
2088 for (int i = 0; i < 4; i++) {
2089 float x = a->get_lane(i);
2090 float y = b->get_lane(i);
2091 // Implements the ES6 SameValueZero operation for floating point types.
2092 // http://www.ecma-international.org/ecma-262/6.0/#sec-samevaluezero
2093 if (x != y && !(std::isnan(x) && std::isnan(y))) return false;
2094 // SameValueZero doesn't distinguish between 0 and -0.
2095 }
2096 return true;
2097 } else if (IsSimd128Value() && other->IsSimd128Value()) {
2098 Simd128Value* a = Simd128Value::cast(this);
2099 Simd128Value* b = Simd128Value::cast(other);
2100 return a->map() == b->map() && a->BitwiseEquals(b);
2101 }
2102 return false;
2103 }
2104
2105
ArraySpeciesConstructor(Isolate * isolate,Handle<Object> original_array)2106 MaybeHandle<Object> Object::ArraySpeciesConstructor(
2107 Isolate* isolate, Handle<Object> original_array) {
2108 Handle<Object> default_species = isolate->array_function();
2109 if (original_array->IsJSArray() &&
2110 Handle<JSArray>::cast(original_array)->HasArrayPrototype(isolate) &&
2111 isolate->IsArraySpeciesLookupChainIntact()) {
2112 return default_species;
2113 }
2114 Handle<Object> constructor = isolate->factory()->undefined_value();
2115 Maybe<bool> is_array = Object::IsArray(original_array);
2116 MAYBE_RETURN_NULL(is_array);
2117 if (is_array.FromJust()) {
2118 ASSIGN_RETURN_ON_EXCEPTION(
2119 isolate, constructor,
2120 Object::GetProperty(original_array,
2121 isolate->factory()->constructor_string()),
2122 Object);
2123 if (constructor->IsConstructor()) {
2124 Handle<Context> constructor_context;
2125 ASSIGN_RETURN_ON_EXCEPTION(
2126 isolate, constructor_context,
2127 JSReceiver::GetFunctionRealm(Handle<JSReceiver>::cast(constructor)),
2128 Object);
2129 if (*constructor_context != *isolate->native_context() &&
2130 *constructor == constructor_context->array_function()) {
2131 constructor = isolate->factory()->undefined_value();
2132 }
2133 }
2134 if (constructor->IsJSReceiver()) {
2135 ASSIGN_RETURN_ON_EXCEPTION(
2136 isolate, constructor,
2137 JSReceiver::GetProperty(Handle<JSReceiver>::cast(constructor),
2138 isolate->factory()->species_symbol()),
2139 Object);
2140 if (constructor->IsNull(isolate)) {
2141 constructor = isolate->factory()->undefined_value();
2142 }
2143 }
2144 }
2145 if (constructor->IsUndefined(isolate)) {
2146 return default_species;
2147 } else {
2148 if (!constructor->IsConstructor()) {
2149 THROW_NEW_ERROR(isolate,
2150 NewTypeError(MessageTemplate::kSpeciesNotConstructor),
2151 Object);
2152 }
2153 return constructor;
2154 }
2155 }
2156
2157
ShortPrint(FILE * out)2158 void Object::ShortPrint(FILE* out) {
2159 OFStream os(out);
2160 os << Brief(this);
2161 }
2162
2163
ShortPrint(StringStream * accumulator)2164 void Object::ShortPrint(StringStream* accumulator) {
2165 std::ostringstream os;
2166 os << Brief(this);
2167 accumulator->Add(os.str().c_str());
2168 }
2169
2170
ShortPrint(std::ostream & os)2171 void Object::ShortPrint(std::ostream& os) { os << Brief(this); }
2172
2173
operator <<(std::ostream & os,const Brief & v)2174 std::ostream& operator<<(std::ostream& os, const Brief& v) {
2175 if (v.value->IsSmi()) {
2176 Smi::cast(v.value)->SmiPrint(os);
2177 } else {
2178 // TODO(svenpanne) Const-correct HeapObjectShortPrint!
2179 HeapObject* obj = const_cast<HeapObject*>(HeapObject::cast(v.value));
2180 obj->HeapObjectShortPrint(os);
2181 }
2182 return os;
2183 }
2184
2185 // Declaration of the static Smi::kZero constant.
2186 Smi* const Smi::kZero(nullptr);
2187
SmiPrint(std::ostream & os) const2188 void Smi::SmiPrint(std::ostream& os) const { // NOLINT
2189 os << value();
2190 }
2191
2192
2193 // Should a word be prefixed by 'a' or 'an' in order to read naturally in
2194 // English? Returns false for non-ASCII or words that don't start with
2195 // a capital letter. The a/an rule follows pronunciation in English.
2196 // We don't use the BBC's overcorrect "an historic occasion" though if
2197 // you speak a dialect you may well say "an 'istoric occasion".
AnWord(String * str)2198 static bool AnWord(String* str) {
2199 if (str->length() == 0) return false; // A nothing.
2200 int c0 = str->Get(0);
2201 int c1 = str->length() > 1 ? str->Get(1) : 0;
2202 if (c0 == 'U') {
2203 if (c1 > 'Z') {
2204 return true; // An Umpire, but a UTF8String, a U.
2205 }
2206 } else if (c0 == 'A' || c0 == 'E' || c0 == 'I' || c0 == 'O') {
2207 return true; // An Ape, an ABCBook.
2208 } else if ((c1 == 0 || (c1 >= 'A' && c1 <= 'Z')) &&
2209 (c0 == 'F' || c0 == 'H' || c0 == 'M' || c0 == 'N' || c0 == 'R' ||
2210 c0 == 'S' || c0 == 'X')) {
2211 return true; // An MP3File, an M.
2212 }
2213 return false;
2214 }
2215
2216
SlowFlatten(Handle<ConsString> cons,PretenureFlag pretenure)2217 Handle<String> String::SlowFlatten(Handle<ConsString> cons,
2218 PretenureFlag pretenure) {
2219 DCHECK(cons->second()->length() != 0);
2220
2221 // TurboFan can create cons strings with empty first parts.
2222 if (cons->first()->length() == 0) return handle(cons->second());
2223
2224 DCHECK(AllowHeapAllocation::IsAllowed());
2225 Isolate* isolate = cons->GetIsolate();
2226 int length = cons->length();
2227 PretenureFlag tenure = isolate->heap()->InNewSpace(*cons) ? pretenure
2228 : TENURED;
2229 Handle<SeqString> result;
2230 if (cons->IsOneByteRepresentation()) {
2231 Handle<SeqOneByteString> flat = isolate->factory()->NewRawOneByteString(
2232 length, tenure).ToHandleChecked();
2233 DisallowHeapAllocation no_gc;
2234 WriteToFlat(*cons, flat->GetChars(), 0, length);
2235 result = flat;
2236 } else {
2237 Handle<SeqTwoByteString> flat = isolate->factory()->NewRawTwoByteString(
2238 length, tenure).ToHandleChecked();
2239 DisallowHeapAllocation no_gc;
2240 WriteToFlat(*cons, flat->GetChars(), 0, length);
2241 result = flat;
2242 }
2243 cons->set_first(*result);
2244 cons->set_second(isolate->heap()->empty_string());
2245 DCHECK(result->IsFlat());
2246 return result;
2247 }
2248
2249
2250
MakeExternal(v8::String::ExternalStringResource * resource)2251 bool String::MakeExternal(v8::String::ExternalStringResource* resource) {
2252 // Externalizing twice leaks the external resource, so it's
2253 // prohibited by the API.
2254 DCHECK(!this->IsExternalString());
2255 DCHECK(!resource->IsCompressible());
2256 #ifdef ENABLE_SLOW_DCHECKS
2257 if (FLAG_enable_slow_asserts) {
2258 // Assert that the resource and the string are equivalent.
2259 DCHECK(static_cast<size_t>(this->length()) == resource->length());
2260 ScopedVector<uc16> smart_chars(this->length());
2261 String::WriteToFlat(this, smart_chars.start(), 0, this->length());
2262 DCHECK(memcmp(smart_chars.start(),
2263 resource->data(),
2264 resource->length() * sizeof(smart_chars[0])) == 0);
2265 }
2266 #endif // DEBUG
2267 int size = this->Size(); // Byte size of the original string.
2268 // Abort if size does not allow in-place conversion.
2269 if (size < ExternalString::kShortSize) return false;
2270 Heap* heap = GetHeap();
2271 bool is_one_byte = this->IsOneByteRepresentation();
2272 bool is_internalized = this->IsInternalizedString();
2273 bool has_pointers = this->IsConsString() || this->IsSlicedString();
2274
2275 // Morph the string to an external string by replacing the map and
2276 // reinitializing the fields. This won't work if the space the existing
2277 // string occupies is too small for a regular external string.
2278 // Instead, we resort to a short external string instead, omitting
2279 // the field caching the address of the backing store. When we encounter
2280 // short external strings in generated code, we need to bailout to runtime.
2281 Map* new_map;
2282 if (size < ExternalString::kSize) {
2283 new_map = is_internalized
2284 ? (is_one_byte
2285 ? heap->short_external_internalized_string_with_one_byte_data_map()
2286 : heap->short_external_internalized_string_map())
2287 : (is_one_byte ? heap->short_external_string_with_one_byte_data_map()
2288 : heap->short_external_string_map());
2289 } else {
2290 new_map = is_internalized
2291 ? (is_one_byte
2292 ? heap->external_internalized_string_with_one_byte_data_map()
2293 : heap->external_internalized_string_map())
2294 : (is_one_byte ? heap->external_string_with_one_byte_data_map()
2295 : heap->external_string_map());
2296 }
2297
2298 // Byte size of the external String object.
2299 int new_size = this->SizeFromMap(new_map);
2300 heap->CreateFillerObjectAt(this->address() + new_size, size - new_size,
2301 ClearRecordedSlots::kNo);
2302 if (has_pointers) {
2303 heap->ClearRecordedSlotRange(this->address(), this->address() + new_size);
2304 }
2305
2306 // We are storing the new map using release store after creating a filler for
2307 // the left-over space to avoid races with the sweeper thread.
2308 this->synchronized_set_map(new_map);
2309
2310 ExternalTwoByteString* self = ExternalTwoByteString::cast(this);
2311 self->set_resource(resource);
2312 if (is_internalized) self->Hash(); // Force regeneration of the hash value.
2313
2314 heap->AdjustLiveBytes(this, new_size - size, Heap::CONCURRENT_TO_SWEEPER);
2315 return true;
2316 }
2317
2318
MakeExternal(v8::String::ExternalOneByteStringResource * resource)2319 bool String::MakeExternal(v8::String::ExternalOneByteStringResource* resource) {
2320 // Externalizing twice leaks the external resource, so it's
2321 // prohibited by the API.
2322 DCHECK(!this->IsExternalString());
2323 DCHECK(!resource->IsCompressible());
2324 #ifdef ENABLE_SLOW_DCHECKS
2325 if (FLAG_enable_slow_asserts) {
2326 // Assert that the resource and the string are equivalent.
2327 DCHECK(static_cast<size_t>(this->length()) == resource->length());
2328 if (this->IsTwoByteRepresentation()) {
2329 ScopedVector<uint16_t> smart_chars(this->length());
2330 String::WriteToFlat(this, smart_chars.start(), 0, this->length());
2331 DCHECK(String::IsOneByte(smart_chars.start(), this->length()));
2332 }
2333 ScopedVector<char> smart_chars(this->length());
2334 String::WriteToFlat(this, smart_chars.start(), 0, this->length());
2335 DCHECK(memcmp(smart_chars.start(),
2336 resource->data(),
2337 resource->length() * sizeof(smart_chars[0])) == 0);
2338 }
2339 #endif // DEBUG
2340 int size = this->Size(); // Byte size of the original string.
2341 // Abort if size does not allow in-place conversion.
2342 if (size < ExternalString::kShortSize) return false;
2343 Heap* heap = GetHeap();
2344 bool is_internalized = this->IsInternalizedString();
2345 bool has_pointers = this->IsConsString() || this->IsSlicedString();
2346
2347 // Morph the string to an external string by replacing the map and
2348 // reinitializing the fields. This won't work if the space the existing
2349 // string occupies is too small for a regular external string.
2350 // Instead, we resort to a short external string instead, omitting
2351 // the field caching the address of the backing store. When we encounter
2352 // short external strings in generated code, we need to bailout to runtime.
2353 Map* new_map;
2354 if (size < ExternalString::kSize) {
2355 new_map = is_internalized
2356 ? heap->short_external_one_byte_internalized_string_map()
2357 : heap->short_external_one_byte_string_map();
2358 } else {
2359 new_map = is_internalized
2360 ? heap->external_one_byte_internalized_string_map()
2361 : heap->external_one_byte_string_map();
2362 }
2363
2364 // Byte size of the external String object.
2365 int new_size = this->SizeFromMap(new_map);
2366 heap->CreateFillerObjectAt(this->address() + new_size, size - new_size,
2367 ClearRecordedSlots::kNo);
2368 if (has_pointers) {
2369 heap->ClearRecordedSlotRange(this->address(), this->address() + new_size);
2370 }
2371
2372 // We are storing the new map using release store after creating a filler for
2373 // the left-over space to avoid races with the sweeper thread.
2374 this->synchronized_set_map(new_map);
2375
2376 ExternalOneByteString* self = ExternalOneByteString::cast(this);
2377 self->set_resource(resource);
2378 if (is_internalized) self->Hash(); // Force regeneration of the hash value.
2379
2380 heap->AdjustLiveBytes(this, new_size - size, Heap::CONCURRENT_TO_SWEEPER);
2381 return true;
2382 }
2383
StringShortPrint(StringStream * accumulator,bool show_details)2384 void String::StringShortPrint(StringStream* accumulator, bool show_details) {
2385 int len = length();
2386 if (len > kMaxShortPrintLength) {
2387 accumulator->Add("<Very long string[%u]>", len);
2388 return;
2389 }
2390
2391 if (!LooksValid()) {
2392 accumulator->Add("<Invalid String>");
2393 return;
2394 }
2395
2396 StringCharacterStream stream(this);
2397
2398 bool truncated = false;
2399 if (len > kMaxShortPrintLength) {
2400 len = kMaxShortPrintLength;
2401 truncated = true;
2402 }
2403 bool one_byte = true;
2404 for (int i = 0; i < len; i++) {
2405 uint16_t c = stream.GetNext();
2406
2407 if (c < 32 || c >= 127) {
2408 one_byte = false;
2409 }
2410 }
2411 stream.Reset(this);
2412 if (one_byte) {
2413 if (show_details) accumulator->Add("<String[%u]: ", length());
2414 for (int i = 0; i < len; i++) {
2415 accumulator->Put(static_cast<char>(stream.GetNext()));
2416 }
2417 if (show_details) accumulator->Put('>');
2418 } else {
2419 // Backslash indicates that the string contains control
2420 // characters and that backslashes are therefore escaped.
2421 if (show_details) accumulator->Add("<String[%u]\\: ", length());
2422 for (int i = 0; i < len; i++) {
2423 uint16_t c = stream.GetNext();
2424 if (c == '\n') {
2425 accumulator->Add("\\n");
2426 } else if (c == '\r') {
2427 accumulator->Add("\\r");
2428 } else if (c == '\\') {
2429 accumulator->Add("\\\\");
2430 } else if (c < 32 || c > 126) {
2431 accumulator->Add("\\x%02x", c);
2432 } else {
2433 accumulator->Put(static_cast<char>(c));
2434 }
2435 }
2436 if (truncated) {
2437 accumulator->Put('.');
2438 accumulator->Put('.');
2439 accumulator->Put('.');
2440 }
2441 if (show_details) accumulator->Put('>');
2442 }
2443 return;
2444 }
2445
2446
PrintUC16(std::ostream & os,int start,int end)2447 void String::PrintUC16(std::ostream& os, int start, int end) { // NOLINT
2448 if (end < 0) end = length();
2449 StringCharacterStream stream(this, start);
2450 for (int i = start; i < end && stream.HasMore(); i++) {
2451 os << AsUC16(stream.GetNext());
2452 }
2453 }
2454
2455
JSObjectShortPrint(StringStream * accumulator)2456 void JSObject::JSObjectShortPrint(StringStream* accumulator) {
2457 switch (map()->instance_type()) {
2458 case JS_ARRAY_TYPE: {
2459 double length = JSArray::cast(this)->length()->IsUndefined(GetIsolate())
2460 ? 0
2461 : JSArray::cast(this)->length()->Number();
2462 accumulator->Add("<JS Array[%u]>", static_cast<uint32_t>(length));
2463 break;
2464 }
2465 case JS_BOUND_FUNCTION_TYPE: {
2466 JSBoundFunction* bound_function = JSBoundFunction::cast(this);
2467 accumulator->Add("<JS BoundFunction");
2468 accumulator->Add(
2469 " (BoundTargetFunction %p)>",
2470 reinterpret_cast<void*>(bound_function->bound_target_function()));
2471 break;
2472 }
2473 case JS_WEAK_MAP_TYPE: {
2474 accumulator->Add("<JS WeakMap>");
2475 break;
2476 }
2477 case JS_WEAK_SET_TYPE: {
2478 accumulator->Add("<JS WeakSet>");
2479 break;
2480 }
2481 case JS_REGEXP_TYPE: {
2482 accumulator->Add("<JS RegExp>");
2483 break;
2484 }
2485 case JS_FUNCTION_TYPE: {
2486 JSFunction* function = JSFunction::cast(this);
2487 Object* fun_name = function->shared()->DebugName();
2488 bool printed = false;
2489 if (fun_name->IsString()) {
2490 String* str = String::cast(fun_name);
2491 if (str->length() > 0) {
2492 accumulator->Add("<JS Function ");
2493 accumulator->Put(str);
2494 printed = true;
2495 }
2496 }
2497 if (!printed) {
2498 accumulator->Add("<JS Function");
2499 }
2500 if (FLAG_trace_file_names) {
2501 Object* source_name =
2502 Script::cast(function->shared()->script())->name();
2503 if (source_name->IsString()) {
2504 String* str = String::cast(source_name);
2505 if (str->length() > 0) {
2506 accumulator->Add(" <");
2507 accumulator->Put(str);
2508 accumulator->Add(">");
2509 }
2510 }
2511 }
2512 accumulator->Add(" (SharedFunctionInfo %p)",
2513 reinterpret_cast<void*>(function->shared()));
2514 accumulator->Put('>');
2515 break;
2516 }
2517 case JS_GENERATOR_OBJECT_TYPE: {
2518 accumulator->Add("<JS Generator>");
2519 break;
2520 }
2521 // All other JSObjects are rather similar to each other (JSObject,
2522 // JSGlobalProxy, JSGlobalObject, JSUndetectable, JSValue).
2523 default: {
2524 Map* map_of_this = map();
2525 Heap* heap = GetHeap();
2526 Object* constructor = map_of_this->GetConstructor();
2527 bool printed = false;
2528 if (constructor->IsHeapObject() &&
2529 !heap->Contains(HeapObject::cast(constructor))) {
2530 accumulator->Add("!!!INVALID CONSTRUCTOR!!!");
2531 } else {
2532 bool global_object = IsJSGlobalProxy();
2533 if (constructor->IsJSFunction()) {
2534 if (!heap->Contains(JSFunction::cast(constructor)->shared())) {
2535 accumulator->Add("!!!INVALID SHARED ON CONSTRUCTOR!!!");
2536 } else {
2537 Object* constructor_name =
2538 JSFunction::cast(constructor)->shared()->name();
2539 if (constructor_name->IsString()) {
2540 String* str = String::cast(constructor_name);
2541 if (str->length() > 0) {
2542 bool vowel = AnWord(str);
2543 accumulator->Add("<%sa%s ",
2544 global_object ? "Global Object: " : "",
2545 vowel ? "n" : "");
2546 accumulator->Put(str);
2547 accumulator->Add(" with %smap %p",
2548 map_of_this->is_deprecated() ? "deprecated " : "",
2549 map_of_this);
2550 printed = true;
2551 }
2552 }
2553 }
2554 }
2555 if (!printed) {
2556 accumulator->Add("<JS %sObject", global_object ? "Global " : "");
2557 }
2558 }
2559 if (IsJSValue()) {
2560 accumulator->Add(" value = ");
2561 JSValue::cast(this)->value()->ShortPrint(accumulator);
2562 }
2563 accumulator->Put('>');
2564 break;
2565 }
2566 }
2567 }
2568
2569
PrintElementsTransition(FILE * file,Handle<JSObject> object,ElementsKind from_kind,Handle<FixedArrayBase> from_elements,ElementsKind to_kind,Handle<FixedArrayBase> to_elements)2570 void JSObject::PrintElementsTransition(
2571 FILE* file, Handle<JSObject> object,
2572 ElementsKind from_kind, Handle<FixedArrayBase> from_elements,
2573 ElementsKind to_kind, Handle<FixedArrayBase> to_elements) {
2574 if (from_kind != to_kind) {
2575 OFStream os(file);
2576 os << "elements transition [" << ElementsKindToString(from_kind) << " -> "
2577 << ElementsKindToString(to_kind) << "] in ";
2578 JavaScriptFrame::PrintTop(object->GetIsolate(), file, false, true);
2579 PrintF(file, " for ");
2580 object->ShortPrint(file);
2581 PrintF(file, " from ");
2582 from_elements->ShortPrint(file);
2583 PrintF(file, " to ");
2584 to_elements->ShortPrint(file);
2585 PrintF(file, "\n");
2586 }
2587 }
2588
2589
2590 // static
GetConstructorFunction(Handle<Map> map,Handle<Context> native_context)2591 MaybeHandle<JSFunction> Map::GetConstructorFunction(
2592 Handle<Map> map, Handle<Context> native_context) {
2593 if (map->IsPrimitiveMap()) {
2594 int const constructor_function_index = map->GetConstructorFunctionIndex();
2595 if (constructor_function_index != kNoConstructorFunctionIndex) {
2596 return handle(
2597 JSFunction::cast(native_context->get(constructor_function_index)));
2598 }
2599 }
2600 return MaybeHandle<JSFunction>();
2601 }
2602
2603
PrintReconfiguration(FILE * file,int modify_index,PropertyKind kind,PropertyAttributes attributes)2604 void Map::PrintReconfiguration(FILE* file, int modify_index, PropertyKind kind,
2605 PropertyAttributes attributes) {
2606 OFStream os(file);
2607 os << "[reconfiguring]";
2608 Name* name = instance_descriptors()->GetKey(modify_index);
2609 if (name->IsString()) {
2610 String::cast(name)->PrintOn(file);
2611 } else {
2612 os << "{symbol " << static_cast<void*>(name) << "}";
2613 }
2614 os << ": " << (kind == kData ? "kData" : "ACCESSORS") << ", attrs: ";
2615 os << attributes << " [";
2616 JavaScriptFrame::PrintTop(GetIsolate(), file, false, true);
2617 os << "]\n";
2618 }
2619
PrintGeneralization(FILE * file,const char * reason,int modify_index,int split,int descriptors,bool constant_to_field,Representation old_representation,Representation new_representation,MaybeHandle<FieldType> old_field_type,MaybeHandle<Object> old_value,MaybeHandle<FieldType> new_field_type,MaybeHandle<Object> new_value)2620 void Map::PrintGeneralization(
2621 FILE* file, const char* reason, int modify_index, int split,
2622 int descriptors, bool constant_to_field, Representation old_representation,
2623 Representation new_representation, MaybeHandle<FieldType> old_field_type,
2624 MaybeHandle<Object> old_value, MaybeHandle<FieldType> new_field_type,
2625 MaybeHandle<Object> new_value) {
2626 OFStream os(file);
2627 os << "[generalizing]";
2628 Name* name = instance_descriptors()->GetKey(modify_index);
2629 if (name->IsString()) {
2630 String::cast(name)->PrintOn(file);
2631 } else {
2632 os << "{symbol " << static_cast<void*>(name) << "}";
2633 }
2634 os << ":";
2635 if (constant_to_field) {
2636 os << "c";
2637 } else {
2638 os << old_representation.Mnemonic() << "{";
2639 if (old_field_type.is_null()) {
2640 os << Brief(*(old_value.ToHandleChecked()));
2641 } else {
2642 old_field_type.ToHandleChecked()->PrintTo(os);
2643 }
2644 os << "}";
2645 }
2646 os << "->" << new_representation.Mnemonic() << "{";
2647 if (new_field_type.is_null()) {
2648 os << Brief(*(new_value.ToHandleChecked()));
2649 } else {
2650 new_field_type.ToHandleChecked()->PrintTo(os);
2651 }
2652 os << "} (";
2653 if (strlen(reason) > 0) {
2654 os << reason;
2655 } else {
2656 os << "+" << (descriptors - split) << " maps";
2657 }
2658 os << ") [";
2659 JavaScriptFrame::PrintTop(GetIsolate(), file, false, true);
2660 os << "]\n";
2661 }
2662
2663
PrintInstanceMigration(FILE * file,Map * original_map,Map * new_map)2664 void JSObject::PrintInstanceMigration(FILE* file,
2665 Map* original_map,
2666 Map* new_map) {
2667 PrintF(file, "[migrating]");
2668 DescriptorArray* o = original_map->instance_descriptors();
2669 DescriptorArray* n = new_map->instance_descriptors();
2670 for (int i = 0; i < original_map->NumberOfOwnDescriptors(); i++) {
2671 Representation o_r = o->GetDetails(i).representation();
2672 Representation n_r = n->GetDetails(i).representation();
2673 if (!o_r.Equals(n_r)) {
2674 String::cast(o->GetKey(i))->PrintOn(file);
2675 PrintF(file, ":%s->%s ", o_r.Mnemonic(), n_r.Mnemonic());
2676 } else if (o->GetDetails(i).type() == DATA_CONSTANT &&
2677 n->GetDetails(i).type() == DATA) {
2678 Name* name = o->GetKey(i);
2679 if (name->IsString()) {
2680 String::cast(name)->PrintOn(file);
2681 } else {
2682 PrintF(file, "{symbol %p}", static_cast<void*>(name));
2683 }
2684 PrintF(file, " ");
2685 }
2686 }
2687 PrintF(file, "\n");
2688 }
2689
2690
HeapObjectShortPrint(std::ostream & os)2691 void HeapObject::HeapObjectShortPrint(std::ostream& os) { // NOLINT
2692 Heap* heap = GetHeap();
2693 Isolate* isolate = heap->isolate();
2694 if (!heap->Contains(this)) {
2695 os << "!!!INVALID POINTER!!!";
2696 return;
2697 }
2698 if (!heap->Contains(map())) {
2699 os << "!!!INVALID MAP!!!";
2700 return;
2701 }
2702
2703 os << this << " ";
2704
2705 if (IsString()) {
2706 HeapStringAllocator allocator;
2707 StringStream accumulator(&allocator);
2708 String::cast(this)->StringShortPrint(&accumulator);
2709 os << accumulator.ToCString().get();
2710 return;
2711 }
2712 if (IsJSObject()) {
2713 HeapStringAllocator allocator;
2714 StringStream accumulator(&allocator);
2715 JSObject::cast(this)->JSObjectShortPrint(&accumulator);
2716 os << accumulator.ToCString().get();
2717 return;
2718 }
2719 switch (map()->instance_type()) {
2720 case MAP_TYPE:
2721 os << "<Map(" << ElementsKindToString(Map::cast(this)->elements_kind())
2722 << ")>";
2723 break;
2724 case FIXED_ARRAY_TYPE:
2725 os << "<FixedArray[" << FixedArray::cast(this)->length() << "]>";
2726 break;
2727 case FIXED_DOUBLE_ARRAY_TYPE:
2728 os << "<FixedDoubleArray[" << FixedDoubleArray::cast(this)->length()
2729 << "]>";
2730 break;
2731 case BYTE_ARRAY_TYPE:
2732 os << "<ByteArray[" << ByteArray::cast(this)->length() << "]>";
2733 break;
2734 case BYTECODE_ARRAY_TYPE:
2735 os << "<BytecodeArray[" << BytecodeArray::cast(this)->length() << "]>";
2736 break;
2737 case TRANSITION_ARRAY_TYPE:
2738 os << "<TransitionArray[" << TransitionArray::cast(this)->length()
2739 << "]>";
2740 break;
2741 case FREE_SPACE_TYPE:
2742 os << "<FreeSpace[" << FreeSpace::cast(this)->size() << "]>";
2743 break;
2744 #define TYPED_ARRAY_SHORT_PRINT(Type, type, TYPE, ctype, size) \
2745 case FIXED_##TYPE##_ARRAY_TYPE: \
2746 os << "<Fixed" #Type "Array[" << Fixed##Type##Array::cast(this)->length() \
2747 << "]>"; \
2748 break;
2749
2750 TYPED_ARRAYS(TYPED_ARRAY_SHORT_PRINT)
2751 #undef TYPED_ARRAY_SHORT_PRINT
2752
2753 case SHARED_FUNCTION_INFO_TYPE: {
2754 SharedFunctionInfo* shared = SharedFunctionInfo::cast(this);
2755 std::unique_ptr<char[]> debug_name = shared->DebugName()->ToCString();
2756 if (debug_name[0] != 0) {
2757 os << "<SharedFunctionInfo " << debug_name.get() << ">";
2758 } else {
2759 os << "<SharedFunctionInfo>";
2760 }
2761 break;
2762 }
2763 case JS_MESSAGE_OBJECT_TYPE:
2764 os << "<JSMessageObject>";
2765 break;
2766 #define MAKE_STRUCT_CASE(NAME, Name, name) \
2767 case NAME##_TYPE: \
2768 os << "<" #Name ">"; \
2769 break;
2770 STRUCT_LIST(MAKE_STRUCT_CASE)
2771 #undef MAKE_STRUCT_CASE
2772 case CODE_TYPE: {
2773 Code* code = Code::cast(this);
2774 os << "<Code: " << Code::Kind2String(code->kind()) << ">";
2775 break;
2776 }
2777 case ODDBALL_TYPE: {
2778 if (IsUndefined(isolate)) {
2779 os << "<undefined>";
2780 } else if (IsTheHole(isolate)) {
2781 os << "<the hole>";
2782 } else if (IsNull(isolate)) {
2783 os << "<null>";
2784 } else if (IsTrue(isolate)) {
2785 os << "<true>";
2786 } else if (IsFalse(isolate)) {
2787 os << "<false>";
2788 } else {
2789 os << "<Odd Oddball: ";
2790 os << Oddball::cast(this)->to_string()->ToCString().get();
2791 os << ">";
2792 }
2793 break;
2794 }
2795 case SYMBOL_TYPE: {
2796 Symbol* symbol = Symbol::cast(this);
2797 symbol->SymbolShortPrint(os);
2798 break;
2799 }
2800 case HEAP_NUMBER_TYPE: {
2801 os << "<Number: ";
2802 HeapNumber::cast(this)->HeapNumberPrint(os);
2803 os << ">";
2804 break;
2805 }
2806 case MUTABLE_HEAP_NUMBER_TYPE: {
2807 os << "<MutableNumber: ";
2808 HeapNumber::cast(this)->HeapNumberPrint(os);
2809 os << '>';
2810 break;
2811 }
2812 case SIMD128_VALUE_TYPE: {
2813 #define SIMD128_TYPE(TYPE, Type, type, lane_count, lane_type) \
2814 if (Is##Type()) { \
2815 os << "<" #Type ">"; \
2816 break; \
2817 }
2818 SIMD128_TYPES(SIMD128_TYPE)
2819 #undef SIMD128_TYPE
2820 UNREACHABLE();
2821 break;
2822 }
2823 case JS_PROXY_TYPE:
2824 os << "<JSProxy>";
2825 break;
2826 case FOREIGN_TYPE:
2827 os << "<Foreign>";
2828 break;
2829 case CELL_TYPE: {
2830 os << "Cell for ";
2831 HeapStringAllocator allocator;
2832 StringStream accumulator(&allocator);
2833 Cell::cast(this)->value()->ShortPrint(&accumulator);
2834 os << accumulator.ToCString().get();
2835 break;
2836 }
2837 case PROPERTY_CELL_TYPE: {
2838 os << "PropertyCell for ";
2839 HeapStringAllocator allocator;
2840 StringStream accumulator(&allocator);
2841 PropertyCell* cell = PropertyCell::cast(this);
2842 cell->value()->ShortPrint(&accumulator);
2843 os << accumulator.ToCString().get();
2844 break;
2845 }
2846 case WEAK_CELL_TYPE: {
2847 os << "WeakCell for ";
2848 HeapStringAllocator allocator;
2849 StringStream accumulator(&allocator);
2850 WeakCell::cast(this)->value()->ShortPrint(&accumulator);
2851 os << accumulator.ToCString().get();
2852 break;
2853 }
2854 default:
2855 os << "<Other heap object (" << map()->instance_type() << ")>";
2856 break;
2857 }
2858 }
2859
2860
Iterate(ObjectVisitor * v)2861 void HeapObject::Iterate(ObjectVisitor* v) { IterateFast<ObjectVisitor>(v); }
2862
2863
IterateBody(ObjectVisitor * v)2864 void HeapObject::IterateBody(ObjectVisitor* v) {
2865 Map* m = map();
2866 IterateBodyFast<ObjectVisitor>(m->instance_type(), SizeFromMap(m), v);
2867 }
2868
2869
IterateBody(InstanceType type,int object_size,ObjectVisitor * v)2870 void HeapObject::IterateBody(InstanceType type, int object_size,
2871 ObjectVisitor* v) {
2872 IterateBodyFast<ObjectVisitor>(type, object_size, v);
2873 }
2874
2875
2876 struct CallIsValidSlot {
2877 template <typename BodyDescriptor>
applyv8::internal::CallIsValidSlot2878 static bool apply(HeapObject* obj, int offset, int) {
2879 return BodyDescriptor::IsValidSlot(obj, offset);
2880 }
2881 };
2882
2883
IsValidSlot(int offset)2884 bool HeapObject::IsValidSlot(int offset) {
2885 DCHECK_NE(0, offset);
2886 return BodyDescriptorApply<CallIsValidSlot, bool>(map()->instance_type(),
2887 this, offset, 0);
2888 }
2889
2890
HeapNumberBooleanValue()2891 bool HeapNumber::HeapNumberBooleanValue() {
2892 return DoubleToBoolean(value());
2893 }
2894
2895
HeapNumberPrint(std::ostream & os)2896 void HeapNumber::HeapNumberPrint(std::ostream& os) { // NOLINT
2897 os << value();
2898 }
2899
2900
2901 #define FIELD_ADDR_CONST(p, offset) \
2902 (reinterpret_cast<const byte*>(p) + offset - kHeapObjectTag)
2903
2904 #define READ_INT32_FIELD(p, offset) \
2905 (*reinterpret_cast<const int32_t*>(FIELD_ADDR_CONST(p, offset)))
2906
2907 #define READ_INT64_FIELD(p, offset) \
2908 (*reinterpret_cast<const int64_t*>(FIELD_ADDR_CONST(p, offset)))
2909
2910 #define READ_BYTE_FIELD(p, offset) \
2911 (*reinterpret_cast<const byte*>(FIELD_ADDR_CONST(p, offset)))
2912
2913
2914 // static
ToString(Handle<Simd128Value> input)2915 Handle<String> Simd128Value::ToString(Handle<Simd128Value> input) {
2916 #define SIMD128_TYPE(TYPE, Type, type, lane_count, lane_type) \
2917 if (input->Is##Type()) return Type::ToString(Handle<Type>::cast(input));
2918 SIMD128_TYPES(SIMD128_TYPE)
2919 #undef SIMD128_TYPE
2920 UNREACHABLE();
2921 return Handle<String>::null();
2922 }
2923
2924
2925 // static
ToString(Handle<Float32x4> input)2926 Handle<String> Float32x4::ToString(Handle<Float32x4> input) {
2927 Isolate* const isolate = input->GetIsolate();
2928 char arr[100];
2929 Vector<char> buffer(arr, arraysize(arr));
2930 std::ostringstream os;
2931 os << "SIMD.Float32x4("
2932 << std::string(DoubleToCString(input->get_lane(0), buffer)) << ", "
2933 << std::string(DoubleToCString(input->get_lane(1), buffer)) << ", "
2934 << std::string(DoubleToCString(input->get_lane(2), buffer)) << ", "
2935 << std::string(DoubleToCString(input->get_lane(3), buffer)) << ")";
2936 return isolate->factory()->NewStringFromAsciiChecked(os.str().c_str());
2937 }
2938
2939
2940 #define SIMD128_BOOL_TO_STRING(Type, lane_count) \
2941 Handle<String> Type::ToString(Handle<Type> input) { \
2942 Isolate* const isolate = input->GetIsolate(); \
2943 std::ostringstream os; \
2944 os << "SIMD." #Type "("; \
2945 os << (input->get_lane(0) ? "true" : "false"); \
2946 for (int i = 1; i < lane_count; i++) { \
2947 os << ", " << (input->get_lane(i) ? "true" : "false"); \
2948 } \
2949 os << ")"; \
2950 return isolate->factory()->NewStringFromAsciiChecked(os.str().c_str()); \
2951 }
2952 SIMD128_BOOL_TO_STRING(Bool32x4, 4)
2953 SIMD128_BOOL_TO_STRING(Bool16x8, 8)
2954 SIMD128_BOOL_TO_STRING(Bool8x16, 16)
2955 #undef SIMD128_BOOL_TO_STRING
2956
2957
2958 #define SIMD128_INT_TO_STRING(Type, lane_count) \
2959 Handle<String> Type::ToString(Handle<Type> input) { \
2960 Isolate* const isolate = input->GetIsolate(); \
2961 char arr[100]; \
2962 Vector<char> buffer(arr, arraysize(arr)); \
2963 std::ostringstream os; \
2964 os << "SIMD." #Type "("; \
2965 os << IntToCString(input->get_lane(0), buffer); \
2966 for (int i = 1; i < lane_count; i++) { \
2967 os << ", " << IntToCString(input->get_lane(i), buffer); \
2968 } \
2969 os << ")"; \
2970 return isolate->factory()->NewStringFromAsciiChecked(os.str().c_str()); \
2971 }
2972 SIMD128_INT_TO_STRING(Int32x4, 4)
2973 SIMD128_INT_TO_STRING(Uint32x4, 4)
2974 SIMD128_INT_TO_STRING(Int16x8, 8)
2975 SIMD128_INT_TO_STRING(Uint16x8, 8)
2976 SIMD128_INT_TO_STRING(Int8x16, 16)
2977 SIMD128_INT_TO_STRING(Uint8x16, 16)
2978 #undef SIMD128_INT_TO_STRING
2979
2980
BitwiseEquals(const Simd128Value * other) const2981 bool Simd128Value::BitwiseEquals(const Simd128Value* other) const {
2982 return READ_INT64_FIELD(this, kValueOffset) ==
2983 READ_INT64_FIELD(other, kValueOffset) &&
2984 READ_INT64_FIELD(this, kValueOffset + kInt64Size) ==
2985 READ_INT64_FIELD(other, kValueOffset + kInt64Size);
2986 }
2987
2988
Hash() const2989 uint32_t Simd128Value::Hash() const {
2990 uint32_t seed = v8::internal::kZeroHashSeed;
2991 uint32_t hash;
2992 hash = ComputeIntegerHash(READ_INT32_FIELD(this, kValueOffset), seed);
2993 hash = ComputeIntegerHash(
2994 READ_INT32_FIELD(this, kValueOffset + 1 * kInt32Size), hash * 31);
2995 hash = ComputeIntegerHash(
2996 READ_INT32_FIELD(this, kValueOffset + 2 * kInt32Size), hash * 31);
2997 hash = ComputeIntegerHash(
2998 READ_INT32_FIELD(this, kValueOffset + 3 * kInt32Size), hash * 31);
2999 return hash;
3000 }
3001
3002
CopyBits(void * destination) const3003 void Simd128Value::CopyBits(void* destination) const {
3004 memcpy(destination, &READ_BYTE_FIELD(this, kValueOffset), kSimd128Size);
3005 }
3006
3007
class_name()3008 String* JSReceiver::class_name() {
3009 if (IsFunction()) {
3010 return GetHeap()->Function_string();
3011 }
3012 Object* maybe_constructor = map()->GetConstructor();
3013 if (maybe_constructor->IsJSFunction()) {
3014 JSFunction* constructor = JSFunction::cast(maybe_constructor);
3015 return String::cast(constructor->shared()->instance_class_name());
3016 }
3017 // If the constructor is not present, return "Object".
3018 return GetHeap()->Object_string();
3019 }
3020
3021
3022 // static
GetConstructorName(Handle<JSReceiver> receiver)3023 Handle<String> JSReceiver::GetConstructorName(Handle<JSReceiver> receiver) {
3024 Isolate* isolate = receiver->GetIsolate();
3025
3026 // If the object was instantiated simply with base == new.target, the
3027 // constructor on the map provides the most accurate name.
3028 // Don't provide the info for prototypes, since their constructors are
3029 // reclaimed and replaced by Object in OptimizeAsPrototype.
3030 if (!receiver->IsJSProxy() && receiver->map()->new_target_is_base() &&
3031 !receiver->map()->is_prototype_map()) {
3032 Object* maybe_constructor = receiver->map()->GetConstructor();
3033 if (maybe_constructor->IsJSFunction()) {
3034 JSFunction* constructor = JSFunction::cast(maybe_constructor);
3035 String* name = String::cast(constructor->shared()->name());
3036 if (name->length() == 0) name = constructor->shared()->inferred_name();
3037 if (name->length() != 0 &&
3038 !name->Equals(isolate->heap()->Object_string())) {
3039 return handle(name, isolate);
3040 }
3041 }
3042 }
3043
3044 Handle<Object> maybe_tag = JSReceiver::GetDataProperty(
3045 receiver, isolate->factory()->to_string_tag_symbol());
3046 if (maybe_tag->IsString()) return Handle<String>::cast(maybe_tag);
3047
3048 PrototypeIterator iter(isolate, receiver);
3049 if (iter.IsAtEnd()) return handle(receiver->class_name());
3050 Handle<JSReceiver> start = PrototypeIterator::GetCurrent<JSReceiver>(iter);
3051 LookupIterator it(receiver, isolate->factory()->constructor_string(), start,
3052 LookupIterator::PROTOTYPE_CHAIN_SKIP_INTERCEPTOR);
3053 Handle<Object> maybe_constructor = JSReceiver::GetDataProperty(&it);
3054 Handle<String> result = isolate->factory()->Object_string();
3055 if (maybe_constructor->IsJSFunction()) {
3056 JSFunction* constructor = JSFunction::cast(*maybe_constructor);
3057 String* name = String::cast(constructor->shared()->name());
3058 if (name->length() == 0) name = constructor->shared()->inferred_name();
3059 if (name->length() > 0) result = handle(name, isolate);
3060 }
3061
3062 return result.is_identical_to(isolate->factory()->Object_string())
3063 ? handle(receiver->class_name())
3064 : result;
3065 }
3066
3067
GetCreationContext()3068 Context* JSReceiver::GetCreationContext() {
3069 JSReceiver* receiver = this;
3070 while (receiver->IsJSBoundFunction()) {
3071 receiver = JSBoundFunction::cast(receiver)->bound_target_function();
3072 }
3073 Object* constructor = receiver->map()->GetConstructor();
3074 JSFunction* function;
3075 if (constructor->IsJSFunction()) {
3076 function = JSFunction::cast(constructor);
3077 } else {
3078 // Functions have null as a constructor,
3079 // but any JSFunction knows its context immediately.
3080 CHECK(receiver->IsJSFunction());
3081 function = JSFunction::cast(receiver);
3082 }
3083
3084 return function->context()->native_context();
3085 }
3086
WrapType(Handle<FieldType> type)3087 static Handle<Object> WrapType(Handle<FieldType> type) {
3088 if (type->IsClass()) return Map::WeakCellForMap(type->AsClass());
3089 return type;
3090 }
3091
CopyWithField(Handle<Map> map,Handle<Name> name,Handle<FieldType> type,PropertyAttributes attributes,Representation representation,TransitionFlag flag)3092 MaybeHandle<Map> Map::CopyWithField(Handle<Map> map, Handle<Name> name,
3093 Handle<FieldType> type,
3094 PropertyAttributes attributes,
3095 Representation representation,
3096 TransitionFlag flag) {
3097 DCHECK(DescriptorArray::kNotFound ==
3098 map->instance_descriptors()->Search(
3099 *name, map->NumberOfOwnDescriptors()));
3100
3101 // Ensure the descriptor array does not get too big.
3102 if (map->NumberOfOwnDescriptors() >= kMaxNumberOfDescriptors) {
3103 return MaybeHandle<Map>();
3104 }
3105
3106 Isolate* isolate = map->GetIsolate();
3107
3108 // Compute the new index for new field.
3109 int index = map->NextFreePropertyIndex();
3110
3111 if (map->instance_type() == JS_CONTEXT_EXTENSION_OBJECT_TYPE) {
3112 representation = Representation::Tagged();
3113 type = FieldType::Any(isolate);
3114 }
3115
3116 Handle<Object> wrapped_type(WrapType(type));
3117
3118 DataDescriptor new_field_desc(name, index, wrapped_type, attributes,
3119 representation);
3120 Handle<Map> new_map = Map::CopyAddDescriptor(map, &new_field_desc, flag);
3121 int unused_property_fields = new_map->unused_property_fields() - 1;
3122 if (unused_property_fields < 0) {
3123 unused_property_fields += JSObject::kFieldsAdded;
3124 }
3125 new_map->set_unused_property_fields(unused_property_fields);
3126 return new_map;
3127 }
3128
3129
CopyWithConstant(Handle<Map> map,Handle<Name> name,Handle<Object> constant,PropertyAttributes attributes,TransitionFlag flag)3130 MaybeHandle<Map> Map::CopyWithConstant(Handle<Map> map,
3131 Handle<Name> name,
3132 Handle<Object> constant,
3133 PropertyAttributes attributes,
3134 TransitionFlag flag) {
3135 // Ensure the descriptor array does not get too big.
3136 if (map->NumberOfOwnDescriptors() >= kMaxNumberOfDescriptors) {
3137 return MaybeHandle<Map>();
3138 }
3139
3140 // Allocate new instance descriptors with (name, constant) added.
3141 DataConstantDescriptor new_constant_desc(name, constant, attributes);
3142 return Map::CopyAddDescriptor(map, &new_constant_desc, flag);
3143 }
3144
Mnemonic() const3145 const char* Representation::Mnemonic() const {
3146 switch (kind_) {
3147 case kNone: return "v";
3148 case kTagged: return "t";
3149 case kSmi: return "s";
3150 case kDouble: return "d";
3151 case kInteger32: return "i";
3152 case kHeapObject: return "h";
3153 case kExternal: return "x";
3154 default:
3155 UNREACHABLE();
3156 return NULL;
3157 }
3158 }
3159
InstancesNeedRewriting(Map * target)3160 bool Map::InstancesNeedRewriting(Map* target) {
3161 int target_number_of_fields = target->NumberOfFields();
3162 int target_inobject = target->GetInObjectProperties();
3163 int target_unused = target->unused_property_fields();
3164 int old_number_of_fields;
3165
3166 return InstancesNeedRewriting(target, target_number_of_fields,
3167 target_inobject, target_unused,
3168 &old_number_of_fields);
3169 }
3170
InstancesNeedRewriting(Map * target,int target_number_of_fields,int target_inobject,int target_unused,int * old_number_of_fields)3171 bool Map::InstancesNeedRewriting(Map* target, int target_number_of_fields,
3172 int target_inobject, int target_unused,
3173 int* old_number_of_fields) {
3174 // If fields were added (or removed), rewrite the instance.
3175 *old_number_of_fields = NumberOfFields();
3176 DCHECK(target_number_of_fields >= *old_number_of_fields);
3177 if (target_number_of_fields != *old_number_of_fields) return true;
3178
3179 // If smi descriptors were replaced by double descriptors, rewrite.
3180 DescriptorArray* old_desc = instance_descriptors();
3181 DescriptorArray* new_desc = target->instance_descriptors();
3182 int limit = NumberOfOwnDescriptors();
3183 for (int i = 0; i < limit; i++) {
3184 if (new_desc->GetDetails(i).representation().IsDouble() !=
3185 old_desc->GetDetails(i).representation().IsDouble()) {
3186 return true;
3187 }
3188 }
3189
3190 // If no fields were added, and no inobject properties were removed, setting
3191 // the map is sufficient.
3192 if (target_inobject == GetInObjectProperties()) return false;
3193 // In-object slack tracking may have reduced the object size of the new map.
3194 // In that case, succeed if all existing fields were inobject, and they still
3195 // fit within the new inobject size.
3196 DCHECK(target_inobject < GetInObjectProperties());
3197 if (target_number_of_fields <= target_inobject) {
3198 DCHECK(target_number_of_fields + target_unused == target_inobject);
3199 return false;
3200 }
3201 // Otherwise, properties will need to be moved to the backing store.
3202 return true;
3203 }
3204
3205
3206 // static
UpdatePrototypeUserRegistration(Handle<Map> old_map,Handle<Map> new_map,Isolate * isolate)3207 void JSObject::UpdatePrototypeUserRegistration(Handle<Map> old_map,
3208 Handle<Map> new_map,
3209 Isolate* isolate) {
3210 DCHECK(old_map->is_prototype_map());
3211 DCHECK(new_map->is_prototype_map());
3212 bool was_registered = JSObject::UnregisterPrototypeUser(old_map, isolate);
3213 new_map->set_prototype_info(old_map->prototype_info());
3214 old_map->set_prototype_info(Smi::kZero);
3215 if (FLAG_trace_prototype_users) {
3216 PrintF("Moving prototype_info %p from map %p to map %p.\n",
3217 reinterpret_cast<void*>(new_map->prototype_info()),
3218 reinterpret_cast<void*>(*old_map),
3219 reinterpret_cast<void*>(*new_map));
3220 }
3221 if (was_registered) {
3222 if (new_map->prototype_info()->IsPrototypeInfo()) {
3223 // The new map isn't registered with its prototype yet; reflect this fact
3224 // in the PrototypeInfo it just inherited from the old map.
3225 PrototypeInfo::cast(new_map->prototype_info())
3226 ->set_registry_slot(PrototypeInfo::UNREGISTERED);
3227 }
3228 JSObject::LazyRegisterPrototypeUser(new_map, isolate);
3229 }
3230 }
3231
3232 namespace {
3233 // To migrate a fast instance to a fast map:
3234 // - First check whether the instance needs to be rewritten. If not, simply
3235 // change the map.
3236 // - Otherwise, allocate a fixed array large enough to hold all fields, in
3237 // addition to unused space.
3238 // - Copy all existing properties in, in the following order: backing store
3239 // properties, unused fields, inobject properties.
3240 // - If all allocation succeeded, commit the state atomically:
3241 // * Copy inobject properties from the backing store back into the object.
3242 // * Trim the difference in instance size of the object. This also cleanly
3243 // frees inobject properties that moved to the backing store.
3244 // * If there are properties left in the backing store, trim of the space used
3245 // to temporarily store the inobject properties.
3246 // * If there are properties left in the backing store, install the backing
3247 // store.
MigrateFastToFast(Handle<JSObject> object,Handle<Map> new_map)3248 void MigrateFastToFast(Handle<JSObject> object, Handle<Map> new_map) {
3249 Isolate* isolate = object->GetIsolate();
3250 Handle<Map> old_map(object->map());
3251 // In case of a regular transition.
3252 if (new_map->GetBackPointer() == *old_map) {
3253 // If the map does not add named properties, simply set the map.
3254 if (old_map->NumberOfOwnDescriptors() ==
3255 new_map->NumberOfOwnDescriptors()) {
3256 object->synchronized_set_map(*new_map);
3257 return;
3258 }
3259
3260 PropertyDetails details = new_map->GetLastDescriptorDetails();
3261 // Either new_map adds an kDescriptor property, or a kField property for
3262 // which there is still space, and which does not require a mutable double
3263 // box (an out-of-object double).
3264 if (details.location() == kDescriptor ||
3265 (old_map->unused_property_fields() > 0 &&
3266 ((FLAG_unbox_double_fields && object->properties()->length() == 0) ||
3267 !details.representation().IsDouble()))) {
3268 object->synchronized_set_map(*new_map);
3269 return;
3270 }
3271
3272 // If there is still space in the object, we need to allocate a mutable
3273 // double box.
3274 if (old_map->unused_property_fields() > 0) {
3275 FieldIndex index =
3276 FieldIndex::ForDescriptor(*new_map, new_map->LastAdded());
3277 DCHECK(details.representation().IsDouble());
3278 DCHECK(!new_map->IsUnboxedDoubleField(index));
3279 Handle<Object> value = isolate->factory()->NewHeapNumber(0, MUTABLE);
3280 object->RawFastPropertyAtPut(index, *value);
3281 object->synchronized_set_map(*new_map);
3282 return;
3283 }
3284
3285 // This migration is a transition from a map that has run out of property
3286 // space. Extend the backing store.
3287 int grow_by = new_map->unused_property_fields() + 1;
3288 Handle<FixedArray> old_storage = handle(object->properties(), isolate);
3289 Handle<FixedArray> new_storage =
3290 isolate->factory()->CopyFixedArrayAndGrow(old_storage, grow_by);
3291
3292 // Properly initialize newly added property.
3293 Handle<Object> value;
3294 if (details.representation().IsDouble()) {
3295 value = isolate->factory()->NewHeapNumber(0, MUTABLE);
3296 } else {
3297 value = isolate->factory()->uninitialized_value();
3298 }
3299 DCHECK_EQ(DATA, details.type());
3300 int target_index = details.field_index() - new_map->GetInObjectProperties();
3301 DCHECK(target_index >= 0); // Must be a backing store index.
3302 new_storage->set(target_index, *value);
3303
3304 // From here on we cannot fail and we shouldn't GC anymore.
3305 DisallowHeapAllocation no_allocation;
3306
3307 // Set the new property value and do the map transition.
3308 object->set_properties(*new_storage);
3309 object->synchronized_set_map(*new_map);
3310 return;
3311 }
3312
3313 int old_number_of_fields;
3314 int number_of_fields = new_map->NumberOfFields();
3315 int inobject = new_map->GetInObjectProperties();
3316 int unused = new_map->unused_property_fields();
3317
3318 // Nothing to do if no functions were converted to fields and no smis were
3319 // converted to doubles.
3320 if (!old_map->InstancesNeedRewriting(*new_map, number_of_fields, inobject,
3321 unused, &old_number_of_fields)) {
3322 object->synchronized_set_map(*new_map);
3323 return;
3324 }
3325
3326 int total_size = number_of_fields + unused;
3327 int external = total_size - inobject;
3328
3329 Handle<FixedArray> array = isolate->factory()->NewFixedArray(total_size);
3330
3331 Handle<DescriptorArray> old_descriptors(old_map->instance_descriptors());
3332 Handle<DescriptorArray> new_descriptors(new_map->instance_descriptors());
3333 int old_nof = old_map->NumberOfOwnDescriptors();
3334 int new_nof = new_map->NumberOfOwnDescriptors();
3335
3336 // This method only supports generalizing instances to at least the same
3337 // number of properties.
3338 DCHECK(old_nof <= new_nof);
3339
3340 for (int i = 0; i < old_nof; i++) {
3341 PropertyDetails details = new_descriptors->GetDetails(i);
3342 if (details.type() != DATA) continue;
3343 PropertyDetails old_details = old_descriptors->GetDetails(i);
3344 Representation old_representation = old_details.representation();
3345 Representation representation = details.representation();
3346 Handle<Object> value;
3347 if (old_details.type() == ACCESSOR_CONSTANT) {
3348 // In case of kAccessor -> kData property reconfiguration, the property
3349 // must already be prepared for data or certain type.
3350 DCHECK(!details.representation().IsNone());
3351 if (details.representation().IsDouble()) {
3352 value = isolate->factory()->NewHeapNumber(0, MUTABLE);
3353 } else {
3354 value = isolate->factory()->uninitialized_value();
3355 }
3356 } else if (old_details.type() == DATA_CONSTANT) {
3357 value = handle(old_descriptors->GetValue(i), isolate);
3358 DCHECK(!old_representation.IsDouble() && !representation.IsDouble());
3359 } else {
3360 FieldIndex index = FieldIndex::ForDescriptor(*old_map, i);
3361 if (object->IsUnboxedDoubleField(index)) {
3362 double old = object->RawFastDoublePropertyAt(index);
3363 value = isolate->factory()->NewHeapNumber(
3364 old, representation.IsDouble() ? MUTABLE : IMMUTABLE);
3365
3366 } else {
3367 value = handle(object->RawFastPropertyAt(index), isolate);
3368 if (!old_representation.IsDouble() && representation.IsDouble()) {
3369 if (old_representation.IsNone()) {
3370 value = handle(Smi::kZero, isolate);
3371 }
3372 value = Object::NewStorageFor(isolate, value, representation);
3373 } else if (old_representation.IsDouble() &&
3374 !representation.IsDouble()) {
3375 value = Object::WrapForRead(isolate, value, old_representation);
3376 }
3377 }
3378 }
3379 DCHECK(!(representation.IsDouble() && value->IsSmi()));
3380 int target_index = new_descriptors->GetFieldIndex(i) - inobject;
3381 if (target_index < 0) target_index += total_size;
3382 array->set(target_index, *value);
3383 }
3384
3385 for (int i = old_nof; i < new_nof; i++) {
3386 PropertyDetails details = new_descriptors->GetDetails(i);
3387 if (details.type() != DATA) continue;
3388 Handle<Object> value;
3389 if (details.representation().IsDouble()) {
3390 value = isolate->factory()->NewHeapNumber(0, MUTABLE);
3391 } else {
3392 value = isolate->factory()->uninitialized_value();
3393 }
3394 int target_index = new_descriptors->GetFieldIndex(i) - inobject;
3395 if (target_index < 0) target_index += total_size;
3396 array->set(target_index, *value);
3397 }
3398
3399 // From here on we cannot fail and we shouldn't GC anymore.
3400 DisallowHeapAllocation no_allocation;
3401
3402 Heap* heap = isolate->heap();
3403
3404 // Copy (real) inobject properties. If necessary, stop at number_of_fields to
3405 // avoid overwriting |one_pointer_filler_map|.
3406 int limit = Min(inobject, number_of_fields);
3407 for (int i = 0; i < limit; i++) {
3408 FieldIndex index = FieldIndex::ForPropertyIndex(*new_map, i);
3409 Object* value = array->get(external + i);
3410 // Can't use JSObject::FastPropertyAtPut() because proper map was not set
3411 // yet.
3412 if (new_map->IsUnboxedDoubleField(index)) {
3413 DCHECK(value->IsMutableHeapNumber());
3414 object->RawFastDoublePropertyAtPut(index,
3415 HeapNumber::cast(value)->value());
3416 if (i < old_number_of_fields && !old_map->IsUnboxedDoubleField(index)) {
3417 // Transition from tagged to untagged slot.
3418 heap->ClearRecordedSlot(*object,
3419 HeapObject::RawField(*object, index.offset()));
3420 }
3421 } else {
3422 object->RawFastPropertyAtPut(index, value);
3423 }
3424 }
3425
3426
3427 // If there are properties in the new backing store, trim it to the correct
3428 // size and install the backing store into the object.
3429 if (external > 0) {
3430 heap->RightTrimFixedArray<Heap::CONCURRENT_TO_SWEEPER>(*array, inobject);
3431 object->set_properties(*array);
3432 }
3433
3434 // Create filler object past the new instance size.
3435 int new_instance_size = new_map->instance_size();
3436 int instance_size_delta = old_map->instance_size() - new_instance_size;
3437 DCHECK(instance_size_delta >= 0);
3438
3439 if (instance_size_delta > 0) {
3440 Address address = object->address();
3441 heap->CreateFillerObjectAt(address + new_instance_size, instance_size_delta,
3442 ClearRecordedSlots::kYes);
3443 heap->AdjustLiveBytes(*object, -instance_size_delta,
3444 Heap::CONCURRENT_TO_SWEEPER);
3445 }
3446
3447 // We are storing the new map using release store after creating a filler for
3448 // the left-over space to avoid races with the sweeper thread.
3449 object->synchronized_set_map(*new_map);
3450 }
3451
MigrateFastToSlow(Handle<JSObject> object,Handle<Map> new_map,int expected_additional_properties)3452 void MigrateFastToSlow(Handle<JSObject> object, Handle<Map> new_map,
3453 int expected_additional_properties) {
3454 // The global object is always normalized.
3455 DCHECK(!object->IsJSGlobalObject());
3456 // JSGlobalProxy must never be normalized
3457 DCHECK(!object->IsJSGlobalProxy());
3458
3459 Isolate* isolate = object->GetIsolate();
3460 HandleScope scope(isolate);
3461 Handle<Map> map(object->map());
3462
3463 // Allocate new content.
3464 int real_size = map->NumberOfOwnDescriptors();
3465 int property_count = real_size;
3466 if (expected_additional_properties > 0) {
3467 property_count += expected_additional_properties;
3468 } else {
3469 // Make space for two more properties.
3470 property_count += NameDictionary::kInitialCapacity;
3471 }
3472 Handle<NameDictionary> dictionary =
3473 NameDictionary::New(isolate, property_count);
3474
3475 Handle<DescriptorArray> descs(map->instance_descriptors());
3476 for (int i = 0; i < real_size; i++) {
3477 PropertyDetails details = descs->GetDetails(i);
3478 Handle<Name> key(descs->GetKey(i));
3479 switch (details.type()) {
3480 case DATA_CONSTANT: {
3481 Handle<Object> value(descs->GetConstant(i), isolate);
3482 PropertyDetails d(details.attributes(), DATA, i + 1,
3483 PropertyCellType::kNoCell);
3484 dictionary = NameDictionary::Add(dictionary, key, value, d);
3485 break;
3486 }
3487 case DATA: {
3488 FieldIndex index = FieldIndex::ForDescriptor(*map, i);
3489 Handle<Object> value;
3490 if (object->IsUnboxedDoubleField(index)) {
3491 double old_value = object->RawFastDoublePropertyAt(index);
3492 value = isolate->factory()->NewHeapNumber(old_value);
3493 } else {
3494 value = handle(object->RawFastPropertyAt(index), isolate);
3495 if (details.representation().IsDouble()) {
3496 DCHECK(value->IsMutableHeapNumber());
3497 Handle<HeapNumber> old = Handle<HeapNumber>::cast(value);
3498 value = isolate->factory()->NewHeapNumber(old->value());
3499 }
3500 }
3501 PropertyDetails d(details.attributes(), DATA, i + 1,
3502 PropertyCellType::kNoCell);
3503 dictionary = NameDictionary::Add(dictionary, key, value, d);
3504 break;
3505 }
3506 case ACCESSOR: {
3507 FieldIndex index = FieldIndex::ForDescriptor(*map, i);
3508 Handle<Object> value(object->RawFastPropertyAt(index), isolate);
3509 PropertyDetails d(details.attributes(), ACCESSOR_CONSTANT, i + 1,
3510 PropertyCellType::kNoCell);
3511 dictionary = NameDictionary::Add(dictionary, key, value, d);
3512 break;
3513 }
3514 case ACCESSOR_CONSTANT: {
3515 Handle<Object> value(descs->GetCallbacksObject(i), isolate);
3516 PropertyDetails d(details.attributes(), ACCESSOR_CONSTANT, i + 1,
3517 PropertyCellType::kNoCell);
3518 dictionary = NameDictionary::Add(dictionary, key, value, d);
3519 break;
3520 }
3521 }
3522 }
3523
3524 // Copy the next enumeration index from instance descriptor.
3525 dictionary->SetNextEnumerationIndex(real_size + 1);
3526
3527 // From here on we cannot fail and we shouldn't GC anymore.
3528 DisallowHeapAllocation no_allocation;
3529
3530 // Resize the object in the heap if necessary.
3531 int new_instance_size = new_map->instance_size();
3532 int instance_size_delta = map->instance_size() - new_instance_size;
3533 DCHECK(instance_size_delta >= 0);
3534
3535 if (instance_size_delta > 0) {
3536 Heap* heap = isolate->heap();
3537 heap->CreateFillerObjectAt(object->address() + new_instance_size,
3538 instance_size_delta, ClearRecordedSlots::kYes);
3539 heap->AdjustLiveBytes(*object, -instance_size_delta,
3540 Heap::CONCURRENT_TO_SWEEPER);
3541 }
3542
3543 // We are storing the new map using release store after creating a filler for
3544 // the left-over space to avoid races with the sweeper thread.
3545 object->synchronized_set_map(*new_map);
3546
3547 object->set_properties(*dictionary);
3548
3549 // Ensure that in-object space of slow-mode object does not contain random
3550 // garbage.
3551 int inobject_properties = new_map->GetInObjectProperties();
3552 if (inobject_properties) {
3553 Heap* heap = isolate->heap();
3554 heap->ClearRecordedSlotRange(
3555 object->address() + map->GetInObjectPropertyOffset(0),
3556 object->address() + new_instance_size);
3557
3558 for (int i = 0; i < inobject_properties; i++) {
3559 FieldIndex index = FieldIndex::ForPropertyIndex(*new_map, i);
3560 object->RawFastPropertyAtPut(index, Smi::kZero);
3561 }
3562 }
3563
3564 isolate->counters()->props_to_dictionary()->Increment();
3565
3566 #ifdef DEBUG
3567 if (FLAG_trace_normalization) {
3568 OFStream os(stdout);
3569 os << "Object properties have been normalized:\n";
3570 object->Print(os);
3571 }
3572 #endif
3573 }
3574
3575 } // namespace
3576
3577 // static
NotifyMapChange(Handle<Map> old_map,Handle<Map> new_map,Isolate * isolate)3578 void JSObject::NotifyMapChange(Handle<Map> old_map, Handle<Map> new_map,
3579 Isolate* isolate) {
3580 if (!old_map->is_prototype_map()) return;
3581
3582 InvalidatePrototypeChains(*old_map);
3583
3584 // If the map was registered with its prototype before, ensure that it
3585 // registers with its new prototype now. This preserves the invariant that
3586 // when a map on a prototype chain is registered with its prototype, then
3587 // all prototypes further up the chain are also registered with their
3588 // respective prototypes.
3589 UpdatePrototypeUserRegistration(old_map, new_map, isolate);
3590 }
3591
MigrateToMap(Handle<JSObject> object,Handle<Map> new_map,int expected_additional_properties)3592 void JSObject::MigrateToMap(Handle<JSObject> object, Handle<Map> new_map,
3593 int expected_additional_properties) {
3594 if (object->map() == *new_map) return;
3595 Handle<Map> old_map(object->map());
3596 NotifyMapChange(old_map, new_map, new_map->GetIsolate());
3597
3598 if (old_map->is_dictionary_map()) {
3599 // For slow-to-fast migrations JSObject::MigrateSlowToFast()
3600 // must be used instead.
3601 CHECK(new_map->is_dictionary_map());
3602
3603 // Slow-to-slow migration is trivial.
3604 object->set_map(*new_map);
3605 } else if (!new_map->is_dictionary_map()) {
3606 MigrateFastToFast(object, new_map);
3607 if (old_map->is_prototype_map()) {
3608 DCHECK(!old_map->is_stable());
3609 DCHECK(new_map->is_stable());
3610 // Clear out the old descriptor array to avoid problems to sharing
3611 // the descriptor array without using an explicit.
3612 old_map->InitializeDescriptors(
3613 old_map->GetHeap()->empty_descriptor_array(),
3614 LayoutDescriptor::FastPointerLayout());
3615 // Ensure that no transition was inserted for prototype migrations.
3616 DCHECK_EQ(
3617 0, TransitionArray::NumberOfTransitions(old_map->raw_transitions()));
3618 DCHECK(new_map->GetBackPointer()->IsUndefined(new_map->GetIsolate()));
3619 }
3620 } else {
3621 MigrateFastToSlow(object, new_map, expected_additional_properties);
3622 }
3623
3624 // Careful: Don't allocate here!
3625 // For some callers of this method, |object| might be in an inconsistent
3626 // state now: the new map might have a new elements_kind, but the object's
3627 // elements pointer hasn't been updated yet. Callers will fix this, but in
3628 // the meantime, (indirectly) calling JSObjectVerify() must be avoided.
3629 // When adding code here, add a DisallowHeapAllocation too.
3630 }
3631
ForceSetPrototype(Handle<JSObject> object,Handle<Object> proto)3632 void JSObject::ForceSetPrototype(Handle<JSObject> object,
3633 Handle<Object> proto) {
3634 // object.__proto__ = proto;
3635 Handle<Map> old_map = Handle<Map>(object->map());
3636 Handle<Map> new_map = Map::Copy(old_map, "ForceSetPrototype");
3637 Map::SetPrototype(new_map, proto, FAST_PROTOTYPE);
3638 JSObject::MigrateToMap(object, new_map);
3639 }
3640
NumberOfFields()3641 int Map::NumberOfFields() {
3642 DescriptorArray* descriptors = instance_descriptors();
3643 int result = 0;
3644 for (int i = 0; i < NumberOfOwnDescriptors(); i++) {
3645 if (descriptors->GetDetails(i).location() == kField) result++;
3646 }
3647 return result;
3648 }
3649
CopyGeneralizeAllRepresentations(Handle<Map> map,ElementsKind elements_kind,int modify_index,StoreMode store_mode,PropertyKind kind,PropertyAttributes attributes,const char * reason)3650 Handle<Map> Map::CopyGeneralizeAllRepresentations(
3651 Handle<Map> map, ElementsKind elements_kind, int modify_index,
3652 StoreMode store_mode, PropertyKind kind, PropertyAttributes attributes,
3653 const char* reason) {
3654 Isolate* isolate = map->GetIsolate();
3655 Handle<DescriptorArray> old_descriptors(map->instance_descriptors(), isolate);
3656 int number_of_own_descriptors = map->NumberOfOwnDescriptors();
3657 Handle<DescriptorArray> descriptors =
3658 DescriptorArray::CopyUpTo(old_descriptors, number_of_own_descriptors);
3659
3660 for (int i = 0; i < number_of_own_descriptors; i++) {
3661 descriptors->SetRepresentation(i, Representation::Tagged());
3662 if (descriptors->GetDetails(i).type() == DATA) {
3663 descriptors->SetValue(i, FieldType::Any());
3664 }
3665 }
3666
3667 Handle<LayoutDescriptor> new_layout_descriptor(
3668 LayoutDescriptor::FastPointerLayout(), isolate);
3669 Handle<Map> new_map = CopyReplaceDescriptors(
3670 map, descriptors, new_layout_descriptor, OMIT_TRANSITION,
3671 MaybeHandle<Name>(), reason, SPECIAL_TRANSITION);
3672
3673 // Unless the instance is being migrated, ensure that modify_index is a field.
3674 if (modify_index >= 0) {
3675 PropertyDetails details = descriptors->GetDetails(modify_index);
3676 if (store_mode == FORCE_FIELD &&
3677 (details.type() != DATA || details.attributes() != attributes)) {
3678 int field_index = details.type() == DATA ? details.field_index()
3679 : new_map->NumberOfFields();
3680 DataDescriptor d(handle(descriptors->GetKey(modify_index), isolate),
3681 field_index, attributes, Representation::Tagged());
3682 descriptors->Replace(modify_index, &d);
3683 if (details.type() != DATA) {
3684 int unused_property_fields = new_map->unused_property_fields() - 1;
3685 if (unused_property_fields < 0) {
3686 unused_property_fields += JSObject::kFieldsAdded;
3687 }
3688 new_map->set_unused_property_fields(unused_property_fields);
3689 }
3690 } else {
3691 DCHECK(details.attributes() == attributes);
3692 }
3693
3694 if (FLAG_trace_generalization) {
3695 MaybeHandle<FieldType> field_type = FieldType::None(isolate);
3696 if (details.type() == DATA) {
3697 field_type = handle(
3698 map->instance_descriptors()->GetFieldType(modify_index), isolate);
3699 }
3700 map->PrintGeneralization(
3701 stdout, reason, modify_index, new_map->NumberOfOwnDescriptors(),
3702 new_map->NumberOfOwnDescriptors(),
3703 details.type() == DATA_CONSTANT && store_mode == FORCE_FIELD,
3704 details.representation(), Representation::Tagged(), field_type,
3705 MaybeHandle<Object>(), FieldType::Any(isolate),
3706 MaybeHandle<Object>());
3707 }
3708 }
3709 new_map->set_elements_kind(elements_kind);
3710 return new_map;
3711 }
3712
3713
DeprecateTransitionTree()3714 void Map::DeprecateTransitionTree() {
3715 if (is_deprecated()) return;
3716 Object* transitions = raw_transitions();
3717 int num_transitions = TransitionArray::NumberOfTransitions(transitions);
3718 for (int i = 0; i < num_transitions; ++i) {
3719 TransitionArray::GetTarget(transitions, i)->DeprecateTransitionTree();
3720 }
3721 deprecate();
3722 dependent_code()->DeoptimizeDependentCodeGroup(
3723 GetIsolate(), DependentCode::kTransitionGroup);
3724 NotifyLeafMapLayoutChange();
3725 }
3726
3727
EqualImmutableValues(Object * obj1,Object * obj2)3728 static inline bool EqualImmutableValues(Object* obj1, Object* obj2) {
3729 if (obj1 == obj2) return true; // Valid for both kData and kAccessor kinds.
3730 // TODO(ishell): compare AccessorPairs.
3731 return false;
3732 }
3733
3734
3735 // Installs |new_descriptors| over the current instance_descriptors to ensure
3736 // proper sharing of descriptor arrays.
ReplaceDescriptors(DescriptorArray * new_descriptors,LayoutDescriptor * new_layout_descriptor)3737 void Map::ReplaceDescriptors(DescriptorArray* new_descriptors,
3738 LayoutDescriptor* new_layout_descriptor) {
3739 Isolate* isolate = GetIsolate();
3740 // Don't overwrite the empty descriptor array or initial map's descriptors.
3741 if (NumberOfOwnDescriptors() == 0 || GetBackPointer()->IsUndefined(isolate)) {
3742 return;
3743 }
3744
3745 DescriptorArray* to_replace = instance_descriptors();
3746 isolate->heap()->incremental_marking()->IterateBlackObject(to_replace);
3747 Map* current = this;
3748 while (current->instance_descriptors() == to_replace) {
3749 Object* next = current->GetBackPointer();
3750 if (next->IsUndefined(isolate)) break; // Stop overwriting at initial map.
3751 current->SetEnumLength(kInvalidEnumCacheSentinel);
3752 current->UpdateDescriptors(new_descriptors, new_layout_descriptor);
3753 current = Map::cast(next);
3754 }
3755 set_owns_descriptors(false);
3756 }
3757
3758
FindRootMap()3759 Map* Map::FindRootMap() {
3760 Map* result = this;
3761 Isolate* isolate = GetIsolate();
3762 while (true) {
3763 Object* back = result->GetBackPointer();
3764 if (back->IsUndefined(isolate)) {
3765 // Initial map always owns descriptors and doesn't have unused entries
3766 // in the descriptor array.
3767 DCHECK(result->owns_descriptors());
3768 DCHECK_EQ(result->NumberOfOwnDescriptors(),
3769 result->instance_descriptors()->number_of_descriptors());
3770 return result;
3771 }
3772 result = Map::cast(back);
3773 }
3774 }
3775
3776
FindLastMatchMap(int verbatim,int length,DescriptorArray * descriptors)3777 Map* Map::FindLastMatchMap(int verbatim,
3778 int length,
3779 DescriptorArray* descriptors) {
3780 DisallowHeapAllocation no_allocation;
3781
3782 // This can only be called on roots of transition trees.
3783 DCHECK_EQ(verbatim, NumberOfOwnDescriptors());
3784
3785 Map* current = this;
3786
3787 for (int i = verbatim; i < length; i++) {
3788 Name* name = descriptors->GetKey(i);
3789 PropertyDetails details = descriptors->GetDetails(i);
3790 Map* next = TransitionArray::SearchTransition(current, details.kind(), name,
3791 details.attributes());
3792 if (next == NULL) break;
3793 DescriptorArray* next_descriptors = next->instance_descriptors();
3794
3795 PropertyDetails next_details = next_descriptors->GetDetails(i);
3796 DCHECK_EQ(details.kind(), next_details.kind());
3797 DCHECK_EQ(details.attributes(), next_details.attributes());
3798 if (details.location() != next_details.location()) break;
3799 if (!details.representation().Equals(next_details.representation())) break;
3800
3801 if (next_details.location() == kField) {
3802 FieldType* next_field_type = next_descriptors->GetFieldType(i);
3803 if (!descriptors->GetFieldType(i)->NowIs(next_field_type)) {
3804 break;
3805 }
3806 } else {
3807 if (!EqualImmutableValues(descriptors->GetValue(i),
3808 next_descriptors->GetValue(i))) {
3809 break;
3810 }
3811 }
3812 current = next;
3813 }
3814 return current;
3815 }
3816
3817
FindFieldOwner(int descriptor)3818 Map* Map::FindFieldOwner(int descriptor) {
3819 DisallowHeapAllocation no_allocation;
3820 DCHECK_EQ(DATA, instance_descriptors()->GetDetails(descriptor).type());
3821 Map* result = this;
3822 Isolate* isolate = GetIsolate();
3823 while (true) {
3824 Object* back = result->GetBackPointer();
3825 if (back->IsUndefined(isolate)) break;
3826 Map* parent = Map::cast(back);
3827 if (parent->NumberOfOwnDescriptors() <= descriptor) break;
3828 result = parent;
3829 }
3830 return result;
3831 }
3832
3833
UpdateFieldType(int descriptor,Handle<Name> name,Representation new_representation,Handle<Object> new_wrapped_type)3834 void Map::UpdateFieldType(int descriptor, Handle<Name> name,
3835 Representation new_representation,
3836 Handle<Object> new_wrapped_type) {
3837 DCHECK(new_wrapped_type->IsSmi() || new_wrapped_type->IsWeakCell());
3838 // We store raw pointers in the queue, so no allocations are allowed.
3839 DisallowHeapAllocation no_allocation;
3840 PropertyDetails details = instance_descriptors()->GetDetails(descriptor);
3841 if (details.type() != DATA) return;
3842
3843 Zone zone(GetIsolate()->allocator(), ZONE_NAME);
3844 ZoneQueue<Map*> backlog(&zone);
3845 backlog.push(this);
3846
3847 while (!backlog.empty()) {
3848 Map* current = backlog.front();
3849 backlog.pop();
3850
3851 Object* transitions = current->raw_transitions();
3852 int num_transitions = TransitionArray::NumberOfTransitions(transitions);
3853 for (int i = 0; i < num_transitions; ++i) {
3854 Map* target = TransitionArray::GetTarget(transitions, i);
3855 backlog.push(target);
3856 }
3857 DescriptorArray* descriptors = current->instance_descriptors();
3858 PropertyDetails details = descriptors->GetDetails(descriptor);
3859
3860 // It is allowed to change representation here only from None to something.
3861 DCHECK(details.representation().Equals(new_representation) ||
3862 details.representation().IsNone());
3863
3864 // Skip if already updated the shared descriptor.
3865 if (descriptors->GetValue(descriptor) != *new_wrapped_type) {
3866 DataDescriptor d(name, descriptors->GetFieldIndex(descriptor),
3867 new_wrapped_type, details.attributes(),
3868 new_representation);
3869 descriptors->Replace(descriptor, &d);
3870 }
3871 }
3872 }
3873
FieldTypeIsCleared(Representation rep,FieldType * type)3874 bool FieldTypeIsCleared(Representation rep, FieldType* type) {
3875 return type->IsNone() && rep.IsHeapObject();
3876 }
3877
3878
3879 // static
GeneralizeFieldType(Representation rep1,Handle<FieldType> type1,Representation rep2,Handle<FieldType> type2,Isolate * isolate)3880 Handle<FieldType> Map::GeneralizeFieldType(Representation rep1,
3881 Handle<FieldType> type1,
3882 Representation rep2,
3883 Handle<FieldType> type2,
3884 Isolate* isolate) {
3885 // Cleared field types need special treatment. They represent lost knowledge,
3886 // so we must be conservative, so their generalization with any other type
3887 // is "Any".
3888 if (FieldTypeIsCleared(rep1, *type1) || FieldTypeIsCleared(rep2, *type2)) {
3889 return FieldType::Any(isolate);
3890 }
3891 if (type1->NowIs(type2)) return type2;
3892 if (type2->NowIs(type1)) return type1;
3893 return FieldType::Any(isolate);
3894 }
3895
3896
3897 // static
GeneralizeFieldType(Handle<Map> map,int modify_index,Representation new_representation,Handle<FieldType> new_field_type)3898 void Map::GeneralizeFieldType(Handle<Map> map, int modify_index,
3899 Representation new_representation,
3900 Handle<FieldType> new_field_type) {
3901 Isolate* isolate = map->GetIsolate();
3902
3903 // Check if we actually need to generalize the field type at all.
3904 Handle<DescriptorArray> old_descriptors(map->instance_descriptors(), isolate);
3905 Representation old_representation =
3906 old_descriptors->GetDetails(modify_index).representation();
3907 Handle<FieldType> old_field_type(old_descriptors->GetFieldType(modify_index),
3908 isolate);
3909
3910 if (old_representation.Equals(new_representation) &&
3911 !FieldTypeIsCleared(new_representation, *new_field_type) &&
3912 // Checking old_field_type for being cleared is not necessary because
3913 // the NowIs check below would fail anyway in that case.
3914 new_field_type->NowIs(old_field_type)) {
3915 DCHECK(Map::GeneralizeFieldType(old_representation, old_field_type,
3916 new_representation, new_field_type, isolate)
3917 ->NowIs(old_field_type));
3918 return;
3919 }
3920
3921 // Determine the field owner.
3922 Handle<Map> field_owner(map->FindFieldOwner(modify_index), isolate);
3923 Handle<DescriptorArray> descriptors(
3924 field_owner->instance_descriptors(), isolate);
3925 DCHECK_EQ(*old_field_type, descriptors->GetFieldType(modify_index));
3926
3927 new_field_type =
3928 Map::GeneralizeFieldType(old_representation, old_field_type,
3929 new_representation, new_field_type, isolate);
3930
3931 PropertyDetails details = descriptors->GetDetails(modify_index);
3932 Handle<Name> name(descriptors->GetKey(modify_index));
3933
3934 Handle<Object> wrapped_type(WrapType(new_field_type));
3935 field_owner->UpdateFieldType(modify_index, name, new_representation,
3936 wrapped_type);
3937 field_owner->dependent_code()->DeoptimizeDependentCodeGroup(
3938 isolate, DependentCode::kFieldOwnerGroup);
3939
3940 if (FLAG_trace_generalization) {
3941 map->PrintGeneralization(
3942 stdout, "field type generalization", modify_index,
3943 map->NumberOfOwnDescriptors(), map->NumberOfOwnDescriptors(), false,
3944 details.representation(), details.representation(), old_field_type,
3945 MaybeHandle<Object>(), new_field_type, MaybeHandle<Object>());
3946 }
3947 }
3948
GetFieldType(Isolate * isolate,Handle<DescriptorArray> descriptors,int descriptor,PropertyLocation location,Representation representation)3949 static inline Handle<FieldType> GetFieldType(
3950 Isolate* isolate, Handle<DescriptorArray> descriptors, int descriptor,
3951 PropertyLocation location, Representation representation) {
3952 #ifdef DEBUG
3953 PropertyDetails details = descriptors->GetDetails(descriptor);
3954 DCHECK_EQ(kData, details.kind());
3955 DCHECK_EQ(details.location(), location);
3956 #endif
3957 if (location == kField) {
3958 return handle(descriptors->GetFieldType(descriptor), isolate);
3959 } else {
3960 return descriptors->GetValue(descriptor)
3961 ->OptimalType(isolate, representation);
3962 }
3963 }
3964
3965 // Reconfigures elements kind to |new_elements_kind| and/or property at
3966 // |modify_index| with |new_kind|, |new_attributes|, |store_mode| and/or
3967 // |new_representation|/|new_field_type|.
3968 // If |modify_index| is negative then no properties are reconfigured but the
3969 // map is migrated to the up-to-date non-deprecated state.
3970 //
3971 // This method rewrites or completes the transition tree to reflect the new
3972 // change. To avoid high degrees over polymorphism, and to stabilize quickly,
3973 // on every rewrite the new type is deduced by merging the current type with
3974 // any potential new (partial) version of the type in the transition tree.
3975 // To do this, on each rewrite:
3976 // - Search the root of the transition tree using FindRootMap.
3977 // - Find/create a |root_map| with requested |new_elements_kind|.
3978 // - Find |target_map|, the newest matching version of this map using the
3979 // virtually "enhanced" |old_map|'s descriptor array (i.e. whose entry at
3980 // |modify_index| is considered to be of |new_kind| and having
3981 // |new_attributes|) to walk the transition tree.
3982 // - Merge/generalize the "enhanced" descriptor array of the |old_map| and
3983 // descriptor array of the |target_map|.
3984 // - Generalize the |modify_index| descriptor using |new_representation| and
3985 // |new_field_type|.
3986 // - Walk the tree again starting from the root towards |target_map|. Stop at
3987 // |split_map|, the first map who's descriptor array does not match the merged
3988 // descriptor array.
3989 // - If |target_map| == |split_map|, |target_map| is in the expected state.
3990 // Return it.
3991 // - Otherwise, invalidate the outdated transition target from |target_map|, and
3992 // replace its transition tree with a new branch for the updated descriptors.
Reconfigure(Handle<Map> old_map,ElementsKind new_elements_kind,int modify_index,PropertyKind new_kind,PropertyAttributes new_attributes,Representation new_representation,Handle<FieldType> new_field_type,StoreMode store_mode)3993 Handle<Map> Map::Reconfigure(Handle<Map> old_map,
3994 ElementsKind new_elements_kind, int modify_index,
3995 PropertyKind new_kind,
3996 PropertyAttributes new_attributes,
3997 Representation new_representation,
3998 Handle<FieldType> new_field_type,
3999 StoreMode store_mode) {
4000 DCHECK_NE(kAccessor, new_kind); // TODO(ishell): not supported yet.
4001 DCHECK(store_mode != FORCE_FIELD || modify_index >= 0);
4002 Isolate* isolate = old_map->GetIsolate();
4003
4004 Handle<DescriptorArray> old_descriptors(
4005 old_map->instance_descriptors(), isolate);
4006 int old_nof = old_map->NumberOfOwnDescriptors();
4007
4008 // If it's just a representation generalization case (i.e. property kind and
4009 // attributes stays unchanged) it's fine to transition from None to anything
4010 // but double without any modification to the object, because the default
4011 // uninitialized value for representation None can be overwritten by both
4012 // smi and tagged values. Doubles, however, would require a box allocation.
4013 if (modify_index >= 0 && !new_representation.IsNone() &&
4014 !new_representation.IsDouble() &&
4015 old_map->elements_kind() == new_elements_kind) {
4016 PropertyDetails old_details = old_descriptors->GetDetails(modify_index);
4017 Representation old_representation = old_details.representation();
4018
4019 if (old_representation.IsNone()) {
4020 DCHECK_EQ(new_kind, old_details.kind());
4021 DCHECK_EQ(new_attributes, old_details.attributes());
4022 DCHECK_EQ(DATA, old_details.type());
4023 if (FLAG_trace_generalization) {
4024 old_map->PrintGeneralization(
4025 stdout, "uninitialized field", modify_index,
4026 old_map->NumberOfOwnDescriptors(),
4027 old_map->NumberOfOwnDescriptors(), false, old_representation,
4028 new_representation,
4029 handle(old_descriptors->GetFieldType(modify_index), isolate),
4030 MaybeHandle<Object>(), new_field_type, MaybeHandle<Object>());
4031 }
4032 Handle<Map> field_owner(old_map->FindFieldOwner(modify_index), isolate);
4033
4034 GeneralizeFieldType(field_owner, modify_index, new_representation,
4035 new_field_type);
4036 DCHECK(old_descriptors->GetDetails(modify_index)
4037 .representation()
4038 .Equals(new_representation));
4039 DCHECK(
4040 old_descriptors->GetFieldType(modify_index)->NowIs(new_field_type));
4041 return old_map;
4042 }
4043 }
4044
4045 // Check the state of the root map.
4046 Handle<Map> root_map(old_map->FindRootMap(), isolate);
4047 if (!old_map->EquivalentToForTransition(*root_map)) {
4048 return CopyGeneralizeAllRepresentations(
4049 old_map, new_elements_kind, modify_index, store_mode, new_kind,
4050 new_attributes, "GenAll_NotEquivalent");
4051 }
4052
4053 ElementsKind from_kind = root_map->elements_kind();
4054 ElementsKind to_kind = new_elements_kind;
4055 // TODO(ishell): Add a test for SLOW_SLOPPY_ARGUMENTS_ELEMENTS.
4056 if (from_kind != to_kind && to_kind != DICTIONARY_ELEMENTS &&
4057 to_kind != SLOW_STRING_WRAPPER_ELEMENTS &&
4058 to_kind != SLOW_SLOPPY_ARGUMENTS_ELEMENTS &&
4059 !(IsTransitionableFastElementsKind(from_kind) &&
4060 IsMoreGeneralElementsKindTransition(from_kind, to_kind))) {
4061 return CopyGeneralizeAllRepresentations(
4062 old_map, to_kind, modify_index, store_mode, new_kind, new_attributes,
4063 "GenAll_InvalidElementsTransition");
4064 }
4065 int root_nof = root_map->NumberOfOwnDescriptors();
4066 if (modify_index >= 0 && modify_index < root_nof) {
4067 PropertyDetails old_details = old_descriptors->GetDetails(modify_index);
4068 if (old_details.kind() != new_kind ||
4069 old_details.attributes() != new_attributes) {
4070 return CopyGeneralizeAllRepresentations(
4071 old_map, to_kind, modify_index, store_mode, new_kind, new_attributes,
4072 "GenAll_RootModification1");
4073 }
4074 if ((old_details.type() != DATA && store_mode == FORCE_FIELD) ||
4075 (old_details.type() == DATA &&
4076 (!new_field_type->NowIs(old_descriptors->GetFieldType(modify_index)) ||
4077 !new_representation.fits_into(old_details.representation())))) {
4078 return CopyGeneralizeAllRepresentations(
4079 old_map, to_kind, modify_index, store_mode, new_kind, new_attributes,
4080 "GenAll_RootModification2");
4081 }
4082 }
4083
4084 // From here on, use the map with correct elements kind as root map.
4085 if (from_kind != to_kind) {
4086 root_map = Map::AsElementsKind(root_map, to_kind);
4087 }
4088
4089 Handle<Map> target_map = root_map;
4090 for (int i = root_nof; i < old_nof; ++i) {
4091 PropertyDetails old_details = old_descriptors->GetDetails(i);
4092 PropertyKind next_kind;
4093 PropertyLocation next_location;
4094 PropertyAttributes next_attributes;
4095 Representation next_representation;
4096 bool property_kind_reconfiguration = false;
4097
4098 if (modify_index == i) {
4099 DCHECK_EQ(FORCE_FIELD, store_mode);
4100 property_kind_reconfiguration = old_details.kind() != new_kind;
4101
4102 next_kind = new_kind;
4103 next_location = kField;
4104 next_attributes = new_attributes;
4105 // If property kind is not reconfigured merge the result with
4106 // representation/field type from the old descriptor.
4107 next_representation = new_representation;
4108 if (!property_kind_reconfiguration) {
4109 next_representation =
4110 next_representation.generalize(old_details.representation());
4111 }
4112
4113 } else {
4114 next_kind = old_details.kind();
4115 next_location = old_details.location();
4116 next_attributes = old_details.attributes();
4117 next_representation = old_details.representation();
4118 }
4119 Map* transition = TransitionArray::SearchTransition(
4120 *target_map, next_kind, old_descriptors->GetKey(i), next_attributes);
4121 if (transition == NULL) break;
4122 Handle<Map> tmp_map(transition, isolate);
4123
4124 Handle<DescriptorArray> tmp_descriptors = handle(
4125 tmp_map->instance_descriptors(), isolate);
4126
4127 // Check if target map is incompatible.
4128 PropertyDetails tmp_details = tmp_descriptors->GetDetails(i);
4129 DCHECK_EQ(next_kind, tmp_details.kind());
4130 DCHECK_EQ(next_attributes, tmp_details.attributes());
4131 if (next_kind == kAccessor &&
4132 !EqualImmutableValues(old_descriptors->GetValue(i),
4133 tmp_descriptors->GetValue(i))) {
4134 return CopyGeneralizeAllRepresentations(
4135 old_map, to_kind, modify_index, store_mode, new_kind, new_attributes,
4136 "GenAll_Incompatible");
4137 }
4138 if (next_location == kField && tmp_details.location() == kDescriptor) break;
4139
4140 Representation tmp_representation = tmp_details.representation();
4141 if (!next_representation.fits_into(tmp_representation)) break;
4142
4143 PropertyLocation old_location = old_details.location();
4144 PropertyLocation tmp_location = tmp_details.location();
4145 if (tmp_location == kField) {
4146 if (next_kind == kData) {
4147 Handle<FieldType> next_field_type;
4148 if (modify_index == i) {
4149 next_field_type = new_field_type;
4150 if (!property_kind_reconfiguration) {
4151 Handle<FieldType> old_field_type =
4152 GetFieldType(isolate, old_descriptors, i,
4153 old_details.location(), tmp_representation);
4154 Representation old_representation = old_details.representation();
4155 next_field_type = GeneralizeFieldType(
4156 old_representation, old_field_type, new_representation,
4157 next_field_type, isolate);
4158 }
4159 } else {
4160 Handle<FieldType> old_field_type =
4161 GetFieldType(isolate, old_descriptors, i, old_details.location(),
4162 tmp_representation);
4163 next_field_type = old_field_type;
4164 }
4165 GeneralizeFieldType(tmp_map, i, tmp_representation, next_field_type);
4166 }
4167 } else if (old_location == kField ||
4168 !EqualImmutableValues(old_descriptors->GetValue(i),
4169 tmp_descriptors->GetValue(i))) {
4170 break;
4171 }
4172 DCHECK(!tmp_map->is_deprecated());
4173 target_map = tmp_map;
4174 }
4175
4176 // Directly change the map if the target map is more general.
4177 Handle<DescriptorArray> target_descriptors(
4178 target_map->instance_descriptors(), isolate);
4179 int target_nof = target_map->NumberOfOwnDescriptors();
4180 if (target_nof == old_nof &&
4181 (store_mode != FORCE_FIELD ||
4182 (modify_index >= 0 &&
4183 target_descriptors->GetDetails(modify_index).location() == kField))) {
4184 #ifdef DEBUG
4185 if (modify_index >= 0) {
4186 PropertyDetails details = target_descriptors->GetDetails(modify_index);
4187 DCHECK_EQ(new_kind, details.kind());
4188 DCHECK_EQ(new_attributes, details.attributes());
4189 DCHECK(new_representation.fits_into(details.representation()));
4190 DCHECK(details.location() != kField ||
4191 new_field_type->NowIs(
4192 target_descriptors->GetFieldType(modify_index)));
4193 }
4194 #endif
4195 if (*target_map != *old_map) {
4196 old_map->NotifyLeafMapLayoutChange();
4197 }
4198 return target_map;
4199 }
4200
4201 // Find the last compatible target map in the transition tree.
4202 for (int i = target_nof; i < old_nof; ++i) {
4203 PropertyDetails old_details = old_descriptors->GetDetails(i);
4204 PropertyKind next_kind;
4205 PropertyAttributes next_attributes;
4206 if (modify_index == i) {
4207 next_kind = new_kind;
4208 next_attributes = new_attributes;
4209 } else {
4210 next_kind = old_details.kind();
4211 next_attributes = old_details.attributes();
4212 }
4213 Map* transition = TransitionArray::SearchTransition(
4214 *target_map, next_kind, old_descriptors->GetKey(i), next_attributes);
4215 if (transition == NULL) break;
4216 Handle<Map> tmp_map(transition, isolate);
4217 Handle<DescriptorArray> tmp_descriptors(
4218 tmp_map->instance_descriptors(), isolate);
4219
4220 // Check if target map is compatible.
4221 #ifdef DEBUG
4222 PropertyDetails tmp_details = tmp_descriptors->GetDetails(i);
4223 DCHECK_EQ(next_kind, tmp_details.kind());
4224 DCHECK_EQ(next_attributes, tmp_details.attributes());
4225 #endif
4226 if (next_kind == kAccessor &&
4227 !EqualImmutableValues(old_descriptors->GetValue(i),
4228 tmp_descriptors->GetValue(i))) {
4229 return CopyGeneralizeAllRepresentations(
4230 old_map, to_kind, modify_index, store_mode, new_kind, new_attributes,
4231 "GenAll_Incompatible");
4232 }
4233 DCHECK(!tmp_map->is_deprecated());
4234 target_map = tmp_map;
4235 }
4236 target_nof = target_map->NumberOfOwnDescriptors();
4237 target_descriptors = handle(target_map->instance_descriptors(), isolate);
4238
4239 // Allocate a new descriptor array large enough to hold the required
4240 // descriptors, with minimally the exact same size as the old descriptor
4241 // array.
4242 int new_slack = Max(
4243 old_nof, old_descriptors->number_of_descriptors()) - old_nof;
4244 Handle<DescriptorArray> new_descriptors = DescriptorArray::Allocate(
4245 isolate, old_nof, new_slack);
4246 DCHECK(new_descriptors->length() > target_descriptors->length() ||
4247 new_descriptors->NumberOfSlackDescriptors() > 0 ||
4248 new_descriptors->number_of_descriptors() ==
4249 old_descriptors->number_of_descriptors());
4250 DCHECK(new_descriptors->number_of_descriptors() == old_nof);
4251
4252 // 0 -> |root_nof|
4253 int current_offset = 0;
4254 for (int i = 0; i < root_nof; ++i) {
4255 PropertyDetails old_details = old_descriptors->GetDetails(i);
4256 if (old_details.location() == kField) {
4257 current_offset += old_details.field_width_in_words();
4258 }
4259 Descriptor d(handle(old_descriptors->GetKey(i), isolate),
4260 handle(old_descriptors->GetValue(i), isolate),
4261 old_details);
4262 new_descriptors->Set(i, &d);
4263 }
4264
4265 // |root_nof| -> |target_nof|
4266 for (int i = root_nof; i < target_nof; ++i) {
4267 Handle<Name> target_key(target_descriptors->GetKey(i), isolate);
4268 PropertyDetails old_details = old_descriptors->GetDetails(i);
4269 PropertyDetails target_details = target_descriptors->GetDetails(i);
4270
4271 PropertyKind next_kind;
4272 PropertyAttributes next_attributes;
4273 PropertyLocation next_location;
4274 Representation next_representation;
4275 bool property_kind_reconfiguration = false;
4276
4277 if (modify_index == i) {
4278 DCHECK_EQ(FORCE_FIELD, store_mode);
4279 property_kind_reconfiguration = old_details.kind() != new_kind;
4280
4281 next_kind = new_kind;
4282 next_attributes = new_attributes;
4283 next_location = kField;
4284
4285 // Merge new representation/field type with ones from the target
4286 // descriptor. If property kind is not reconfigured merge the result with
4287 // representation/field type from the old descriptor.
4288 next_representation =
4289 new_representation.generalize(target_details.representation());
4290 if (!property_kind_reconfiguration) {
4291 next_representation =
4292 next_representation.generalize(old_details.representation());
4293 }
4294 } else {
4295 // Merge old_descriptor and target_descriptor entries.
4296 DCHECK_EQ(target_details.kind(), old_details.kind());
4297 next_kind = target_details.kind();
4298 next_attributes = target_details.attributes();
4299 next_location =
4300 old_details.location() == kField ||
4301 target_details.location() == kField ||
4302 !EqualImmutableValues(target_descriptors->GetValue(i),
4303 old_descriptors->GetValue(i))
4304 ? kField
4305 : kDescriptor;
4306
4307 next_representation = old_details.representation().generalize(
4308 target_details.representation());
4309 }
4310 DCHECK_EQ(next_kind, target_details.kind());
4311 DCHECK_EQ(next_attributes, target_details.attributes());
4312
4313 if (next_location == kField) {
4314 if (next_kind == kData) {
4315 Handle<FieldType> target_field_type =
4316 GetFieldType(isolate, target_descriptors, i,
4317 target_details.location(), next_representation);
4318
4319 Handle<FieldType> next_field_type;
4320 if (modify_index == i) {
4321 next_field_type = GeneralizeFieldType(
4322 target_details.representation(), target_field_type,
4323 new_representation, new_field_type, isolate);
4324 if (!property_kind_reconfiguration) {
4325 Handle<FieldType> old_field_type =
4326 GetFieldType(isolate, old_descriptors, i,
4327 old_details.location(), next_representation);
4328 next_field_type = GeneralizeFieldType(
4329 old_details.representation(), old_field_type,
4330 next_representation, next_field_type, isolate);
4331 }
4332 } else {
4333 Handle<FieldType> old_field_type =
4334 GetFieldType(isolate, old_descriptors, i, old_details.location(),
4335 next_representation);
4336 next_field_type = GeneralizeFieldType(
4337 old_details.representation(), old_field_type, next_representation,
4338 target_field_type, isolate);
4339 }
4340 Handle<Object> wrapped_type(WrapType(next_field_type));
4341 DataDescriptor d(target_key, current_offset, wrapped_type,
4342 next_attributes, next_representation);
4343 current_offset += d.GetDetails().field_width_in_words();
4344 new_descriptors->Set(i, &d);
4345 } else {
4346 UNIMPLEMENTED(); // TODO(ishell): implement.
4347 }
4348 } else {
4349 PropertyDetails details(next_attributes, next_kind, next_location,
4350 next_representation);
4351 Descriptor d(target_key, handle(target_descriptors->GetValue(i), isolate),
4352 details);
4353 new_descriptors->Set(i, &d);
4354 }
4355 }
4356
4357 // |target_nof| -> |old_nof|
4358 for (int i = target_nof; i < old_nof; ++i) {
4359 PropertyDetails old_details = old_descriptors->GetDetails(i);
4360 Handle<Name> old_key(old_descriptors->GetKey(i), isolate);
4361
4362 // Merge old_descriptor entry and modified details together.
4363 PropertyKind next_kind;
4364 PropertyAttributes next_attributes;
4365 PropertyLocation next_location;
4366 Representation next_representation;
4367 bool property_kind_reconfiguration = false;
4368
4369 if (modify_index == i) {
4370 DCHECK_EQ(FORCE_FIELD, store_mode);
4371 // In case of property kind reconfiguration it is not necessary to
4372 // take into account representation/field type of the old descriptor.
4373 property_kind_reconfiguration = old_details.kind() != new_kind;
4374
4375 next_kind = new_kind;
4376 next_attributes = new_attributes;
4377 next_location = kField;
4378 next_representation = new_representation;
4379 if (!property_kind_reconfiguration) {
4380 next_representation =
4381 next_representation.generalize(old_details.representation());
4382 }
4383 } else {
4384 next_kind = old_details.kind();
4385 next_attributes = old_details.attributes();
4386 next_location = old_details.location();
4387 next_representation = old_details.representation();
4388 }
4389
4390 if (next_location == kField) {
4391 if (next_kind == kData) {
4392 Handle<FieldType> next_field_type;
4393 if (modify_index == i) {
4394 next_field_type = new_field_type;
4395 if (!property_kind_reconfiguration) {
4396 Handle<FieldType> old_field_type =
4397 GetFieldType(isolate, old_descriptors, i,
4398 old_details.location(), next_representation);
4399 next_field_type = GeneralizeFieldType(
4400 old_details.representation(), old_field_type,
4401 next_representation, next_field_type, isolate);
4402 }
4403 } else {
4404 Handle<FieldType> old_field_type =
4405 GetFieldType(isolate, old_descriptors, i, old_details.location(),
4406 next_representation);
4407 next_field_type = old_field_type;
4408 }
4409
4410 Handle<Object> wrapped_type(WrapType(next_field_type));
4411
4412 DataDescriptor d(old_key, current_offset, wrapped_type, next_attributes,
4413 next_representation);
4414 current_offset += d.GetDetails().field_width_in_words();
4415 new_descriptors->Set(i, &d);
4416 } else {
4417 UNIMPLEMENTED(); // TODO(ishell): implement.
4418 }
4419 } else {
4420 PropertyDetails details(next_attributes, next_kind, next_location,
4421 next_representation);
4422 Descriptor d(old_key, handle(old_descriptors->GetValue(i), isolate),
4423 details);
4424 new_descriptors->Set(i, &d);
4425 }
4426 }
4427
4428 new_descriptors->Sort();
4429
4430 DCHECK(store_mode != FORCE_FIELD ||
4431 new_descriptors->GetDetails(modify_index).location() == kField);
4432
4433 Handle<Map> split_map(root_map->FindLastMatchMap(
4434 root_nof, old_nof, *new_descriptors), isolate);
4435 int split_nof = split_map->NumberOfOwnDescriptors();
4436 DCHECK_NE(old_nof, split_nof);
4437
4438 PropertyKind split_kind;
4439 PropertyAttributes split_attributes;
4440 if (modify_index == split_nof) {
4441 split_kind = new_kind;
4442 split_attributes = new_attributes;
4443 } else {
4444 PropertyDetails split_prop_details = old_descriptors->GetDetails(split_nof);
4445 split_kind = split_prop_details.kind();
4446 split_attributes = split_prop_details.attributes();
4447 }
4448
4449 // Invalidate a transition target at |key|.
4450 Map* maybe_transition = TransitionArray::SearchTransition(
4451 *split_map, split_kind, old_descriptors->GetKey(split_nof),
4452 split_attributes);
4453 if (maybe_transition != NULL) {
4454 maybe_transition->DeprecateTransitionTree();
4455 }
4456
4457 // If |maybe_transition| is not NULL then the transition array already
4458 // contains entry for given descriptor. This means that the transition
4459 // could be inserted regardless of whether transitions array is full or not.
4460 if (maybe_transition == NULL &&
4461 !TransitionArray::CanHaveMoreTransitions(split_map)) {
4462 return CopyGeneralizeAllRepresentations(
4463 old_map, to_kind, modify_index, store_mode, new_kind, new_attributes,
4464 "GenAll_CantHaveMoreTransitions");
4465 }
4466
4467 old_map->NotifyLeafMapLayoutChange();
4468
4469 if (FLAG_trace_generalization && modify_index >= 0) {
4470 PropertyDetails old_details = old_descriptors->GetDetails(modify_index);
4471 PropertyDetails new_details = new_descriptors->GetDetails(modify_index);
4472 MaybeHandle<FieldType> old_field_type;
4473 MaybeHandle<FieldType> new_field_type;
4474 MaybeHandle<Object> old_value;
4475 MaybeHandle<Object> new_value;
4476 if (old_details.type() == DATA) {
4477 old_field_type =
4478 handle(old_descriptors->GetFieldType(modify_index), isolate);
4479 } else {
4480 old_value = handle(old_descriptors->GetValue(modify_index), isolate);
4481 }
4482 if (new_details.type() == DATA) {
4483 new_field_type =
4484 handle(new_descriptors->GetFieldType(modify_index), isolate);
4485 } else {
4486 new_value = handle(new_descriptors->GetValue(modify_index), isolate);
4487 }
4488
4489 old_map->PrintGeneralization(
4490 stdout, "", modify_index, split_nof, old_nof,
4491 old_details.location() == kDescriptor && store_mode == FORCE_FIELD,
4492 old_details.representation(), new_details.representation(),
4493 old_field_type, old_value, new_field_type, new_value);
4494 }
4495
4496 Handle<LayoutDescriptor> new_layout_descriptor =
4497 LayoutDescriptor::New(split_map, new_descriptors, old_nof);
4498
4499 Handle<Map> new_map =
4500 AddMissingTransitions(split_map, new_descriptors, new_layout_descriptor);
4501
4502 // Deprecated part of the transition tree is no longer reachable, so replace
4503 // current instance descriptors in the "survived" part of the tree with
4504 // the new descriptors to maintain descriptors sharing invariant.
4505 split_map->ReplaceDescriptors(*new_descriptors, *new_layout_descriptor);
4506 return new_map;
4507 }
4508
4509
4510 // Generalize the representation of all DATA descriptors.
GeneralizeAllFieldRepresentations(Handle<Map> map)4511 Handle<Map> Map::GeneralizeAllFieldRepresentations(
4512 Handle<Map> map) {
4513 Handle<DescriptorArray> descriptors(map->instance_descriptors());
4514 for (int i = 0; i < map->NumberOfOwnDescriptors(); ++i) {
4515 PropertyDetails details = descriptors->GetDetails(i);
4516 if (details.type() == DATA) {
4517 map = ReconfigureProperty(map, i, kData, details.attributes(),
4518 Representation::Tagged(),
4519 FieldType::Any(map->GetIsolate()), FORCE_FIELD);
4520 }
4521 }
4522 return map;
4523 }
4524
4525
4526 // static
TryUpdate(Handle<Map> old_map)4527 MaybeHandle<Map> Map::TryUpdate(Handle<Map> old_map) {
4528 DisallowHeapAllocation no_allocation;
4529 DisallowDeoptimization no_deoptimization(old_map->GetIsolate());
4530
4531 if (!old_map->is_deprecated()) return old_map;
4532
4533 // Check the state of the root map.
4534 Map* root_map = old_map->FindRootMap();
4535 if (!old_map->EquivalentToForTransition(root_map)) return MaybeHandle<Map>();
4536
4537 ElementsKind from_kind = root_map->elements_kind();
4538 ElementsKind to_kind = old_map->elements_kind();
4539 if (from_kind != to_kind) {
4540 // Try to follow existing elements kind transitions.
4541 root_map = root_map->LookupElementsTransitionMap(to_kind);
4542 if (root_map == NULL) return MaybeHandle<Map>();
4543 // From here on, use the map with correct elements kind as root map.
4544 }
4545 Map* new_map = root_map->TryReplayPropertyTransitions(*old_map);
4546 if (new_map == nullptr) return MaybeHandle<Map>();
4547 return handle(new_map);
4548 }
4549
TryReplayPropertyTransitions(Map * old_map)4550 Map* Map::TryReplayPropertyTransitions(Map* old_map) {
4551 DisallowHeapAllocation no_allocation;
4552 DisallowDeoptimization no_deoptimization(GetIsolate());
4553
4554 int root_nof = NumberOfOwnDescriptors();
4555
4556 int old_nof = old_map->NumberOfOwnDescriptors();
4557 DescriptorArray* old_descriptors = old_map->instance_descriptors();
4558
4559 Map* new_map = this;
4560 for (int i = root_nof; i < old_nof; ++i) {
4561 PropertyDetails old_details = old_descriptors->GetDetails(i);
4562 Map* transition = TransitionArray::SearchTransition(
4563 new_map, old_details.kind(), old_descriptors->GetKey(i),
4564 old_details.attributes());
4565 if (transition == NULL) return nullptr;
4566 new_map = transition;
4567 DescriptorArray* new_descriptors = new_map->instance_descriptors();
4568
4569 PropertyDetails new_details = new_descriptors->GetDetails(i);
4570 DCHECK_EQ(old_details.kind(), new_details.kind());
4571 DCHECK_EQ(old_details.attributes(), new_details.attributes());
4572 if (!old_details.representation().fits_into(new_details.representation())) {
4573 return nullptr;
4574 }
4575 switch (new_details.type()) {
4576 case DATA: {
4577 FieldType* new_type = new_descriptors->GetFieldType(i);
4578 // Cleared field types need special treatment. They represent lost
4579 // knowledge, so we must first generalize the new_type to "Any".
4580 if (FieldTypeIsCleared(new_details.representation(), new_type)) {
4581 return nullptr;
4582 }
4583 PropertyType old_property_type = old_details.type();
4584 if (old_property_type == DATA) {
4585 FieldType* old_type = old_descriptors->GetFieldType(i);
4586 if (FieldTypeIsCleared(old_details.representation(), old_type) ||
4587 !old_type->NowIs(new_type)) {
4588 return nullptr;
4589 }
4590 } else {
4591 DCHECK(old_property_type == DATA_CONSTANT);
4592 Object* old_value = old_descriptors->GetValue(i);
4593 if (!new_type->NowContains(old_value)) {
4594 return nullptr;
4595 }
4596 }
4597 break;
4598 }
4599 case ACCESSOR: {
4600 #ifdef DEBUG
4601 FieldType* new_type = new_descriptors->GetFieldType(i);
4602 DCHECK(new_type->IsAny());
4603 #endif
4604 break;
4605 }
4606
4607 case DATA_CONSTANT:
4608 case ACCESSOR_CONSTANT: {
4609 Object* old_value = old_descriptors->GetValue(i);
4610 Object* new_value = new_descriptors->GetValue(i);
4611 if (old_details.location() == kField || old_value != new_value) {
4612 return nullptr;
4613 }
4614 break;
4615 }
4616 }
4617 }
4618 if (new_map->NumberOfOwnDescriptors() != old_nof) return nullptr;
4619 return new_map;
4620 }
4621
4622
4623 // static
Update(Handle<Map> map)4624 Handle<Map> Map::Update(Handle<Map> map) {
4625 if (!map->is_deprecated()) return map;
4626 return ReconfigureProperty(map, -1, kData, NONE, Representation::None(),
4627 FieldType::None(map->GetIsolate()),
4628 ALLOW_IN_DESCRIPTOR);
4629 }
4630
SetPropertyWithInterceptor(LookupIterator * it,ShouldThrow should_throw,Handle<Object> value)4631 Maybe<bool> JSObject::SetPropertyWithInterceptor(LookupIterator* it,
4632 ShouldThrow should_throw,
4633 Handle<Object> value) {
4634 DCHECK_EQ(LookupIterator::INTERCEPTOR, it->state());
4635 return SetPropertyWithInterceptorInternal(it, it->GetInterceptor(),
4636 should_throw, value);
4637 }
4638
SetProperty(Handle<Object> object,Handle<Name> name,Handle<Object> value,LanguageMode language_mode,StoreFromKeyed store_mode)4639 MaybeHandle<Object> Object::SetProperty(Handle<Object> object,
4640 Handle<Name> name, Handle<Object> value,
4641 LanguageMode language_mode,
4642 StoreFromKeyed store_mode) {
4643 LookupIterator it(object, name);
4644 MAYBE_RETURN_NULL(SetProperty(&it, value, language_mode, store_mode));
4645 return value;
4646 }
4647
4648
SetPropertyInternal(LookupIterator * it,Handle<Object> value,LanguageMode language_mode,StoreFromKeyed store_mode,bool * found)4649 Maybe<bool> Object::SetPropertyInternal(LookupIterator* it,
4650 Handle<Object> value,
4651 LanguageMode language_mode,
4652 StoreFromKeyed store_mode,
4653 bool* found) {
4654 it->UpdateProtector();
4655 DCHECK(it->IsFound());
4656 ShouldThrow should_throw =
4657 is_sloppy(language_mode) ? DONT_THROW : THROW_ON_ERROR;
4658
4659 // Make sure that the top context does not change when doing callbacks or
4660 // interceptor calls.
4661 AssertNoContextChange ncc(it->isolate());
4662
4663 do {
4664 switch (it->state()) {
4665 case LookupIterator::NOT_FOUND:
4666 UNREACHABLE();
4667
4668 case LookupIterator::ACCESS_CHECK:
4669 if (it->HasAccess()) break;
4670 // Check whether it makes sense to reuse the lookup iterator. Here it
4671 // might still call into setters up the prototype chain.
4672 return JSObject::SetPropertyWithFailedAccessCheck(it, value,
4673 should_throw);
4674
4675 case LookupIterator::JSPROXY:
4676 return JSProxy::SetProperty(it->GetHolder<JSProxy>(), it->GetName(),
4677 value, it->GetReceiver(), language_mode);
4678
4679 case LookupIterator::INTERCEPTOR: {
4680 if (it->HolderIsReceiverOrHiddenPrototype()) {
4681 Maybe<bool> result =
4682 JSObject::SetPropertyWithInterceptor(it, should_throw, value);
4683 if (result.IsNothing() || result.FromJust()) return result;
4684 } else {
4685 Maybe<PropertyAttributes> maybe_attributes =
4686 JSObject::GetPropertyAttributesWithInterceptor(it);
4687 if (!maybe_attributes.IsJust()) return Nothing<bool>();
4688 if ((maybe_attributes.FromJust() & READ_ONLY) != 0) {
4689 return WriteToReadOnlyProperty(it, value, should_throw);
4690 }
4691 if (maybe_attributes.FromJust() == ABSENT) break;
4692 *found = false;
4693 return Nothing<bool>();
4694 }
4695 break;
4696 }
4697
4698 case LookupIterator::ACCESSOR: {
4699 if (it->IsReadOnly()) {
4700 return WriteToReadOnlyProperty(it, value, should_throw);
4701 }
4702 Handle<Object> accessors = it->GetAccessors();
4703 if (accessors->IsAccessorInfo() &&
4704 !it->HolderIsReceiverOrHiddenPrototype() &&
4705 AccessorInfo::cast(*accessors)->is_special_data_property()) {
4706 *found = false;
4707 return Nothing<bool>();
4708 }
4709 return SetPropertyWithAccessor(it, value, should_throw);
4710 }
4711 case LookupIterator::INTEGER_INDEXED_EXOTIC:
4712 // TODO(verwaest): We should throw an exception if holder is receiver.
4713 return Just(true);
4714
4715 case LookupIterator::DATA:
4716 if (it->IsReadOnly()) {
4717 return WriteToReadOnlyProperty(it, value, should_throw);
4718 }
4719 if (it->HolderIsReceiverOrHiddenPrototype()) {
4720 return SetDataProperty(it, value);
4721 }
4722 // Fall through.
4723 case LookupIterator::TRANSITION:
4724 *found = false;
4725 return Nothing<bool>();
4726 }
4727 it->Next();
4728 } while (it->IsFound());
4729
4730 *found = false;
4731 return Nothing<bool>();
4732 }
4733
4734
SetProperty(LookupIterator * it,Handle<Object> value,LanguageMode language_mode,StoreFromKeyed store_mode)4735 Maybe<bool> Object::SetProperty(LookupIterator* it, Handle<Object> value,
4736 LanguageMode language_mode,
4737 StoreFromKeyed store_mode) {
4738 if (it->IsFound()) {
4739 bool found = true;
4740 Maybe<bool> result =
4741 SetPropertyInternal(it, value, language_mode, store_mode, &found);
4742 if (found) return result;
4743 }
4744
4745 // If the receiver is the JSGlobalObject, the store was contextual. In case
4746 // the property did not exist yet on the global object itself, we have to
4747 // throw a reference error in strict mode. In sloppy mode, we continue.
4748 if (is_strict(language_mode) && it->GetReceiver()->IsJSGlobalObject()) {
4749 it->isolate()->Throw(*it->isolate()->factory()->NewReferenceError(
4750 MessageTemplate::kNotDefined, it->name()));
4751 return Nothing<bool>();
4752 }
4753
4754 ShouldThrow should_throw =
4755 is_sloppy(language_mode) ? DONT_THROW : THROW_ON_ERROR;
4756 return AddDataProperty(it, value, NONE, should_throw, store_mode);
4757 }
4758
4759
SetSuperProperty(LookupIterator * it,Handle<Object> value,LanguageMode language_mode,StoreFromKeyed store_mode)4760 Maybe<bool> Object::SetSuperProperty(LookupIterator* it, Handle<Object> value,
4761 LanguageMode language_mode,
4762 StoreFromKeyed store_mode) {
4763 Isolate* isolate = it->isolate();
4764
4765 if (it->IsFound()) {
4766 bool found = true;
4767 Maybe<bool> result =
4768 SetPropertyInternal(it, value, language_mode, store_mode, &found);
4769 if (found) return result;
4770 }
4771
4772 it->UpdateProtector();
4773
4774 // The property either doesn't exist on the holder or exists there as a data
4775 // property.
4776
4777 ShouldThrow should_throw =
4778 is_sloppy(language_mode) ? DONT_THROW : THROW_ON_ERROR;
4779
4780 if (!it->GetReceiver()->IsJSReceiver()) {
4781 return WriteToReadOnlyProperty(it, value, should_throw);
4782 }
4783 Handle<JSReceiver> receiver = Handle<JSReceiver>::cast(it->GetReceiver());
4784
4785 LookupIterator::Configuration c = LookupIterator::OWN;
4786 LookupIterator own_lookup =
4787 it->IsElement() ? LookupIterator(isolate, receiver, it->index(), c)
4788 : LookupIterator(receiver, it->name(), c);
4789
4790 for (; own_lookup.IsFound(); own_lookup.Next()) {
4791 switch (own_lookup.state()) {
4792 case LookupIterator::ACCESS_CHECK:
4793 if (!own_lookup.HasAccess()) {
4794 return JSObject::SetPropertyWithFailedAccessCheck(&own_lookup, value,
4795 should_throw);
4796 }
4797 break;
4798
4799 case LookupIterator::ACCESSOR:
4800 if (own_lookup.GetAccessors()->IsAccessorInfo()) {
4801 if (own_lookup.IsReadOnly()) {
4802 return WriteToReadOnlyProperty(&own_lookup, value, should_throw);
4803 }
4804 return JSObject::SetPropertyWithAccessor(&own_lookup, value,
4805 should_throw);
4806 }
4807 // Fall through.
4808 case LookupIterator::INTEGER_INDEXED_EXOTIC:
4809 return RedefineIncompatibleProperty(isolate, it->GetName(), value,
4810 should_throw);
4811
4812 case LookupIterator::DATA: {
4813 if (own_lookup.IsReadOnly()) {
4814 return WriteToReadOnlyProperty(&own_lookup, value, should_throw);
4815 }
4816 return SetDataProperty(&own_lookup, value);
4817 }
4818
4819 case LookupIterator::INTERCEPTOR:
4820 case LookupIterator::JSPROXY: {
4821 PropertyDescriptor desc;
4822 Maybe<bool> owned =
4823 JSReceiver::GetOwnPropertyDescriptor(&own_lookup, &desc);
4824 MAYBE_RETURN(owned, Nothing<bool>());
4825 if (!owned.FromJust()) {
4826 return JSReceiver::CreateDataProperty(&own_lookup, value,
4827 should_throw);
4828 }
4829 if (PropertyDescriptor::IsAccessorDescriptor(&desc) ||
4830 !desc.writable()) {
4831 return RedefineIncompatibleProperty(isolate, it->GetName(), value,
4832 should_throw);
4833 }
4834
4835 PropertyDescriptor value_desc;
4836 value_desc.set_value(value);
4837 return JSReceiver::DefineOwnProperty(isolate, receiver, it->GetName(),
4838 &value_desc, should_throw);
4839 }
4840
4841 case LookupIterator::NOT_FOUND:
4842 case LookupIterator::TRANSITION:
4843 UNREACHABLE();
4844 }
4845 }
4846
4847 return AddDataProperty(&own_lookup, value, NONE, should_throw, store_mode);
4848 }
4849
CannotCreateProperty(Isolate * isolate,Handle<Object> receiver,Handle<Object> name,Handle<Object> value,ShouldThrow should_throw)4850 Maybe<bool> Object::CannotCreateProperty(Isolate* isolate,
4851 Handle<Object> receiver,
4852 Handle<Object> name,
4853 Handle<Object> value,
4854 ShouldThrow should_throw) {
4855 RETURN_FAILURE(
4856 isolate, should_throw,
4857 NewTypeError(MessageTemplate::kStrictCannotCreateProperty, name,
4858 Object::TypeOf(isolate, receiver), receiver));
4859 }
4860
4861
WriteToReadOnlyProperty(LookupIterator * it,Handle<Object> value,ShouldThrow should_throw)4862 Maybe<bool> Object::WriteToReadOnlyProperty(LookupIterator* it,
4863 Handle<Object> value,
4864 ShouldThrow should_throw) {
4865 return WriteToReadOnlyProperty(it->isolate(), it->GetReceiver(),
4866 it->GetName(), value, should_throw);
4867 }
4868
4869
WriteToReadOnlyProperty(Isolate * isolate,Handle<Object> receiver,Handle<Object> name,Handle<Object> value,ShouldThrow should_throw)4870 Maybe<bool> Object::WriteToReadOnlyProperty(Isolate* isolate,
4871 Handle<Object> receiver,
4872 Handle<Object> name,
4873 Handle<Object> value,
4874 ShouldThrow should_throw) {
4875 RETURN_FAILURE(isolate, should_throw,
4876 NewTypeError(MessageTemplate::kStrictReadOnlyProperty, name,
4877 Object::TypeOf(isolate, receiver), receiver));
4878 }
4879
4880
RedefineIncompatibleProperty(Isolate * isolate,Handle<Object> name,Handle<Object> value,ShouldThrow should_throw)4881 Maybe<bool> Object::RedefineIncompatibleProperty(Isolate* isolate,
4882 Handle<Object> name,
4883 Handle<Object> value,
4884 ShouldThrow should_throw) {
4885 RETURN_FAILURE(isolate, should_throw,
4886 NewTypeError(MessageTemplate::kRedefineDisallowed, name));
4887 }
4888
4889
SetDataProperty(LookupIterator * it,Handle<Object> value)4890 Maybe<bool> Object::SetDataProperty(LookupIterator* it, Handle<Object> value) {
4891 // Proxies are handled elsewhere. Other non-JSObjects cannot have own
4892 // properties.
4893 Handle<JSObject> receiver = Handle<JSObject>::cast(it->GetReceiver());
4894
4895 // Store on the holder which may be hidden behind the receiver.
4896 DCHECK(it->HolderIsReceiverOrHiddenPrototype());
4897
4898 Handle<Object> to_assign = value;
4899 // Convert the incoming value to a number for storing into typed arrays.
4900 if (it->IsElement() && receiver->HasFixedTypedArrayElements()) {
4901 if (!value->IsNumber() && !value->IsUndefined(it->isolate())) {
4902 ASSIGN_RETURN_ON_EXCEPTION_VALUE(
4903 it->isolate(), to_assign, Object::ToNumber(value), Nothing<bool>());
4904 // We have to recheck the length. However, it can only change if the
4905 // underlying buffer was neutered, so just check that.
4906 if (Handle<JSArrayBufferView>::cast(receiver)->WasNeutered()) {
4907 return Just(true);
4908 // TODO(neis): According to the spec, this should throw a TypeError.
4909 }
4910 }
4911 }
4912
4913 // Possibly migrate to the most up-to-date map that will be able to store
4914 // |value| under it->name().
4915 it->PrepareForDataProperty(to_assign);
4916
4917 // Write the property value.
4918 it->WriteDataValue(to_assign);
4919
4920 #if VERIFY_HEAP
4921 if (FLAG_verify_heap) {
4922 receiver->JSObjectVerify();
4923 }
4924 #endif
4925 return Just(true);
4926 }
4927
4928
AddDataProperty(LookupIterator * it,Handle<Object> value,PropertyAttributes attributes,ShouldThrow should_throw,StoreFromKeyed store_mode)4929 Maybe<bool> Object::AddDataProperty(LookupIterator* it, Handle<Object> value,
4930 PropertyAttributes attributes,
4931 ShouldThrow should_throw,
4932 StoreFromKeyed store_mode) {
4933 if (!it->GetReceiver()->IsJSObject()) {
4934 if (it->GetReceiver()->IsJSProxy() && it->GetName()->IsPrivate()) {
4935 RETURN_FAILURE(it->isolate(), should_throw,
4936 NewTypeError(MessageTemplate::kProxyPrivate));
4937 }
4938 return CannotCreateProperty(it->isolate(), it->GetReceiver(), it->GetName(),
4939 value, should_throw);
4940 }
4941
4942 DCHECK_NE(LookupIterator::INTEGER_INDEXED_EXOTIC, it->state());
4943
4944 Handle<JSObject> receiver = it->GetStoreTarget();
4945
4946 // If the receiver is a JSGlobalProxy, store on the prototype (JSGlobalObject)
4947 // instead. If the prototype is Null, the proxy is detached.
4948 if (receiver->IsJSGlobalProxy()) return Just(true);
4949
4950 Isolate* isolate = it->isolate();
4951
4952 if (it->ExtendingNonExtensible(receiver)) {
4953 RETURN_FAILURE(
4954 isolate, should_throw,
4955 NewTypeError(MessageTemplate::kObjectNotExtensible, it->GetName()));
4956 }
4957
4958 if (it->IsElement()) {
4959 if (receiver->IsJSArray()) {
4960 Handle<JSArray> array = Handle<JSArray>::cast(receiver);
4961 if (JSArray::WouldChangeReadOnlyLength(array, it->index())) {
4962 RETURN_FAILURE(array->GetIsolate(), should_throw,
4963 NewTypeError(MessageTemplate::kStrictReadOnlyProperty,
4964 isolate->factory()->length_string(),
4965 Object::TypeOf(isolate, array), array));
4966 }
4967
4968 if (FLAG_trace_external_array_abuse &&
4969 array->HasFixedTypedArrayElements()) {
4970 CheckArrayAbuse(array, "typed elements write", it->index(), true);
4971 }
4972
4973 if (FLAG_trace_js_array_abuse && !array->HasFixedTypedArrayElements()) {
4974 CheckArrayAbuse(array, "elements write", it->index(), false);
4975 }
4976 }
4977
4978 Maybe<bool> result = JSObject::AddDataElement(receiver, it->index(), value,
4979 attributes, should_throw);
4980 JSObject::ValidateElements(receiver);
4981 return result;
4982 } else {
4983 it->UpdateProtector();
4984 // Migrate to the most up-to-date map that will be able to store |value|
4985 // under it->name() with |attributes|.
4986 it->PrepareTransitionToDataProperty(receiver, value, attributes,
4987 store_mode);
4988 DCHECK_EQ(LookupIterator::TRANSITION, it->state());
4989 it->ApplyTransitionToDataProperty(receiver);
4990
4991 // Write the property value.
4992 it->WriteDataValue(value);
4993
4994 #if VERIFY_HEAP
4995 if (FLAG_verify_heap) {
4996 receiver->JSObjectVerify();
4997 }
4998 #endif
4999 }
5000
5001 return Just(true);
5002 }
5003
5004
EnsureDescriptorSlack(Handle<Map> map,int slack)5005 void Map::EnsureDescriptorSlack(Handle<Map> map, int slack) {
5006 // Only supports adding slack to owned descriptors.
5007 DCHECK(map->owns_descriptors());
5008
5009 Handle<DescriptorArray> descriptors(map->instance_descriptors());
5010 int old_size = map->NumberOfOwnDescriptors();
5011 if (slack <= descriptors->NumberOfSlackDescriptors()) return;
5012
5013 Handle<DescriptorArray> new_descriptors = DescriptorArray::CopyUpTo(
5014 descriptors, old_size, slack);
5015
5016 DisallowHeapAllocation no_allocation;
5017 // The descriptors are still the same, so keep the layout descriptor.
5018 LayoutDescriptor* layout_descriptor = map->GetLayoutDescriptor();
5019
5020 if (old_size == 0) {
5021 map->UpdateDescriptors(*new_descriptors, layout_descriptor);
5022 return;
5023 }
5024
5025 // If the source descriptors had an enum cache we copy it. This ensures
5026 // that the maps to which we push the new descriptor array back can rely
5027 // on a cache always being available once it is set. If the map has more
5028 // enumerated descriptors than available in the original cache, the cache
5029 // will be lazily replaced by the extended cache when needed.
5030 if (descriptors->HasEnumCache()) {
5031 new_descriptors->CopyEnumCacheFrom(*descriptors);
5032 }
5033
5034 Isolate* isolate = map->GetIsolate();
5035 // Replace descriptors by new_descriptors in all maps that share it.
5036 isolate->heap()->incremental_marking()->IterateBlackObject(*descriptors);
5037
5038 Map* current = *map;
5039 while (current->instance_descriptors() == *descriptors) {
5040 Object* next = current->GetBackPointer();
5041 if (next->IsUndefined(isolate)) break; // Stop overwriting at initial map.
5042 current->UpdateDescriptors(*new_descriptors, layout_descriptor);
5043 current = Map::cast(next);
5044 }
5045 map->UpdateDescriptors(*new_descriptors, layout_descriptor);
5046 }
5047
5048 template <class T>
AppendUniqueCallbacks(Handle<TemplateList> callbacks,Handle<typename T::Array> array,int valid_descriptors)5049 static int AppendUniqueCallbacks(Handle<TemplateList> callbacks,
5050 Handle<typename T::Array> array,
5051 int valid_descriptors) {
5052 int nof_callbacks = callbacks->length();
5053
5054 Isolate* isolate = array->GetIsolate();
5055 // Ensure the keys are unique names before writing them into the
5056 // instance descriptor. Since it may cause a GC, it has to be done before we
5057 // temporarily put the heap in an invalid state while appending descriptors.
5058 for (int i = 0; i < nof_callbacks; ++i) {
5059 Handle<AccessorInfo> entry(AccessorInfo::cast(callbacks->get(i)));
5060 if (entry->name()->IsUniqueName()) continue;
5061 Handle<String> key =
5062 isolate->factory()->InternalizeString(
5063 Handle<String>(String::cast(entry->name())));
5064 entry->set_name(*key);
5065 }
5066
5067 // Fill in new callback descriptors. Process the callbacks from
5068 // back to front so that the last callback with a given name takes
5069 // precedence over previously added callbacks with that name.
5070 for (int i = nof_callbacks - 1; i >= 0; i--) {
5071 Handle<AccessorInfo> entry(AccessorInfo::cast(callbacks->get(i)));
5072 Handle<Name> key(Name::cast(entry->name()));
5073 // Check if a descriptor with this name already exists before writing.
5074 if (!T::Contains(key, entry, valid_descriptors, array)) {
5075 T::Insert(key, entry, valid_descriptors, array);
5076 valid_descriptors++;
5077 }
5078 }
5079
5080 return valid_descriptors;
5081 }
5082
5083 struct DescriptorArrayAppender {
5084 typedef DescriptorArray Array;
Containsv8::internal::DescriptorArrayAppender5085 static bool Contains(Handle<Name> key,
5086 Handle<AccessorInfo> entry,
5087 int valid_descriptors,
5088 Handle<DescriptorArray> array) {
5089 DisallowHeapAllocation no_gc;
5090 return array->Search(*key, valid_descriptors) != DescriptorArray::kNotFound;
5091 }
Insertv8::internal::DescriptorArrayAppender5092 static void Insert(Handle<Name> key,
5093 Handle<AccessorInfo> entry,
5094 int valid_descriptors,
5095 Handle<DescriptorArray> array) {
5096 DisallowHeapAllocation no_gc;
5097 AccessorConstantDescriptor desc(key, entry, entry->property_attributes());
5098 array->Append(&desc);
5099 }
5100 };
5101
5102
5103 struct FixedArrayAppender {
5104 typedef FixedArray Array;
Containsv8::internal::FixedArrayAppender5105 static bool Contains(Handle<Name> key,
5106 Handle<AccessorInfo> entry,
5107 int valid_descriptors,
5108 Handle<FixedArray> array) {
5109 for (int i = 0; i < valid_descriptors; i++) {
5110 if (*key == AccessorInfo::cast(array->get(i))->name()) return true;
5111 }
5112 return false;
5113 }
Insertv8::internal::FixedArrayAppender5114 static void Insert(Handle<Name> key,
5115 Handle<AccessorInfo> entry,
5116 int valid_descriptors,
5117 Handle<FixedArray> array) {
5118 DisallowHeapAllocation no_gc;
5119 array->set(valid_descriptors, *entry);
5120 }
5121 };
5122
5123
AppendCallbackDescriptors(Handle<Map> map,Handle<Object> descriptors)5124 void Map::AppendCallbackDescriptors(Handle<Map> map,
5125 Handle<Object> descriptors) {
5126 int nof = map->NumberOfOwnDescriptors();
5127 Handle<DescriptorArray> array(map->instance_descriptors());
5128 Handle<TemplateList> callbacks = Handle<TemplateList>::cast(descriptors);
5129 DCHECK_GE(array->NumberOfSlackDescriptors(), callbacks->length());
5130 nof = AppendUniqueCallbacks<DescriptorArrayAppender>(callbacks, array, nof);
5131 map->SetNumberOfOwnDescriptors(nof);
5132 }
5133
5134
AppendUnique(Handle<Object> descriptors,Handle<FixedArray> array,int valid_descriptors)5135 int AccessorInfo::AppendUnique(Handle<Object> descriptors,
5136 Handle<FixedArray> array,
5137 int valid_descriptors) {
5138 Handle<TemplateList> callbacks = Handle<TemplateList>::cast(descriptors);
5139 DCHECK_GE(array->length(), callbacks->length() + valid_descriptors);
5140 return AppendUniqueCallbacks<FixedArrayAppender>(callbacks, array,
5141 valid_descriptors);
5142 }
5143
5144
ContainsMap(MapHandleList * maps,Map * map)5145 static bool ContainsMap(MapHandleList* maps, Map* map) {
5146 DCHECK_NOT_NULL(map);
5147 for (int i = 0; i < maps->length(); ++i) {
5148 if (!maps->at(i).is_null() && *maps->at(i) == map) return true;
5149 }
5150 return false;
5151 }
5152
FindElementsKindTransitionedMap(MapHandleList * candidates)5153 Map* Map::FindElementsKindTransitionedMap(MapHandleList* candidates) {
5154 DisallowHeapAllocation no_allocation;
5155 DisallowDeoptimization no_deoptimization(GetIsolate());
5156
5157 ElementsKind kind = elements_kind();
5158 bool packed = IsFastPackedElementsKind(kind);
5159
5160 Map* transition = nullptr;
5161 if (IsTransitionableFastElementsKind(kind)) {
5162 // Check the state of the root map.
5163 Map* root_map = FindRootMap();
5164 if (!EquivalentToForTransition(root_map)) return nullptr;
5165 root_map = root_map->LookupElementsTransitionMap(kind);
5166 DCHECK_NOT_NULL(root_map);
5167 // Starting from the next existing elements kind transition try to
5168 // replay the property transitions that does not involve instance rewriting
5169 // (ElementsTransitionAndStoreStub does not support that).
5170 for (root_map = root_map->ElementsTransitionMap();
5171 root_map != nullptr && root_map->has_fast_elements();
5172 root_map = root_map->ElementsTransitionMap()) {
5173 Map* current = root_map->TryReplayPropertyTransitions(this);
5174 if (current == nullptr) continue;
5175 if (InstancesNeedRewriting(current)) continue;
5176
5177 if (ContainsMap(candidates, current) &&
5178 (packed || !IsFastPackedElementsKind(current->elements_kind()))) {
5179 transition = current;
5180 packed = packed && IsFastPackedElementsKind(current->elements_kind());
5181 }
5182 }
5183 }
5184 return transition;
5185 }
5186
5187
FindClosestElementsTransition(Map * map,ElementsKind to_kind)5188 static Map* FindClosestElementsTransition(Map* map, ElementsKind to_kind) {
5189 // Ensure we are requested to search elements kind transition "near the root".
5190 DCHECK_EQ(map->FindRootMap()->NumberOfOwnDescriptors(),
5191 map->NumberOfOwnDescriptors());
5192 Map* current_map = map;
5193
5194 ElementsKind kind = map->elements_kind();
5195 while (kind != to_kind) {
5196 Map* next_map = current_map->ElementsTransitionMap();
5197 if (next_map == nullptr) return current_map;
5198 kind = next_map->elements_kind();
5199 current_map = next_map;
5200 }
5201
5202 DCHECK_EQ(to_kind, current_map->elements_kind());
5203 return current_map;
5204 }
5205
5206
LookupElementsTransitionMap(ElementsKind to_kind)5207 Map* Map::LookupElementsTransitionMap(ElementsKind to_kind) {
5208 Map* to_map = FindClosestElementsTransition(this, to_kind);
5209 if (to_map->elements_kind() == to_kind) return to_map;
5210 return nullptr;
5211 }
5212
5213
IsMapInArrayPrototypeChain()5214 bool Map::IsMapInArrayPrototypeChain() {
5215 Isolate* isolate = GetIsolate();
5216 if (isolate->initial_array_prototype()->map() == this) {
5217 return true;
5218 }
5219
5220 if (isolate->initial_object_prototype()->map() == this) {
5221 return true;
5222 }
5223
5224 return false;
5225 }
5226
5227
WeakCellForMap(Handle<Map> map)5228 Handle<WeakCell> Map::WeakCellForMap(Handle<Map> map) {
5229 Isolate* isolate = map->GetIsolate();
5230 if (map->weak_cell_cache()->IsWeakCell()) {
5231 return Handle<WeakCell>(WeakCell::cast(map->weak_cell_cache()));
5232 }
5233 Handle<WeakCell> weak_cell = isolate->factory()->NewWeakCell(map);
5234 map->set_weak_cell_cache(*weak_cell);
5235 return weak_cell;
5236 }
5237
5238
AddMissingElementsTransitions(Handle<Map> map,ElementsKind to_kind)5239 static Handle<Map> AddMissingElementsTransitions(Handle<Map> map,
5240 ElementsKind to_kind) {
5241 DCHECK(IsTransitionElementsKind(map->elements_kind()));
5242
5243 Handle<Map> current_map = map;
5244
5245 ElementsKind kind = map->elements_kind();
5246 TransitionFlag flag;
5247 if (map->is_prototype_map()) {
5248 flag = OMIT_TRANSITION;
5249 } else {
5250 flag = INSERT_TRANSITION;
5251 if (IsFastElementsKind(kind)) {
5252 while (kind != to_kind && !IsTerminalElementsKind(kind)) {
5253 kind = GetNextTransitionElementsKind(kind);
5254 current_map = Map::CopyAsElementsKind(current_map, kind, flag);
5255 }
5256 }
5257 }
5258
5259 // In case we are exiting the fast elements kind system, just add the map in
5260 // the end.
5261 if (kind != to_kind) {
5262 current_map = Map::CopyAsElementsKind(current_map, to_kind, flag);
5263 }
5264
5265 DCHECK(current_map->elements_kind() == to_kind);
5266 return current_map;
5267 }
5268
5269
TransitionElementsTo(Handle<Map> map,ElementsKind to_kind)5270 Handle<Map> Map::TransitionElementsTo(Handle<Map> map,
5271 ElementsKind to_kind) {
5272 ElementsKind from_kind = map->elements_kind();
5273 if (from_kind == to_kind) return map;
5274
5275 Isolate* isolate = map->GetIsolate();
5276 Context* native_context = isolate->context()->native_context();
5277 if (from_kind == FAST_SLOPPY_ARGUMENTS_ELEMENTS) {
5278 if (*map == native_context->fast_aliased_arguments_map()) {
5279 DCHECK_EQ(SLOW_SLOPPY_ARGUMENTS_ELEMENTS, to_kind);
5280 return handle(native_context->slow_aliased_arguments_map());
5281 }
5282 } else if (from_kind == SLOW_SLOPPY_ARGUMENTS_ELEMENTS) {
5283 if (*map == native_context->slow_aliased_arguments_map()) {
5284 DCHECK_EQ(FAST_SLOPPY_ARGUMENTS_ELEMENTS, to_kind);
5285 return handle(native_context->fast_aliased_arguments_map());
5286 }
5287 } else if (IsFastElementsKind(from_kind) && IsFastElementsKind(to_kind)) {
5288 // Reuse map transitions for JSArrays.
5289 DisallowHeapAllocation no_gc;
5290 if (native_context->get(Context::ArrayMapIndex(from_kind)) == *map) {
5291 Object* maybe_transitioned_map =
5292 native_context->get(Context::ArrayMapIndex(to_kind));
5293 if (maybe_transitioned_map->IsMap()) {
5294 return handle(Map::cast(maybe_transitioned_map), isolate);
5295 }
5296 }
5297 }
5298
5299 DCHECK(!map->IsUndefined(isolate));
5300 // Check if we can go back in the elements kind transition chain.
5301 if (IsHoleyElementsKind(from_kind) &&
5302 to_kind == GetPackedElementsKind(from_kind) &&
5303 map->GetBackPointer()->IsMap() &&
5304 Map::cast(map->GetBackPointer())->elements_kind() == to_kind) {
5305 return handle(Map::cast(map->GetBackPointer()));
5306 }
5307
5308 bool allow_store_transition = IsTransitionElementsKind(from_kind);
5309 // Only store fast element maps in ascending generality.
5310 if (IsFastElementsKind(to_kind)) {
5311 allow_store_transition =
5312 allow_store_transition && IsTransitionableFastElementsKind(from_kind) &&
5313 IsMoreGeneralElementsKindTransition(from_kind, to_kind);
5314 }
5315
5316 if (!allow_store_transition) {
5317 return Map::CopyAsElementsKind(map, to_kind, OMIT_TRANSITION);
5318 }
5319
5320 return Map::ReconfigureElementsKind(map, to_kind);
5321 }
5322
5323
5324 // static
AsElementsKind(Handle<Map> map,ElementsKind kind)5325 Handle<Map> Map::AsElementsKind(Handle<Map> map, ElementsKind kind) {
5326 Handle<Map> closest_map(FindClosestElementsTransition(*map, kind));
5327
5328 if (closest_map->elements_kind() == kind) {
5329 return closest_map;
5330 }
5331
5332 return AddMissingElementsTransitions(closest_map, kind);
5333 }
5334
5335
GetElementsTransitionMap(Handle<JSObject> object,ElementsKind to_kind)5336 Handle<Map> JSObject::GetElementsTransitionMap(Handle<JSObject> object,
5337 ElementsKind to_kind) {
5338 Handle<Map> map(object->map());
5339 return Map::TransitionElementsTo(map, to_kind);
5340 }
5341
5342
Revoke(Handle<JSProxy> proxy)5343 void JSProxy::Revoke(Handle<JSProxy> proxy) {
5344 Isolate* isolate = proxy->GetIsolate();
5345 if (!proxy->IsRevoked()) proxy->set_handler(isolate->heap()->null_value());
5346 DCHECK(proxy->IsRevoked());
5347 }
5348
5349
HasProperty(Isolate * isolate,Handle<JSProxy> proxy,Handle<Name> name)5350 Maybe<bool> JSProxy::HasProperty(Isolate* isolate, Handle<JSProxy> proxy,
5351 Handle<Name> name) {
5352 DCHECK(!name->IsPrivate());
5353 STACK_CHECK(isolate, Nothing<bool>());
5354 // 1. (Assert)
5355 // 2. Let handler be the value of the [[ProxyHandler]] internal slot of O.
5356 Handle<Object> handler(proxy->handler(), isolate);
5357 // 3. If handler is null, throw a TypeError exception.
5358 // 4. Assert: Type(handler) is Object.
5359 if (proxy->IsRevoked()) {
5360 isolate->Throw(*isolate->factory()->NewTypeError(
5361 MessageTemplate::kProxyRevoked, isolate->factory()->has_string()));
5362 return Nothing<bool>();
5363 }
5364 // 5. Let target be the value of the [[ProxyTarget]] internal slot of O.
5365 Handle<JSReceiver> target(proxy->target(), isolate);
5366 // 6. Let trap be ? GetMethod(handler, "has").
5367 Handle<Object> trap;
5368 ASSIGN_RETURN_ON_EXCEPTION_VALUE(
5369 isolate, trap, Object::GetMethod(Handle<JSReceiver>::cast(handler),
5370 isolate->factory()->has_string()),
5371 Nothing<bool>());
5372 // 7. If trap is undefined, then
5373 if (trap->IsUndefined(isolate)) {
5374 // 7a. Return target.[[HasProperty]](P).
5375 return JSReceiver::HasProperty(target, name);
5376 }
5377 // 8. Let booleanTrapResult be ToBoolean(? Call(trap, handler, «target, P»)).
5378 Handle<Object> trap_result_obj;
5379 Handle<Object> args[] = {target, name};
5380 ASSIGN_RETURN_ON_EXCEPTION_VALUE(
5381 isolate, trap_result_obj,
5382 Execution::Call(isolate, trap, handler, arraysize(args), args),
5383 Nothing<bool>());
5384 bool boolean_trap_result = trap_result_obj->BooleanValue();
5385 // 9. If booleanTrapResult is false, then:
5386 if (!boolean_trap_result) {
5387 // 9a. Let targetDesc be ? target.[[GetOwnProperty]](P).
5388 PropertyDescriptor target_desc;
5389 Maybe<bool> target_found = JSReceiver::GetOwnPropertyDescriptor(
5390 isolate, target, name, &target_desc);
5391 MAYBE_RETURN(target_found, Nothing<bool>());
5392 // 9b. If targetDesc is not undefined, then:
5393 if (target_found.FromJust()) {
5394 // 9b i. If targetDesc.[[Configurable]] is false, throw a TypeError
5395 // exception.
5396 if (!target_desc.configurable()) {
5397 isolate->Throw(*isolate->factory()->NewTypeError(
5398 MessageTemplate::kProxyHasNonConfigurable, name));
5399 return Nothing<bool>();
5400 }
5401 // 9b ii. Let extensibleTarget be ? IsExtensible(target).
5402 Maybe<bool> extensible_target = JSReceiver::IsExtensible(target);
5403 MAYBE_RETURN(extensible_target, Nothing<bool>());
5404 // 9b iii. If extensibleTarget is false, throw a TypeError exception.
5405 if (!extensible_target.FromJust()) {
5406 isolate->Throw(*isolate->factory()->NewTypeError(
5407 MessageTemplate::kProxyHasNonExtensible, name));
5408 return Nothing<bool>();
5409 }
5410 }
5411 }
5412 // 10. Return booleanTrapResult.
5413 return Just(boolean_trap_result);
5414 }
5415
5416
SetProperty(Handle<JSProxy> proxy,Handle<Name> name,Handle<Object> value,Handle<Object> receiver,LanguageMode language_mode)5417 Maybe<bool> JSProxy::SetProperty(Handle<JSProxy> proxy, Handle<Name> name,
5418 Handle<Object> value, Handle<Object> receiver,
5419 LanguageMode language_mode) {
5420 DCHECK(!name->IsPrivate());
5421 Isolate* isolate = proxy->GetIsolate();
5422 STACK_CHECK(isolate, Nothing<bool>());
5423 Factory* factory = isolate->factory();
5424 Handle<String> trap_name = factory->set_string();
5425 ShouldThrow should_throw =
5426 is_sloppy(language_mode) ? DONT_THROW : THROW_ON_ERROR;
5427
5428 if (proxy->IsRevoked()) {
5429 isolate->Throw(
5430 *factory->NewTypeError(MessageTemplate::kProxyRevoked, trap_name));
5431 return Nothing<bool>();
5432 }
5433 Handle<JSReceiver> target(proxy->target(), isolate);
5434 Handle<JSReceiver> handler(JSReceiver::cast(proxy->handler()), isolate);
5435
5436 Handle<Object> trap;
5437 ASSIGN_RETURN_ON_EXCEPTION_VALUE(
5438 isolate, trap, Object::GetMethod(handler, trap_name), Nothing<bool>());
5439 if (trap->IsUndefined(isolate)) {
5440 LookupIterator it =
5441 LookupIterator::PropertyOrElement(isolate, receiver, name, target);
5442 return Object::SetSuperProperty(&it, value, language_mode,
5443 Object::MAY_BE_STORE_FROM_KEYED);
5444 }
5445
5446 Handle<Object> trap_result;
5447 Handle<Object> args[] = {target, name, value, receiver};
5448 ASSIGN_RETURN_ON_EXCEPTION_VALUE(
5449 isolate, trap_result,
5450 Execution::Call(isolate, trap, handler, arraysize(args), args),
5451 Nothing<bool>());
5452 if (!trap_result->BooleanValue()) {
5453 RETURN_FAILURE(isolate, should_throw,
5454 NewTypeError(MessageTemplate::kProxyTrapReturnedFalsishFor,
5455 trap_name, name));
5456 }
5457
5458 // Enforce the invariant.
5459 PropertyDescriptor target_desc;
5460 Maybe<bool> owned =
5461 JSReceiver::GetOwnPropertyDescriptor(isolate, target, name, &target_desc);
5462 MAYBE_RETURN(owned, Nothing<bool>());
5463 if (owned.FromJust()) {
5464 bool inconsistent = PropertyDescriptor::IsDataDescriptor(&target_desc) &&
5465 !target_desc.configurable() &&
5466 !target_desc.writable() &&
5467 !value->SameValue(*target_desc.value());
5468 if (inconsistent) {
5469 isolate->Throw(*isolate->factory()->NewTypeError(
5470 MessageTemplate::kProxySetFrozenData, name));
5471 return Nothing<bool>();
5472 }
5473 inconsistent = PropertyDescriptor::IsAccessorDescriptor(&target_desc) &&
5474 !target_desc.configurable() &&
5475 target_desc.set()->IsUndefined(isolate);
5476 if (inconsistent) {
5477 isolate->Throw(*isolate->factory()->NewTypeError(
5478 MessageTemplate::kProxySetFrozenAccessor, name));
5479 return Nothing<bool>();
5480 }
5481 }
5482 return Just(true);
5483 }
5484
5485
DeletePropertyOrElement(Handle<JSProxy> proxy,Handle<Name> name,LanguageMode language_mode)5486 Maybe<bool> JSProxy::DeletePropertyOrElement(Handle<JSProxy> proxy,
5487 Handle<Name> name,
5488 LanguageMode language_mode) {
5489 DCHECK(!name->IsPrivate());
5490 ShouldThrow should_throw =
5491 is_sloppy(language_mode) ? DONT_THROW : THROW_ON_ERROR;
5492 Isolate* isolate = proxy->GetIsolate();
5493 STACK_CHECK(isolate, Nothing<bool>());
5494 Factory* factory = isolate->factory();
5495 Handle<String> trap_name = factory->deleteProperty_string();
5496
5497 if (proxy->IsRevoked()) {
5498 isolate->Throw(
5499 *factory->NewTypeError(MessageTemplate::kProxyRevoked, trap_name));
5500 return Nothing<bool>();
5501 }
5502 Handle<JSReceiver> target(proxy->target(), isolate);
5503 Handle<JSReceiver> handler(JSReceiver::cast(proxy->handler()), isolate);
5504
5505 Handle<Object> trap;
5506 ASSIGN_RETURN_ON_EXCEPTION_VALUE(
5507 isolate, trap, Object::GetMethod(handler, trap_name), Nothing<bool>());
5508 if (trap->IsUndefined(isolate)) {
5509 return JSReceiver::DeletePropertyOrElement(target, name, language_mode);
5510 }
5511
5512 Handle<Object> trap_result;
5513 Handle<Object> args[] = {target, name};
5514 ASSIGN_RETURN_ON_EXCEPTION_VALUE(
5515 isolate, trap_result,
5516 Execution::Call(isolate, trap, handler, arraysize(args), args),
5517 Nothing<bool>());
5518 if (!trap_result->BooleanValue()) {
5519 RETURN_FAILURE(isolate, should_throw,
5520 NewTypeError(MessageTemplate::kProxyTrapReturnedFalsishFor,
5521 trap_name, name));
5522 }
5523
5524 // Enforce the invariant.
5525 PropertyDescriptor target_desc;
5526 Maybe<bool> owned =
5527 JSReceiver::GetOwnPropertyDescriptor(isolate, target, name, &target_desc);
5528 MAYBE_RETURN(owned, Nothing<bool>());
5529 if (owned.FromJust() && !target_desc.configurable()) {
5530 isolate->Throw(*factory->NewTypeError(
5531 MessageTemplate::kProxyDeletePropertyNonConfigurable, name));
5532 return Nothing<bool>();
5533 }
5534 return Just(true);
5535 }
5536
5537
5538 // static
New(Isolate * isolate,Handle<Object> target,Handle<Object> handler)5539 MaybeHandle<JSProxy> JSProxy::New(Isolate* isolate, Handle<Object> target,
5540 Handle<Object> handler) {
5541 if (!target->IsJSReceiver()) {
5542 THROW_NEW_ERROR(isolate, NewTypeError(MessageTemplate::kProxyNonObject),
5543 JSProxy);
5544 }
5545 if (target->IsJSProxy() && JSProxy::cast(*target)->IsRevoked()) {
5546 THROW_NEW_ERROR(isolate,
5547 NewTypeError(MessageTemplate::kProxyHandlerOrTargetRevoked),
5548 JSProxy);
5549 }
5550 if (!handler->IsJSReceiver()) {
5551 THROW_NEW_ERROR(isolate, NewTypeError(MessageTemplate::kProxyNonObject),
5552 JSProxy);
5553 }
5554 if (handler->IsJSProxy() && JSProxy::cast(*handler)->IsRevoked()) {
5555 THROW_NEW_ERROR(isolate,
5556 NewTypeError(MessageTemplate::kProxyHandlerOrTargetRevoked),
5557 JSProxy);
5558 }
5559 return isolate->factory()->NewJSProxy(Handle<JSReceiver>::cast(target),
5560 Handle<JSReceiver>::cast(handler));
5561 }
5562
5563
5564 // static
GetFunctionRealm(Handle<JSProxy> proxy)5565 MaybeHandle<Context> JSProxy::GetFunctionRealm(Handle<JSProxy> proxy) {
5566 DCHECK(proxy->map()->is_constructor());
5567 if (proxy->IsRevoked()) {
5568 THROW_NEW_ERROR(proxy->GetIsolate(),
5569 NewTypeError(MessageTemplate::kProxyRevoked), Context);
5570 }
5571 Handle<JSReceiver> target(JSReceiver::cast(proxy->target()));
5572 return JSReceiver::GetFunctionRealm(target);
5573 }
5574
5575
5576 // static
GetFunctionRealm(Handle<JSBoundFunction> function)5577 MaybeHandle<Context> JSBoundFunction::GetFunctionRealm(
5578 Handle<JSBoundFunction> function) {
5579 DCHECK(function->map()->is_constructor());
5580 return JSReceiver::GetFunctionRealm(
5581 handle(function->bound_target_function()));
5582 }
5583
5584 // static
GetName(Isolate * isolate,Handle<JSBoundFunction> function)5585 MaybeHandle<String> JSBoundFunction::GetName(Isolate* isolate,
5586 Handle<JSBoundFunction> function) {
5587 Handle<String> prefix = isolate->factory()->bound__string();
5588 if (!function->bound_target_function()->IsJSFunction()) return prefix;
5589 Handle<JSFunction> target(JSFunction::cast(function->bound_target_function()),
5590 isolate);
5591 Handle<Object> target_name = JSFunction::GetName(isolate, target);
5592 if (!target_name->IsString()) return prefix;
5593 Factory* factory = isolate->factory();
5594 return factory->NewConsString(prefix, Handle<String>::cast(target_name));
5595 }
5596
5597 // static
GetName(Isolate * isolate,Handle<JSFunction> function)5598 Handle<Object> JSFunction::GetName(Isolate* isolate,
5599 Handle<JSFunction> function) {
5600 if (function->shared()->name_should_print_as_anonymous()) {
5601 return isolate->factory()->anonymous_string();
5602 }
5603 return handle(function->shared()->name(), isolate);
5604 }
5605
5606 // static
GetLength(Isolate * isolate,Handle<JSFunction> function)5607 MaybeHandle<Smi> JSFunction::GetLength(Isolate* isolate,
5608 Handle<JSFunction> function) {
5609 int length = 0;
5610 if (function->shared()->is_compiled()) {
5611 length = function->shared()->length();
5612 } else {
5613 // If the function isn't compiled yet, the length is not computed
5614 // correctly yet. Compile it now and return the right length.
5615 if (Compiler::Compile(function, Compiler::KEEP_EXCEPTION)) {
5616 length = function->shared()->length();
5617 }
5618 if (isolate->has_pending_exception()) return MaybeHandle<Smi>();
5619 }
5620 return handle(Smi::FromInt(length), isolate);
5621 }
5622
5623 // static
GetFunctionRealm(Handle<JSFunction> function)5624 Handle<Context> JSFunction::GetFunctionRealm(Handle<JSFunction> function) {
5625 DCHECK(function->map()->is_constructor());
5626 return handle(function->context()->native_context());
5627 }
5628
5629
5630 // static
GetFunctionRealm(Handle<JSObject> object)5631 MaybeHandle<Context> JSObject::GetFunctionRealm(Handle<JSObject> object) {
5632 DCHECK(object->map()->is_constructor());
5633 DCHECK(!object->IsJSFunction());
5634 return handle(object->GetCreationContext());
5635 }
5636
5637
5638 // static
GetFunctionRealm(Handle<JSReceiver> receiver)5639 MaybeHandle<Context> JSReceiver::GetFunctionRealm(Handle<JSReceiver> receiver) {
5640 if (receiver->IsJSProxy()) {
5641 return JSProxy::GetFunctionRealm(Handle<JSProxy>::cast(receiver));
5642 }
5643
5644 if (receiver->IsJSFunction()) {
5645 return JSFunction::GetFunctionRealm(Handle<JSFunction>::cast(receiver));
5646 }
5647
5648 if (receiver->IsJSBoundFunction()) {
5649 return JSBoundFunction::GetFunctionRealm(
5650 Handle<JSBoundFunction>::cast(receiver));
5651 }
5652
5653 return JSObject::GetFunctionRealm(Handle<JSObject>::cast(receiver));
5654 }
5655
5656
GetPropertyAttributes(LookupIterator * it)5657 Maybe<PropertyAttributes> JSProxy::GetPropertyAttributes(LookupIterator* it) {
5658 PropertyDescriptor desc;
5659 Maybe<bool> found = JSProxy::GetOwnPropertyDescriptor(
5660 it->isolate(), it->GetHolder<JSProxy>(), it->GetName(), &desc);
5661 MAYBE_RETURN(found, Nothing<PropertyAttributes>());
5662 if (!found.FromJust()) return Just(ABSENT);
5663 return Just(desc.ToAttributes());
5664 }
5665
5666
AllocateStorageForMap(Handle<JSObject> object,Handle<Map> map)5667 void JSObject::AllocateStorageForMap(Handle<JSObject> object, Handle<Map> map) {
5668 DCHECK(object->map()->GetInObjectProperties() ==
5669 map->GetInObjectProperties());
5670 ElementsKind obj_kind = object->map()->elements_kind();
5671 ElementsKind map_kind = map->elements_kind();
5672 if (map_kind != obj_kind) {
5673 ElementsKind to_kind = GetMoreGeneralElementsKind(map_kind, obj_kind);
5674 if (IsDictionaryElementsKind(obj_kind)) {
5675 to_kind = obj_kind;
5676 }
5677 if (IsDictionaryElementsKind(to_kind)) {
5678 NormalizeElements(object);
5679 } else {
5680 TransitionElementsKind(object, to_kind);
5681 }
5682 map = Map::ReconfigureElementsKind(map, to_kind);
5683 }
5684 JSObject::MigrateToMap(object, map);
5685 }
5686
5687
MigrateInstance(Handle<JSObject> object)5688 void JSObject::MigrateInstance(Handle<JSObject> object) {
5689 Handle<Map> original_map(object->map());
5690 Handle<Map> map = Map::Update(original_map);
5691 map->set_migration_target(true);
5692 MigrateToMap(object, map);
5693 if (FLAG_trace_migration) {
5694 object->PrintInstanceMigration(stdout, *original_map, *map);
5695 }
5696 #if VERIFY_HEAP
5697 if (FLAG_verify_heap) {
5698 object->JSObjectVerify();
5699 }
5700 #endif
5701 }
5702
5703
5704 // static
TryMigrateInstance(Handle<JSObject> object)5705 bool JSObject::TryMigrateInstance(Handle<JSObject> object) {
5706 Isolate* isolate = object->GetIsolate();
5707 DisallowDeoptimization no_deoptimization(isolate);
5708 Handle<Map> original_map(object->map(), isolate);
5709 Handle<Map> new_map;
5710 if (!Map::TryUpdate(original_map).ToHandle(&new_map)) {
5711 return false;
5712 }
5713 JSObject::MigrateToMap(object, new_map);
5714 if (FLAG_trace_migration) {
5715 object->PrintInstanceMigration(stdout, *original_map, object->map());
5716 }
5717 #if VERIFY_HEAP
5718 if (FLAG_verify_heap) {
5719 object->JSObjectVerify();
5720 }
5721 #endif
5722 return true;
5723 }
5724
5725
AddProperty(Handle<JSObject> object,Handle<Name> name,Handle<Object> value,PropertyAttributes attributes)5726 void JSObject::AddProperty(Handle<JSObject> object, Handle<Name> name,
5727 Handle<Object> value,
5728 PropertyAttributes attributes) {
5729 LookupIterator it(object, name, object, LookupIterator::OWN_SKIP_INTERCEPTOR);
5730 CHECK_NE(LookupIterator::ACCESS_CHECK, it.state());
5731 #ifdef DEBUG
5732 uint32_t index;
5733 DCHECK(!object->IsJSProxy());
5734 DCHECK(!name->AsArrayIndex(&index));
5735 Maybe<PropertyAttributes> maybe = GetPropertyAttributes(&it);
5736 DCHECK(maybe.IsJust());
5737 DCHECK(!it.IsFound());
5738 DCHECK(object->map()->is_extensible() || name->IsPrivate());
5739 #endif
5740 CHECK(AddDataProperty(&it, value, attributes, THROW_ON_ERROR,
5741 CERTAINLY_NOT_STORE_FROM_KEYED)
5742 .IsJust());
5743 }
5744
5745
5746 // Reconfigures a property to a data property with attributes, even if it is not
5747 // reconfigurable.
5748 // Requires a LookupIterator that does not look at the prototype chain beyond
5749 // hidden prototypes.
DefineOwnPropertyIgnoreAttributes(LookupIterator * it,Handle<Object> value,PropertyAttributes attributes,AccessorInfoHandling handling)5750 MaybeHandle<Object> JSObject::DefineOwnPropertyIgnoreAttributes(
5751 LookupIterator* it, Handle<Object> value, PropertyAttributes attributes,
5752 AccessorInfoHandling handling) {
5753 MAYBE_RETURN_NULL(DefineOwnPropertyIgnoreAttributes(
5754 it, value, attributes, THROW_ON_ERROR, handling));
5755 return value;
5756 }
5757
5758
DefineOwnPropertyIgnoreAttributes(LookupIterator * it,Handle<Object> value,PropertyAttributes attributes,ShouldThrow should_throw,AccessorInfoHandling handling)5759 Maybe<bool> JSObject::DefineOwnPropertyIgnoreAttributes(
5760 LookupIterator* it, Handle<Object> value, PropertyAttributes attributes,
5761 ShouldThrow should_throw, AccessorInfoHandling handling) {
5762 it->UpdateProtector();
5763 Handle<JSObject> object = Handle<JSObject>::cast(it->GetReceiver());
5764
5765 for (; it->IsFound(); it->Next()) {
5766 switch (it->state()) {
5767 case LookupIterator::JSPROXY:
5768 case LookupIterator::NOT_FOUND:
5769 case LookupIterator::TRANSITION:
5770 UNREACHABLE();
5771
5772 case LookupIterator::ACCESS_CHECK:
5773 if (!it->HasAccess()) {
5774 it->isolate()->ReportFailedAccessCheck(it->GetHolder<JSObject>());
5775 RETURN_VALUE_IF_SCHEDULED_EXCEPTION(it->isolate(), Nothing<bool>());
5776 return Just(true);
5777 }
5778 break;
5779
5780 // If there's an interceptor, try to store the property with the
5781 // interceptor.
5782 // In case of success, the attributes will have been reset to the default
5783 // attributes of the interceptor, rather than the incoming attributes.
5784 //
5785 // TODO(verwaest): JSProxy afterwards verify the attributes that the
5786 // JSProxy claims it has, and verifies that they are compatible. If not,
5787 // they throw. Here we should do the same.
5788 case LookupIterator::INTERCEPTOR:
5789 if (handling == DONT_FORCE_FIELD) {
5790 Maybe<bool> result =
5791 JSObject::SetPropertyWithInterceptor(it, should_throw, value);
5792 if (result.IsNothing() || result.FromJust()) return result;
5793 }
5794 break;
5795
5796 case LookupIterator::ACCESSOR: {
5797 Handle<Object> accessors = it->GetAccessors();
5798
5799 // Special handling for AccessorInfo, which behaves like a data
5800 // property.
5801 if (accessors->IsAccessorInfo() && handling == DONT_FORCE_FIELD) {
5802 PropertyAttributes current_attributes = it->property_attributes();
5803 // Ensure the context isn't changed after calling into accessors.
5804 AssertNoContextChange ncc(it->isolate());
5805
5806 // Update the attributes before calling the setter. The setter may
5807 // later change the shape of the property.
5808 if (current_attributes != attributes) {
5809 it->TransitionToAccessorPair(accessors, attributes);
5810 }
5811
5812 return JSObject::SetPropertyWithAccessor(it, value, should_throw);
5813 }
5814
5815 it->ReconfigureDataProperty(value, attributes);
5816 return Just(true);
5817 }
5818 case LookupIterator::INTEGER_INDEXED_EXOTIC:
5819 return RedefineIncompatibleProperty(it->isolate(), it->GetName(), value,
5820 should_throw);
5821
5822 case LookupIterator::DATA: {
5823 // Regular property update if the attributes match.
5824 if (it->property_attributes() == attributes) {
5825 return SetDataProperty(it, value);
5826 }
5827
5828 // Special case: properties of typed arrays cannot be reconfigured to
5829 // non-writable nor to non-enumerable.
5830 if (it->IsElement() && object->HasFixedTypedArrayElements()) {
5831 return RedefineIncompatibleProperty(it->isolate(), it->GetName(),
5832 value, should_throw);
5833 }
5834
5835 // Reconfigure the data property if the attributes mismatch.
5836 it->ReconfigureDataProperty(value, attributes);
5837
5838 return Just(true);
5839 }
5840 }
5841 }
5842
5843 return AddDataProperty(it, value, attributes, should_throw,
5844 CERTAINLY_NOT_STORE_FROM_KEYED);
5845 }
5846
SetOwnPropertyIgnoreAttributes(Handle<JSObject> object,Handle<Name> name,Handle<Object> value,PropertyAttributes attributes)5847 MaybeHandle<Object> JSObject::SetOwnPropertyIgnoreAttributes(
5848 Handle<JSObject> object, Handle<Name> name, Handle<Object> value,
5849 PropertyAttributes attributes) {
5850 DCHECK(!value->IsTheHole(object->GetIsolate()));
5851 LookupIterator it(object, name, object, LookupIterator::OWN);
5852 return DefineOwnPropertyIgnoreAttributes(&it, value, attributes);
5853 }
5854
SetOwnElementIgnoreAttributes(Handle<JSObject> object,uint32_t index,Handle<Object> value,PropertyAttributes attributes)5855 MaybeHandle<Object> JSObject::SetOwnElementIgnoreAttributes(
5856 Handle<JSObject> object, uint32_t index, Handle<Object> value,
5857 PropertyAttributes attributes) {
5858 Isolate* isolate = object->GetIsolate();
5859 LookupIterator it(isolate, object, index, object, LookupIterator::OWN);
5860 return DefineOwnPropertyIgnoreAttributes(&it, value, attributes);
5861 }
5862
DefinePropertyOrElementIgnoreAttributes(Handle<JSObject> object,Handle<Name> name,Handle<Object> value,PropertyAttributes attributes)5863 MaybeHandle<Object> JSObject::DefinePropertyOrElementIgnoreAttributes(
5864 Handle<JSObject> object, Handle<Name> name, Handle<Object> value,
5865 PropertyAttributes attributes) {
5866 Isolate* isolate = object->GetIsolate();
5867 LookupIterator it = LookupIterator::PropertyOrElement(
5868 isolate, object, name, object, LookupIterator::OWN);
5869 return DefineOwnPropertyIgnoreAttributes(&it, value, attributes);
5870 }
5871
GetPropertyAttributesWithInterceptor(LookupIterator * it)5872 Maybe<PropertyAttributes> JSObject::GetPropertyAttributesWithInterceptor(
5873 LookupIterator* it) {
5874 return GetPropertyAttributesWithInterceptorInternal(it, it->GetInterceptor());
5875 }
5876
GetPropertyAttributes(LookupIterator * it)5877 Maybe<PropertyAttributes> JSReceiver::GetPropertyAttributes(
5878 LookupIterator* it) {
5879 for (; it->IsFound(); it->Next()) {
5880 switch (it->state()) {
5881 case LookupIterator::NOT_FOUND:
5882 case LookupIterator::TRANSITION:
5883 UNREACHABLE();
5884 case LookupIterator::JSPROXY:
5885 return JSProxy::GetPropertyAttributes(it);
5886 case LookupIterator::INTERCEPTOR: {
5887 Maybe<PropertyAttributes> result =
5888 JSObject::GetPropertyAttributesWithInterceptor(it);
5889 if (!result.IsJust()) return result;
5890 if (result.FromJust() != ABSENT) return result;
5891 break;
5892 }
5893 case LookupIterator::ACCESS_CHECK:
5894 if (it->HasAccess()) break;
5895 return JSObject::GetPropertyAttributesWithFailedAccessCheck(it);
5896 case LookupIterator::INTEGER_INDEXED_EXOTIC:
5897 return Just(ABSENT);
5898 case LookupIterator::ACCESSOR:
5899 case LookupIterator::DATA:
5900 return Just(it->property_attributes());
5901 }
5902 }
5903 return Just(ABSENT);
5904 }
5905
5906
New(Isolate * isolate)5907 Handle<NormalizedMapCache> NormalizedMapCache::New(Isolate* isolate) {
5908 Handle<FixedArray> array(
5909 isolate->factory()->NewFixedArray(kEntries, TENURED));
5910 return Handle<NormalizedMapCache>::cast(array);
5911 }
5912
5913
Get(Handle<Map> fast_map,PropertyNormalizationMode mode)5914 MaybeHandle<Map> NormalizedMapCache::Get(Handle<Map> fast_map,
5915 PropertyNormalizationMode mode) {
5916 DisallowHeapAllocation no_gc;
5917 Object* value = FixedArray::get(GetIndex(fast_map));
5918 if (!value->IsMap() ||
5919 !Map::cast(value)->EquivalentToForNormalization(*fast_map, mode)) {
5920 return MaybeHandle<Map>();
5921 }
5922 return handle(Map::cast(value));
5923 }
5924
5925
Set(Handle<Map> fast_map,Handle<Map> normalized_map)5926 void NormalizedMapCache::Set(Handle<Map> fast_map,
5927 Handle<Map> normalized_map) {
5928 DisallowHeapAllocation no_gc;
5929 DCHECK(normalized_map->is_dictionary_map());
5930 FixedArray::set(GetIndex(fast_map), *normalized_map);
5931 }
5932
5933
Clear()5934 void NormalizedMapCache::Clear() {
5935 int entries = length();
5936 for (int i = 0; i != entries; i++) {
5937 set_undefined(i);
5938 }
5939 }
5940
5941
UpdateMapCodeCache(Handle<HeapObject> object,Handle<Name> name,Handle<Code> code)5942 void HeapObject::UpdateMapCodeCache(Handle<HeapObject> object,
5943 Handle<Name> name,
5944 Handle<Code> code) {
5945 Handle<Map> map(object->map());
5946 Map::UpdateCodeCache(map, name, code);
5947 }
5948
5949
NormalizeProperties(Handle<JSObject> object,PropertyNormalizationMode mode,int expected_additional_properties,const char * reason)5950 void JSObject::NormalizeProperties(Handle<JSObject> object,
5951 PropertyNormalizationMode mode,
5952 int expected_additional_properties,
5953 const char* reason) {
5954 if (!object->HasFastProperties()) return;
5955
5956 Handle<Map> map(object->map());
5957 Handle<Map> new_map = Map::Normalize(map, mode, reason);
5958
5959 MigrateToMap(object, new_map, expected_additional_properties);
5960 }
5961
5962
MigrateSlowToFast(Handle<JSObject> object,int unused_property_fields,const char * reason)5963 void JSObject::MigrateSlowToFast(Handle<JSObject> object,
5964 int unused_property_fields,
5965 const char* reason) {
5966 if (object->HasFastProperties()) return;
5967 DCHECK(!object->IsJSGlobalObject());
5968 Isolate* isolate = object->GetIsolate();
5969 Factory* factory = isolate->factory();
5970 Handle<NameDictionary> dictionary(object->property_dictionary());
5971
5972 // Make sure we preserve dictionary representation if there are too many
5973 // descriptors.
5974 int number_of_elements = dictionary->NumberOfElements();
5975 if (number_of_elements > kMaxNumberOfDescriptors) return;
5976
5977 Handle<FixedArray> iteration_order;
5978 if (number_of_elements != dictionary->NextEnumerationIndex()) {
5979 iteration_order =
5980 NameDictionary::DoGenerateNewEnumerationIndices(dictionary);
5981 } else {
5982 iteration_order = NameDictionary::BuildIterationIndicesArray(dictionary);
5983 }
5984
5985 int instance_descriptor_length = iteration_order->length();
5986 int number_of_fields = 0;
5987
5988 // Compute the length of the instance descriptor.
5989 for (int i = 0; i < instance_descriptor_length; i++) {
5990 int index = Smi::cast(iteration_order->get(i))->value();
5991 DCHECK(dictionary->IsKey(isolate, dictionary->KeyAt(index)));
5992
5993 Object* value = dictionary->ValueAt(index);
5994 PropertyType type = dictionary->DetailsAt(index).type();
5995 if (type == DATA && !value->IsJSFunction()) {
5996 number_of_fields += 1;
5997 }
5998 }
5999
6000 Handle<Map> old_map(object->map(), isolate);
6001
6002 int inobject_props = old_map->GetInObjectProperties();
6003
6004 // Allocate new map.
6005 Handle<Map> new_map = Map::CopyDropDescriptors(old_map);
6006 new_map->set_dictionary_map(false);
6007
6008 NotifyMapChange(old_map, new_map, isolate);
6009
6010 #if TRACE_MAPS
6011 if (FLAG_trace_maps) {
6012 PrintF("[TraceMaps: SlowToFast from= %p to= %p reason= %s ]\n",
6013 reinterpret_cast<void*>(*old_map), reinterpret_cast<void*>(*new_map),
6014 reason);
6015 }
6016 #endif
6017
6018 if (instance_descriptor_length == 0) {
6019 DisallowHeapAllocation no_gc;
6020 DCHECK_LE(unused_property_fields, inobject_props);
6021 // Transform the object.
6022 new_map->set_unused_property_fields(inobject_props);
6023 object->synchronized_set_map(*new_map);
6024 object->set_properties(isolate->heap()->empty_fixed_array());
6025 // Check that it really works.
6026 DCHECK(object->HasFastProperties());
6027 return;
6028 }
6029
6030 // Allocate the instance descriptor.
6031 Handle<DescriptorArray> descriptors = DescriptorArray::Allocate(
6032 isolate, instance_descriptor_length, 0, TENURED);
6033
6034 int number_of_allocated_fields =
6035 number_of_fields + unused_property_fields - inobject_props;
6036 if (number_of_allocated_fields < 0) {
6037 // There is enough inobject space for all fields (including unused).
6038 number_of_allocated_fields = 0;
6039 unused_property_fields = inobject_props - number_of_fields;
6040 }
6041
6042 // Allocate the fixed array for the fields.
6043 Handle<FixedArray> fields = factory->NewFixedArray(
6044 number_of_allocated_fields);
6045
6046 // Fill in the instance descriptor and the fields.
6047 int current_offset = 0;
6048 for (int i = 0; i < instance_descriptor_length; i++) {
6049 int index = Smi::cast(iteration_order->get(i))->value();
6050 Object* k = dictionary->KeyAt(index);
6051 DCHECK(dictionary->IsKey(k));
6052 // Dictionary keys are internalized upon insertion.
6053 // TODO(jkummerow): Turn this into a DCHECK if it's not hit in the wild.
6054 CHECK(k->IsUniqueName());
6055 Handle<Name> key(Name::cast(k), isolate);
6056
6057 Object* value = dictionary->ValueAt(index);
6058
6059 PropertyDetails details = dictionary->DetailsAt(index);
6060 int enumeration_index = details.dictionary_index();
6061 PropertyType type = details.type();
6062
6063 if (value->IsJSFunction()) {
6064 DataConstantDescriptor d(key, handle(value, isolate),
6065 details.attributes());
6066 descriptors->Set(enumeration_index - 1, &d);
6067 } else if (type == DATA) {
6068 if (current_offset < inobject_props) {
6069 object->InObjectPropertyAtPut(current_offset, value,
6070 UPDATE_WRITE_BARRIER);
6071 } else {
6072 int offset = current_offset - inobject_props;
6073 fields->set(offset, value);
6074 }
6075 DataDescriptor d(key, current_offset, details.attributes(),
6076 // TODO(verwaest): value->OptimalRepresentation();
6077 Representation::Tagged());
6078 current_offset += d.GetDetails().field_width_in_words();
6079 descriptors->Set(enumeration_index - 1, &d);
6080 } else if (type == ACCESSOR_CONSTANT) {
6081 AccessorConstantDescriptor d(key, handle(value, isolate),
6082 details.attributes());
6083 descriptors->Set(enumeration_index - 1, &d);
6084 } else {
6085 UNREACHABLE();
6086 }
6087 }
6088 DCHECK(current_offset == number_of_fields);
6089
6090 descriptors->Sort();
6091
6092 Handle<LayoutDescriptor> layout_descriptor = LayoutDescriptor::New(
6093 new_map, descriptors, descriptors->number_of_descriptors());
6094
6095 DisallowHeapAllocation no_gc;
6096 new_map->InitializeDescriptors(*descriptors, *layout_descriptor);
6097 new_map->set_unused_property_fields(unused_property_fields);
6098
6099 // Transform the object.
6100 object->synchronized_set_map(*new_map);
6101
6102 object->set_properties(*fields);
6103 DCHECK(object->IsJSObject());
6104
6105 // Check that it really works.
6106 DCHECK(object->HasFastProperties());
6107 }
6108
6109
ResetElements(Handle<JSObject> object)6110 void JSObject::ResetElements(Handle<JSObject> object) {
6111 Isolate* isolate = object->GetIsolate();
6112 CHECK(object->map() != isolate->heap()->sloppy_arguments_elements_map());
6113 if (object->map()->has_dictionary_elements()) {
6114 Handle<SeededNumberDictionary> new_elements =
6115 SeededNumberDictionary::New(isolate, 0);
6116 object->set_elements(*new_elements);
6117 } else {
6118 object->set_elements(object->map()->GetInitialElements());
6119 }
6120 }
6121
6122
RequireSlowElements(SeededNumberDictionary * dictionary)6123 void JSObject::RequireSlowElements(SeededNumberDictionary* dictionary) {
6124 if (dictionary->requires_slow_elements()) return;
6125 dictionary->set_requires_slow_elements();
6126 // TODO(verwaest): Remove this hack.
6127 if (map()->is_prototype_map()) {
6128 TypeFeedbackVector::ClearAllKeyedStoreICs(GetIsolate());
6129 }
6130 }
6131
6132
NormalizeElements(Handle<JSObject> object)6133 Handle<SeededNumberDictionary> JSObject::NormalizeElements(
6134 Handle<JSObject> object) {
6135 DCHECK(!object->HasFixedTypedArrayElements());
6136 Isolate* isolate = object->GetIsolate();
6137 bool is_arguments = object->HasSloppyArgumentsElements();
6138 {
6139 DisallowHeapAllocation no_gc;
6140 FixedArrayBase* elements = object->elements();
6141
6142 if (is_arguments) {
6143 FixedArray* parameter_map = FixedArray::cast(elements);
6144 elements = FixedArrayBase::cast(parameter_map->get(1));
6145 }
6146
6147 if (elements->IsDictionary()) {
6148 return handle(SeededNumberDictionary::cast(elements), isolate);
6149 }
6150 }
6151
6152 DCHECK(object->HasFastSmiOrObjectElements() ||
6153 object->HasFastDoubleElements() ||
6154 object->HasFastArgumentsElements() ||
6155 object->HasFastStringWrapperElements());
6156
6157 Handle<SeededNumberDictionary> dictionary =
6158 object->GetElementsAccessor()->Normalize(object);
6159
6160 // Switch to using the dictionary as the backing storage for elements.
6161 ElementsKind target_kind = is_arguments
6162 ? SLOW_SLOPPY_ARGUMENTS_ELEMENTS
6163 : object->HasFastStringWrapperElements()
6164 ? SLOW_STRING_WRAPPER_ELEMENTS
6165 : DICTIONARY_ELEMENTS;
6166 Handle<Map> new_map = JSObject::GetElementsTransitionMap(object, target_kind);
6167 // Set the new map first to satify the elements type assert in set_elements().
6168 JSObject::MigrateToMap(object, new_map);
6169
6170 if (is_arguments) {
6171 FixedArray::cast(object->elements())->set(1, *dictionary);
6172 } else {
6173 object->set_elements(*dictionary);
6174 }
6175
6176 isolate->counters()->elements_to_dictionary()->Increment();
6177
6178 #ifdef DEBUG
6179 if (FLAG_trace_normalization) {
6180 OFStream os(stdout);
6181 os << "Object elements have been normalized:\n";
6182 object->Print(os);
6183 }
6184 #endif
6185
6186 DCHECK(object->HasDictionaryElements() ||
6187 object->HasSlowArgumentsElements() ||
6188 object->HasSlowStringWrapperElements());
6189 return dictionary;
6190 }
6191
6192
6193 template <typename ProxyType>
GetOrCreateIdentityHashHelper(Isolate * isolate,Handle<ProxyType> proxy)6194 static Smi* GetOrCreateIdentityHashHelper(Isolate* isolate,
6195 Handle<ProxyType> proxy) {
6196 Object* maybe_hash = proxy->hash();
6197 if (maybe_hash->IsSmi()) return Smi::cast(maybe_hash);
6198
6199 Smi* hash = Smi::FromInt(isolate->GenerateIdentityHash(Smi::kMaxValue));
6200 proxy->set_hash(hash);
6201 return hash;
6202 }
6203
6204 // static
GetIdentityHash(Isolate * isolate,Handle<JSObject> object)6205 Object* JSObject::GetIdentityHash(Isolate* isolate, Handle<JSObject> object) {
6206 if (object->IsJSGlobalProxy()) {
6207 return JSGlobalProxy::cast(*object)->hash();
6208 }
6209 Handle<Name> hash_code_symbol = isolate->factory()->hash_code_symbol();
6210 return *JSReceiver::GetDataProperty(object, hash_code_symbol);
6211 }
6212
6213 // static
GetOrCreateIdentityHash(Isolate * isolate,Handle<JSObject> object)6214 Smi* JSObject::GetOrCreateIdentityHash(Isolate* isolate,
6215 Handle<JSObject> object) {
6216 if (object->IsJSGlobalProxy()) {
6217 return GetOrCreateIdentityHashHelper(isolate,
6218 Handle<JSGlobalProxy>::cast(object));
6219 }
6220
6221 Handle<Name> hash_code_symbol = isolate->factory()->hash_code_symbol();
6222 LookupIterator it(object, hash_code_symbol, object, LookupIterator::OWN);
6223 if (it.IsFound()) {
6224 DCHECK_EQ(LookupIterator::DATA, it.state());
6225 Object* maybe_hash = *it.GetDataValue();
6226 if (maybe_hash->IsSmi()) return Smi::cast(maybe_hash);
6227 }
6228
6229 Smi* hash = Smi::FromInt(isolate->GenerateIdentityHash(Smi::kMaxValue));
6230 CHECK(AddDataProperty(&it, handle(hash, isolate), NONE, THROW_ON_ERROR,
6231 CERTAINLY_NOT_STORE_FROM_KEYED)
6232 .IsJust());
6233 return hash;
6234 }
6235
6236 // static
GetIdentityHash(Handle<JSProxy> proxy)6237 Object* JSProxy::GetIdentityHash(Handle<JSProxy> proxy) {
6238 return proxy->hash();
6239 }
6240
GetOrCreateIdentityHash(Isolate * isolate,Handle<JSProxy> proxy)6241 Smi* JSProxy::GetOrCreateIdentityHash(Isolate* isolate, Handle<JSProxy> proxy) {
6242 return GetOrCreateIdentityHashHelper(isolate, proxy);
6243 }
6244
6245
DeletePropertyWithInterceptor(LookupIterator * it,ShouldThrow should_throw)6246 Maybe<bool> JSObject::DeletePropertyWithInterceptor(LookupIterator* it,
6247 ShouldThrow should_throw) {
6248 Isolate* isolate = it->isolate();
6249 // Make sure that the top context does not change when doing callbacks or
6250 // interceptor calls.
6251 AssertNoContextChange ncc(isolate);
6252
6253 DCHECK_EQ(LookupIterator::INTERCEPTOR, it->state());
6254 Handle<InterceptorInfo> interceptor(it->GetInterceptor());
6255 if (interceptor->deleter()->IsUndefined(isolate)) return Nothing<bool>();
6256
6257 Handle<JSObject> holder = it->GetHolder<JSObject>();
6258 Handle<Object> receiver = it->GetReceiver();
6259 if (!receiver->IsJSReceiver()) {
6260 ASSIGN_RETURN_ON_EXCEPTION_VALUE(isolate, receiver,
6261 Object::ConvertReceiver(isolate, receiver),
6262 Nothing<bool>());
6263 }
6264
6265 PropertyCallbackArguments args(isolate, interceptor->data(), *receiver,
6266 *holder, should_throw);
6267 Handle<Object> result;
6268 if (it->IsElement()) {
6269 uint32_t index = it->index();
6270 v8::IndexedPropertyDeleterCallback deleter =
6271 v8::ToCData<v8::IndexedPropertyDeleterCallback>(interceptor->deleter());
6272 result = args.Call(deleter, index);
6273 } else if (it->name()->IsSymbol() && !interceptor->can_intercept_symbols()) {
6274 return Nothing<bool>();
6275 } else {
6276 Handle<Name> name = it->name();
6277 DCHECK(!name->IsPrivate());
6278 v8::GenericNamedPropertyDeleterCallback deleter =
6279 v8::ToCData<v8::GenericNamedPropertyDeleterCallback>(
6280 interceptor->deleter());
6281 result = args.Call(deleter, name);
6282 }
6283
6284 RETURN_VALUE_IF_SCHEDULED_EXCEPTION(isolate, Nothing<bool>());
6285 if (result.is_null()) return Nothing<bool>();
6286
6287 DCHECK(result->IsBoolean());
6288 // Rebox CustomArguments::kReturnValueOffset before returning.
6289 return Just(result->IsTrue(isolate));
6290 }
6291
6292
DeleteNormalizedProperty(Handle<JSReceiver> object,Handle<Name> name,int entry)6293 void JSReceiver::DeleteNormalizedProperty(Handle<JSReceiver> object,
6294 Handle<Name> name, int entry) {
6295 DCHECK(!object->HasFastProperties());
6296 Isolate* isolate = object->GetIsolate();
6297
6298 if (object->IsJSGlobalObject()) {
6299 // If we have a global object, invalidate the cell and swap in a new one.
6300 Handle<GlobalDictionary> dictionary(
6301 JSObject::cast(*object)->global_dictionary());
6302 DCHECK_NE(GlobalDictionary::kNotFound, entry);
6303
6304 auto cell = PropertyCell::InvalidateEntry(dictionary, entry);
6305 cell->set_value(isolate->heap()->the_hole_value());
6306 cell->set_property_details(
6307 PropertyDetails::Empty(PropertyCellType::kUninitialized));
6308 } else {
6309 Handle<NameDictionary> dictionary(object->property_dictionary());
6310 DCHECK_NE(NameDictionary::kNotFound, entry);
6311
6312 NameDictionary::DeleteProperty(dictionary, entry);
6313 Handle<NameDictionary> new_properties =
6314 NameDictionary::Shrink(dictionary, name);
6315 object->set_properties(*new_properties);
6316 }
6317 }
6318
6319
DeleteProperty(LookupIterator * it,LanguageMode language_mode)6320 Maybe<bool> JSReceiver::DeleteProperty(LookupIterator* it,
6321 LanguageMode language_mode) {
6322 it->UpdateProtector();
6323
6324 Isolate* isolate = it->isolate();
6325
6326 if (it->state() == LookupIterator::JSPROXY) {
6327 return JSProxy::DeletePropertyOrElement(it->GetHolder<JSProxy>(),
6328 it->GetName(), language_mode);
6329 }
6330
6331 if (it->GetReceiver()->IsJSProxy()) {
6332 if (it->state() != LookupIterator::NOT_FOUND) {
6333 DCHECK_EQ(LookupIterator::DATA, it->state());
6334 DCHECK(it->name()->IsPrivate());
6335 it->Delete();
6336 }
6337 return Just(true);
6338 }
6339 Handle<JSObject> receiver = Handle<JSObject>::cast(it->GetReceiver());
6340
6341 for (; it->IsFound(); it->Next()) {
6342 switch (it->state()) {
6343 case LookupIterator::JSPROXY:
6344 case LookupIterator::NOT_FOUND:
6345 case LookupIterator::TRANSITION:
6346 UNREACHABLE();
6347 case LookupIterator::ACCESS_CHECK:
6348 if (it->HasAccess()) break;
6349 isolate->ReportFailedAccessCheck(it->GetHolder<JSObject>());
6350 RETURN_VALUE_IF_SCHEDULED_EXCEPTION(isolate, Nothing<bool>());
6351 return Just(false);
6352 case LookupIterator::INTERCEPTOR: {
6353 ShouldThrow should_throw =
6354 is_sloppy(language_mode) ? DONT_THROW : THROW_ON_ERROR;
6355 Maybe<bool> result =
6356 JSObject::DeletePropertyWithInterceptor(it, should_throw);
6357 // An exception was thrown in the interceptor. Propagate.
6358 if (isolate->has_pending_exception()) return Nothing<bool>();
6359 // Delete with interceptor succeeded. Return result.
6360 // TODO(neis): In strict mode, we should probably throw if the
6361 // interceptor returns false.
6362 if (result.IsJust()) return result;
6363 break;
6364 }
6365 case LookupIterator::INTEGER_INDEXED_EXOTIC:
6366 return Just(true);
6367 case LookupIterator::DATA:
6368 case LookupIterator::ACCESSOR: {
6369 if (!it->IsConfigurable()) {
6370 // Fail if the property is not configurable.
6371 if (is_strict(language_mode)) {
6372 isolate->Throw(*isolate->factory()->NewTypeError(
6373 MessageTemplate::kStrictDeleteProperty, it->GetName(),
6374 receiver));
6375 return Nothing<bool>();
6376 }
6377 return Just(false);
6378 }
6379
6380 it->Delete();
6381
6382 return Just(true);
6383 }
6384 }
6385 }
6386
6387 return Just(true);
6388 }
6389
6390
DeleteElement(Handle<JSReceiver> object,uint32_t index,LanguageMode language_mode)6391 Maybe<bool> JSReceiver::DeleteElement(Handle<JSReceiver> object, uint32_t index,
6392 LanguageMode language_mode) {
6393 LookupIterator it(object->GetIsolate(), object, index, object,
6394 LookupIterator::OWN);
6395 return DeleteProperty(&it, language_mode);
6396 }
6397
6398
DeleteProperty(Handle<JSReceiver> object,Handle<Name> name,LanguageMode language_mode)6399 Maybe<bool> JSReceiver::DeleteProperty(Handle<JSReceiver> object,
6400 Handle<Name> name,
6401 LanguageMode language_mode) {
6402 LookupIterator it(object, name, object, LookupIterator::OWN);
6403 return DeleteProperty(&it, language_mode);
6404 }
6405
6406
DeletePropertyOrElement(Handle<JSReceiver> object,Handle<Name> name,LanguageMode language_mode)6407 Maybe<bool> JSReceiver::DeletePropertyOrElement(Handle<JSReceiver> object,
6408 Handle<Name> name,
6409 LanguageMode language_mode) {
6410 LookupIterator it = LookupIterator::PropertyOrElement(
6411 name->GetIsolate(), object, name, object, LookupIterator::OWN);
6412 return DeleteProperty(&it, language_mode);
6413 }
6414
6415
6416 // ES6 7.1.14
6417 // static
ToPropertyKey(Isolate * isolate,Handle<Object> value)6418 MaybeHandle<Object> Object::ToPropertyKey(Isolate* isolate,
6419 Handle<Object> value) {
6420 // 1. Let key be ToPrimitive(argument, hint String).
6421 MaybeHandle<Object> maybe_key =
6422 Object::ToPrimitive(value, ToPrimitiveHint::kString);
6423 // 2. ReturnIfAbrupt(key).
6424 Handle<Object> key;
6425 if (!maybe_key.ToHandle(&key)) return key;
6426 // 3. If Type(key) is Symbol, then return key.
6427 if (key->IsSymbol()) return key;
6428 // 4. Return ToString(key).
6429 // Extending spec'ed behavior, we'd be happy to return an element index.
6430 if (key->IsSmi()) return key;
6431 if (key->IsHeapNumber()) {
6432 uint32_t uint_value;
6433 if (value->ToArrayLength(&uint_value) &&
6434 uint_value <= static_cast<uint32_t>(Smi::kMaxValue)) {
6435 return handle(Smi::FromInt(static_cast<int>(uint_value)), isolate);
6436 }
6437 }
6438 return Object::ToString(isolate, key);
6439 }
6440
6441
6442 // ES6 19.1.2.4
6443 // static
DefineProperty(Isolate * isolate,Handle<Object> object,Handle<Object> key,Handle<Object> attributes)6444 Object* JSReceiver::DefineProperty(Isolate* isolate, Handle<Object> object,
6445 Handle<Object> key,
6446 Handle<Object> attributes) {
6447 // 1. If Type(O) is not Object, throw a TypeError exception.
6448 if (!object->IsJSReceiver()) {
6449 Handle<String> fun_name =
6450 isolate->factory()->InternalizeUtf8String("Object.defineProperty");
6451 THROW_NEW_ERROR_RETURN_FAILURE(
6452 isolate, NewTypeError(MessageTemplate::kCalledOnNonObject, fun_name));
6453 }
6454 // 2. Let key be ToPropertyKey(P).
6455 // 3. ReturnIfAbrupt(key).
6456 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, key, ToPropertyKey(isolate, key));
6457 // 4. Let desc be ToPropertyDescriptor(Attributes).
6458 // 5. ReturnIfAbrupt(desc).
6459 PropertyDescriptor desc;
6460 if (!PropertyDescriptor::ToPropertyDescriptor(isolate, attributes, &desc)) {
6461 return isolate->heap()->exception();
6462 }
6463 // 6. Let success be DefinePropertyOrThrow(O,key, desc).
6464 Maybe<bool> success = DefineOwnProperty(
6465 isolate, Handle<JSReceiver>::cast(object), key, &desc, THROW_ON_ERROR);
6466 // 7. ReturnIfAbrupt(success).
6467 MAYBE_RETURN(success, isolate->heap()->exception());
6468 CHECK(success.FromJust());
6469 // 8. Return O.
6470 return *object;
6471 }
6472
6473
6474 // ES6 19.1.2.3.1
6475 // static
DefineProperties(Isolate * isolate,Handle<Object> object,Handle<Object> properties)6476 MaybeHandle<Object> JSReceiver::DefineProperties(Isolate* isolate,
6477 Handle<Object> object,
6478 Handle<Object> properties) {
6479 // 1. If Type(O) is not Object, throw a TypeError exception.
6480 if (!object->IsJSReceiver()) {
6481 Handle<String> fun_name =
6482 isolate->factory()->InternalizeUtf8String("Object.defineProperties");
6483 THROW_NEW_ERROR(isolate,
6484 NewTypeError(MessageTemplate::kCalledOnNonObject, fun_name),
6485 Object);
6486 }
6487 // 2. Let props be ToObject(Properties).
6488 // 3. ReturnIfAbrupt(props).
6489 Handle<JSReceiver> props;
6490 ASSIGN_RETURN_ON_EXCEPTION(isolate, props,
6491 Object::ToObject(isolate, properties), Object);
6492
6493 // 4. Let keys be props.[[OwnPropertyKeys]]().
6494 // 5. ReturnIfAbrupt(keys).
6495 Handle<FixedArray> keys;
6496 ASSIGN_RETURN_ON_EXCEPTION(
6497 isolate, keys, KeyAccumulator::GetKeys(props, KeyCollectionMode::kOwnOnly,
6498 ALL_PROPERTIES),
6499 Object);
6500 // 6. Let descriptors be an empty List.
6501 int capacity = keys->length();
6502 std::vector<PropertyDescriptor> descriptors(capacity);
6503 size_t descriptors_index = 0;
6504 // 7. Repeat for each element nextKey of keys in List order,
6505 for (int i = 0; i < keys->length(); ++i) {
6506 Handle<Object> next_key(keys->get(i), isolate);
6507 // 7a. Let propDesc be props.[[GetOwnProperty]](nextKey).
6508 // 7b. ReturnIfAbrupt(propDesc).
6509 bool success = false;
6510 LookupIterator it = LookupIterator::PropertyOrElement(
6511 isolate, props, next_key, &success, LookupIterator::OWN);
6512 DCHECK(success);
6513 Maybe<PropertyAttributes> maybe = JSReceiver::GetPropertyAttributes(&it);
6514 if (!maybe.IsJust()) return MaybeHandle<Object>();
6515 PropertyAttributes attrs = maybe.FromJust();
6516 // 7c. If propDesc is not undefined and propDesc.[[Enumerable]] is true:
6517 if (attrs == ABSENT) continue;
6518 if (attrs & DONT_ENUM) continue;
6519 // 7c i. Let descObj be Get(props, nextKey).
6520 // 7c ii. ReturnIfAbrupt(descObj).
6521 Handle<Object> desc_obj;
6522 ASSIGN_RETURN_ON_EXCEPTION(isolate, desc_obj, Object::GetProperty(&it),
6523 Object);
6524 // 7c iii. Let desc be ToPropertyDescriptor(descObj).
6525 success = PropertyDescriptor::ToPropertyDescriptor(
6526 isolate, desc_obj, &descriptors[descriptors_index]);
6527 // 7c iv. ReturnIfAbrupt(desc).
6528 if (!success) return MaybeHandle<Object>();
6529 // 7c v. Append the pair (a two element List) consisting of nextKey and
6530 // desc to the end of descriptors.
6531 descriptors[descriptors_index].set_name(next_key);
6532 descriptors_index++;
6533 }
6534 // 8. For each pair from descriptors in list order,
6535 for (size_t i = 0; i < descriptors_index; ++i) {
6536 PropertyDescriptor* desc = &descriptors[i];
6537 // 8a. Let P be the first element of pair.
6538 // 8b. Let desc be the second element of pair.
6539 // 8c. Let status be DefinePropertyOrThrow(O, P, desc).
6540 Maybe<bool> status =
6541 DefineOwnProperty(isolate, Handle<JSReceiver>::cast(object),
6542 desc->name(), desc, THROW_ON_ERROR);
6543 // 8d. ReturnIfAbrupt(status).
6544 if (!status.IsJust()) return MaybeHandle<Object>();
6545 CHECK(status.FromJust());
6546 }
6547 // 9. Return o.
6548 return object;
6549 }
6550
6551
6552 // static
DefineOwnProperty(Isolate * isolate,Handle<JSReceiver> object,Handle<Object> key,PropertyDescriptor * desc,ShouldThrow should_throw)6553 Maybe<bool> JSReceiver::DefineOwnProperty(Isolate* isolate,
6554 Handle<JSReceiver> object,
6555 Handle<Object> key,
6556 PropertyDescriptor* desc,
6557 ShouldThrow should_throw) {
6558 if (object->IsJSArray()) {
6559 return JSArray::DefineOwnProperty(isolate, Handle<JSArray>::cast(object),
6560 key, desc, should_throw);
6561 }
6562 if (object->IsJSProxy()) {
6563 return JSProxy::DefineOwnProperty(isolate, Handle<JSProxy>::cast(object),
6564 key, desc, should_throw);
6565 }
6566 // TODO(neis): Special case for JSModuleNamespace?
6567
6568 // OrdinaryDefineOwnProperty, by virtue of calling
6569 // DefineOwnPropertyIgnoreAttributes, can handle arguments (ES6 9.4.4.2)
6570 // and IntegerIndexedExotics (ES6 9.4.5.3), with one exception:
6571 // TODO(jkummerow): Setting an indexed accessor on a typed array should throw.
6572 return OrdinaryDefineOwnProperty(isolate, Handle<JSObject>::cast(object), key,
6573 desc, should_throw);
6574 }
6575
6576
6577 // static
OrdinaryDefineOwnProperty(Isolate * isolate,Handle<JSObject> object,Handle<Object> key,PropertyDescriptor * desc,ShouldThrow should_throw)6578 Maybe<bool> JSReceiver::OrdinaryDefineOwnProperty(Isolate* isolate,
6579 Handle<JSObject> object,
6580 Handle<Object> key,
6581 PropertyDescriptor* desc,
6582 ShouldThrow should_throw) {
6583 bool success = false;
6584 DCHECK(key->IsName() || key->IsNumber()); // |key| is a PropertyKey...
6585 LookupIterator it = LookupIterator::PropertyOrElement(
6586 isolate, object, key, &success, LookupIterator::OWN);
6587 DCHECK(success); // ...so creating a LookupIterator can't fail.
6588
6589 // Deal with access checks first.
6590 if (it.state() == LookupIterator::ACCESS_CHECK) {
6591 if (!it.HasAccess()) {
6592 isolate->ReportFailedAccessCheck(it.GetHolder<JSObject>());
6593 RETURN_VALUE_IF_SCHEDULED_EXCEPTION(isolate, Nothing<bool>());
6594 return Just(true);
6595 }
6596 it.Next();
6597 }
6598
6599 // Handle interceptor
6600 if (it.state() == LookupIterator::INTERCEPTOR) {
6601 if (it.HolderIsReceiverOrHiddenPrototype()) {
6602 Maybe<bool> result = DefinePropertyWithInterceptorInternal(
6603 &it, it.GetInterceptor(), should_throw, *desc);
6604 if (result.IsNothing() || result.FromJust()) {
6605 return result;
6606 }
6607 }
6608 }
6609
6610 return OrdinaryDefineOwnProperty(&it, desc, should_throw);
6611 }
6612
6613
6614 // ES6 9.1.6.1
6615 // static
OrdinaryDefineOwnProperty(LookupIterator * it,PropertyDescriptor * desc,ShouldThrow should_throw)6616 Maybe<bool> JSReceiver::OrdinaryDefineOwnProperty(LookupIterator* it,
6617 PropertyDescriptor* desc,
6618 ShouldThrow should_throw) {
6619 Isolate* isolate = it->isolate();
6620 // 1. Let current be O.[[GetOwnProperty]](P).
6621 // 2. ReturnIfAbrupt(current).
6622 PropertyDescriptor current;
6623 MAYBE_RETURN(GetOwnPropertyDescriptor(it, ¤t), Nothing<bool>());
6624
6625 // TODO(jkummerow/verwaest): It would be nice if we didn't have to reset
6626 // the iterator every time. Currently, the reasons why we need it are:
6627 // - handle interceptors correctly
6628 // - handle accessors correctly (which might change the holder's map)
6629 it->Restart();
6630 // 3. Let extensible be the value of the [[Extensible]] internal slot of O.
6631 Handle<JSObject> object = Handle<JSObject>::cast(it->GetReceiver());
6632 bool extensible = JSObject::IsExtensible(object);
6633
6634 return ValidateAndApplyPropertyDescriptor(isolate, it, extensible, desc,
6635 ¤t, should_throw);
6636 }
6637
6638
6639 // ES6 9.1.6.2
6640 // static
IsCompatiblePropertyDescriptor(Isolate * isolate,bool extensible,PropertyDescriptor * desc,PropertyDescriptor * current,Handle<Name> property_name,ShouldThrow should_throw)6641 Maybe<bool> JSReceiver::IsCompatiblePropertyDescriptor(
6642 Isolate* isolate, bool extensible, PropertyDescriptor* desc,
6643 PropertyDescriptor* current, Handle<Name> property_name,
6644 ShouldThrow should_throw) {
6645 // 1. Return ValidateAndApplyPropertyDescriptor(undefined, undefined,
6646 // Extensible, Desc, Current).
6647 return ValidateAndApplyPropertyDescriptor(
6648 isolate, NULL, extensible, desc, current, should_throw, property_name);
6649 }
6650
6651
6652 // ES6 9.1.6.3
6653 // static
ValidateAndApplyPropertyDescriptor(Isolate * isolate,LookupIterator * it,bool extensible,PropertyDescriptor * desc,PropertyDescriptor * current,ShouldThrow should_throw,Handle<Name> property_name)6654 Maybe<bool> JSReceiver::ValidateAndApplyPropertyDescriptor(
6655 Isolate* isolate, LookupIterator* it, bool extensible,
6656 PropertyDescriptor* desc, PropertyDescriptor* current,
6657 ShouldThrow should_throw, Handle<Name> property_name) {
6658 // We either need a LookupIterator, or a property name.
6659 DCHECK((it == NULL) != property_name.is_null());
6660 Handle<JSObject> object;
6661 if (it != NULL) object = Handle<JSObject>::cast(it->GetReceiver());
6662 bool desc_is_data_descriptor = PropertyDescriptor::IsDataDescriptor(desc);
6663 bool desc_is_accessor_descriptor =
6664 PropertyDescriptor::IsAccessorDescriptor(desc);
6665 bool desc_is_generic_descriptor =
6666 PropertyDescriptor::IsGenericDescriptor(desc);
6667 // 1. (Assert)
6668 // 2. If current is undefined, then
6669 if (current->is_empty()) {
6670 // 2a. If extensible is false, return false.
6671 if (!extensible) {
6672 RETURN_FAILURE(isolate, should_throw,
6673 NewTypeError(MessageTemplate::kDefineDisallowed,
6674 it != NULL ? it->GetName() : property_name));
6675 }
6676 // 2c. If IsGenericDescriptor(Desc) or IsDataDescriptor(Desc) is true, then:
6677 // (This is equivalent to !IsAccessorDescriptor(desc).)
6678 DCHECK((desc_is_generic_descriptor || desc_is_data_descriptor) ==
6679 !desc_is_accessor_descriptor);
6680 if (!desc_is_accessor_descriptor) {
6681 // 2c i. If O is not undefined, create an own data property named P of
6682 // object O whose [[Value]], [[Writable]], [[Enumerable]] and
6683 // [[Configurable]] attribute values are described by Desc. If the value
6684 // of an attribute field of Desc is absent, the attribute of the newly
6685 // created property is set to its default value.
6686 if (it != NULL) {
6687 if (!desc->has_writable()) desc->set_writable(false);
6688 if (!desc->has_enumerable()) desc->set_enumerable(false);
6689 if (!desc->has_configurable()) desc->set_configurable(false);
6690 Handle<Object> value(
6691 desc->has_value()
6692 ? desc->value()
6693 : Handle<Object>::cast(isolate->factory()->undefined_value()));
6694 MaybeHandle<Object> result =
6695 JSObject::DefineOwnPropertyIgnoreAttributes(it, value,
6696 desc->ToAttributes());
6697 if (result.is_null()) return Nothing<bool>();
6698 }
6699 } else {
6700 // 2d. Else Desc must be an accessor Property Descriptor,
6701 DCHECK(desc_is_accessor_descriptor);
6702 // 2d i. If O is not undefined, create an own accessor property named P
6703 // of object O whose [[Get]], [[Set]], [[Enumerable]] and
6704 // [[Configurable]] attribute values are described by Desc. If the value
6705 // of an attribute field of Desc is absent, the attribute of the newly
6706 // created property is set to its default value.
6707 if (it != NULL) {
6708 if (!desc->has_enumerable()) desc->set_enumerable(false);
6709 if (!desc->has_configurable()) desc->set_configurable(false);
6710 Handle<Object> getter(
6711 desc->has_get()
6712 ? desc->get()
6713 : Handle<Object>::cast(isolate->factory()->null_value()));
6714 Handle<Object> setter(
6715 desc->has_set()
6716 ? desc->set()
6717 : Handle<Object>::cast(isolate->factory()->null_value()));
6718 MaybeHandle<Object> result =
6719 JSObject::DefineAccessor(it, getter, setter, desc->ToAttributes());
6720 if (result.is_null()) return Nothing<bool>();
6721 }
6722 }
6723 // 2e. Return true.
6724 return Just(true);
6725 }
6726 // 3. Return true, if every field in Desc is absent.
6727 // 4. Return true, if every field in Desc also occurs in current and the
6728 // value of every field in Desc is the same value as the corresponding field
6729 // in current when compared using the SameValue algorithm.
6730 if ((!desc->has_enumerable() ||
6731 desc->enumerable() == current->enumerable()) &&
6732 (!desc->has_configurable() ||
6733 desc->configurable() == current->configurable()) &&
6734 (!desc->has_value() ||
6735 (current->has_value() && current->value()->SameValue(*desc->value()))) &&
6736 (!desc->has_writable() ||
6737 (current->has_writable() && current->writable() == desc->writable())) &&
6738 (!desc->has_get() ||
6739 (current->has_get() && current->get()->SameValue(*desc->get()))) &&
6740 (!desc->has_set() ||
6741 (current->has_set() && current->set()->SameValue(*desc->set())))) {
6742 return Just(true);
6743 }
6744 // 5. If the [[Configurable]] field of current is false, then
6745 if (!current->configurable()) {
6746 // 5a. Return false, if the [[Configurable]] field of Desc is true.
6747 if (desc->has_configurable() && desc->configurable()) {
6748 RETURN_FAILURE(isolate, should_throw,
6749 NewTypeError(MessageTemplate::kRedefineDisallowed,
6750 it != NULL ? it->GetName() : property_name));
6751 }
6752 // 5b. Return false, if the [[Enumerable]] field of Desc is present and the
6753 // [[Enumerable]] fields of current and Desc are the Boolean negation of
6754 // each other.
6755 if (desc->has_enumerable() && desc->enumerable() != current->enumerable()) {
6756 RETURN_FAILURE(isolate, should_throw,
6757 NewTypeError(MessageTemplate::kRedefineDisallowed,
6758 it != NULL ? it->GetName() : property_name));
6759 }
6760 }
6761
6762 bool current_is_data_descriptor =
6763 PropertyDescriptor::IsDataDescriptor(current);
6764 // 6. If IsGenericDescriptor(Desc) is true, no further validation is required.
6765 if (desc_is_generic_descriptor) {
6766 // Nothing to see here.
6767
6768 // 7. Else if IsDataDescriptor(current) and IsDataDescriptor(Desc) have
6769 // different results, then:
6770 } else if (current_is_data_descriptor != desc_is_data_descriptor) {
6771 // 7a. Return false, if the [[Configurable]] field of current is false.
6772 if (!current->configurable()) {
6773 RETURN_FAILURE(isolate, should_throw,
6774 NewTypeError(MessageTemplate::kRedefineDisallowed,
6775 it != NULL ? it->GetName() : property_name));
6776 }
6777 // 7b. If IsDataDescriptor(current) is true, then:
6778 if (current_is_data_descriptor) {
6779 // 7b i. If O is not undefined, convert the property named P of object O
6780 // from a data property to an accessor property. Preserve the existing
6781 // values of the converted property's [[Configurable]] and [[Enumerable]]
6782 // attributes and set the rest of the property's attributes to their
6783 // default values.
6784 // --> Folded into step 10.
6785 } else {
6786 // 7c i. If O is not undefined, convert the property named P of object O
6787 // from an accessor property to a data property. Preserve the existing
6788 // values of the converted property’s [[Configurable]] and [[Enumerable]]
6789 // attributes and set the rest of the property’s attributes to their
6790 // default values.
6791 // --> Folded into step 10.
6792 }
6793
6794 // 8. Else if IsDataDescriptor(current) and IsDataDescriptor(Desc) are both
6795 // true, then:
6796 } else if (current_is_data_descriptor && desc_is_data_descriptor) {
6797 // 8a. If the [[Configurable]] field of current is false, then:
6798 if (!current->configurable()) {
6799 // 8a i. Return false, if the [[Writable]] field of current is false and
6800 // the [[Writable]] field of Desc is true.
6801 if (!current->writable() && desc->has_writable() && desc->writable()) {
6802 RETURN_FAILURE(
6803 isolate, should_throw,
6804 NewTypeError(MessageTemplate::kRedefineDisallowed,
6805 it != NULL ? it->GetName() : property_name));
6806 }
6807 // 8a ii. If the [[Writable]] field of current is false, then:
6808 if (!current->writable()) {
6809 // 8a ii 1. Return false, if the [[Value]] field of Desc is present and
6810 // SameValue(Desc.[[Value]], current.[[Value]]) is false.
6811 if (desc->has_value() && !desc->value()->SameValue(*current->value())) {
6812 RETURN_FAILURE(
6813 isolate, should_throw,
6814 NewTypeError(MessageTemplate::kRedefineDisallowed,
6815 it != NULL ? it->GetName() : property_name));
6816 }
6817 }
6818 }
6819 } else {
6820 // 9. Else IsAccessorDescriptor(current) and IsAccessorDescriptor(Desc)
6821 // are both true,
6822 DCHECK(PropertyDescriptor::IsAccessorDescriptor(current) &&
6823 desc_is_accessor_descriptor);
6824 // 9a. If the [[Configurable]] field of current is false, then:
6825 if (!current->configurable()) {
6826 // 9a i. Return false, if the [[Set]] field of Desc is present and
6827 // SameValue(Desc.[[Set]], current.[[Set]]) is false.
6828 if (desc->has_set() && !desc->set()->SameValue(*current->set())) {
6829 RETURN_FAILURE(
6830 isolate, should_throw,
6831 NewTypeError(MessageTemplate::kRedefineDisallowed,
6832 it != NULL ? it->GetName() : property_name));
6833 }
6834 // 9a ii. Return false, if the [[Get]] field of Desc is present and
6835 // SameValue(Desc.[[Get]], current.[[Get]]) is false.
6836 if (desc->has_get() && !desc->get()->SameValue(*current->get())) {
6837 RETURN_FAILURE(
6838 isolate, should_throw,
6839 NewTypeError(MessageTemplate::kRedefineDisallowed,
6840 it != NULL ? it->GetName() : property_name));
6841 }
6842 }
6843 }
6844
6845 // 10. If O is not undefined, then:
6846 if (it != NULL) {
6847 // 10a. For each field of Desc that is present, set the corresponding
6848 // attribute of the property named P of object O to the value of the field.
6849 PropertyAttributes attrs = NONE;
6850
6851 if (desc->has_enumerable()) {
6852 attrs = static_cast<PropertyAttributes>(
6853 attrs | (desc->enumerable() ? NONE : DONT_ENUM));
6854 } else {
6855 attrs = static_cast<PropertyAttributes>(
6856 attrs | (current->enumerable() ? NONE : DONT_ENUM));
6857 }
6858 if (desc->has_configurable()) {
6859 attrs = static_cast<PropertyAttributes>(
6860 attrs | (desc->configurable() ? NONE : DONT_DELETE));
6861 } else {
6862 attrs = static_cast<PropertyAttributes>(
6863 attrs | (current->configurable() ? NONE : DONT_DELETE));
6864 }
6865 if (desc_is_data_descriptor ||
6866 (desc_is_generic_descriptor && current_is_data_descriptor)) {
6867 if (desc->has_writable()) {
6868 attrs = static_cast<PropertyAttributes>(
6869 attrs | (desc->writable() ? NONE : READ_ONLY));
6870 } else {
6871 attrs = static_cast<PropertyAttributes>(
6872 attrs | (current->writable() ? NONE : READ_ONLY));
6873 }
6874 Handle<Object> value(
6875 desc->has_value() ? desc->value()
6876 : current->has_value()
6877 ? current->value()
6878 : Handle<Object>::cast(
6879 isolate->factory()->undefined_value()));
6880 MaybeHandle<Object> result =
6881 JSObject::DefineOwnPropertyIgnoreAttributes(it, value, attrs);
6882 if (result.is_null()) return Nothing<bool>();
6883 } else {
6884 DCHECK(desc_is_accessor_descriptor ||
6885 (desc_is_generic_descriptor &&
6886 PropertyDescriptor::IsAccessorDescriptor(current)));
6887 Handle<Object> getter(
6888 desc->has_get()
6889 ? desc->get()
6890 : current->has_get()
6891 ? current->get()
6892 : Handle<Object>::cast(isolate->factory()->null_value()));
6893 Handle<Object> setter(
6894 desc->has_set()
6895 ? desc->set()
6896 : current->has_set()
6897 ? current->set()
6898 : Handle<Object>::cast(isolate->factory()->null_value()));
6899 MaybeHandle<Object> result =
6900 JSObject::DefineAccessor(it, getter, setter, attrs);
6901 if (result.is_null()) return Nothing<bool>();
6902 }
6903 }
6904
6905 // 11. Return true.
6906 return Just(true);
6907 }
6908
6909
6910 // static
CreateDataProperty(LookupIterator * it,Handle<Object> value,ShouldThrow should_throw)6911 Maybe<bool> JSReceiver::CreateDataProperty(LookupIterator* it,
6912 Handle<Object> value,
6913 ShouldThrow should_throw) {
6914 DCHECK(!it->check_prototype_chain());
6915 Handle<JSReceiver> receiver = Handle<JSReceiver>::cast(it->GetReceiver());
6916 Isolate* isolate = receiver->GetIsolate();
6917
6918 if (receiver->IsJSObject()) {
6919 return JSObject::CreateDataProperty(it, value, should_throw); // Shortcut.
6920 }
6921
6922 PropertyDescriptor new_desc;
6923 new_desc.set_value(value);
6924 new_desc.set_writable(true);
6925 new_desc.set_enumerable(true);
6926 new_desc.set_configurable(true);
6927
6928 return JSReceiver::DefineOwnProperty(isolate, receiver, it->GetName(),
6929 &new_desc, should_throw);
6930 }
6931
CreateDataProperty(LookupIterator * it,Handle<Object> value,ShouldThrow should_throw)6932 Maybe<bool> JSObject::CreateDataProperty(LookupIterator* it,
6933 Handle<Object> value,
6934 ShouldThrow should_throw) {
6935 DCHECK(it->GetReceiver()->IsJSObject());
6936 MAYBE_RETURN(JSReceiver::GetPropertyAttributes(it), Nothing<bool>());
6937 Handle<JSReceiver> receiver = Handle<JSReceiver>::cast(it->GetReceiver());
6938 Isolate* isolate = receiver->GetIsolate();
6939
6940 if (it->IsFound()) {
6941 Maybe<PropertyAttributes> attributes = GetPropertyAttributes(it);
6942 MAYBE_RETURN(attributes, Nothing<bool>());
6943 if ((attributes.FromJust() & DONT_DELETE) != 0) {
6944 RETURN_FAILURE(
6945 isolate, should_throw,
6946 NewTypeError(MessageTemplate::kRedefineDisallowed, it->GetName()));
6947 }
6948 } else {
6949 if (!JSObject::IsExtensible(Handle<JSObject>::cast(it->GetReceiver()))) {
6950 RETURN_FAILURE(
6951 isolate, should_throw,
6952 NewTypeError(MessageTemplate::kDefineDisallowed, it->GetName()));
6953 }
6954 }
6955
6956 RETURN_ON_EXCEPTION_VALUE(it->isolate(),
6957 DefineOwnPropertyIgnoreAttributes(it, value, NONE),
6958 Nothing<bool>());
6959
6960 return Just(true);
6961 }
6962
6963
6964 // TODO(jkummerow): Consider unification with FastAsArrayLength() in
6965 // accessors.cc.
PropertyKeyToArrayLength(Handle<Object> value,uint32_t * length)6966 bool PropertyKeyToArrayLength(Handle<Object> value, uint32_t* length) {
6967 DCHECK(value->IsNumber() || value->IsName());
6968 if (value->ToArrayLength(length)) return true;
6969 if (value->IsString()) return String::cast(*value)->AsArrayIndex(length);
6970 return false;
6971 }
6972
6973
PropertyKeyToArrayIndex(Handle<Object> index_obj,uint32_t * output)6974 bool PropertyKeyToArrayIndex(Handle<Object> index_obj, uint32_t* output) {
6975 return PropertyKeyToArrayLength(index_obj, output) && *output != kMaxUInt32;
6976 }
6977
6978
6979 // ES6 9.4.2.1
6980 // static
DefineOwnProperty(Isolate * isolate,Handle<JSArray> o,Handle<Object> name,PropertyDescriptor * desc,ShouldThrow should_throw)6981 Maybe<bool> JSArray::DefineOwnProperty(Isolate* isolate, Handle<JSArray> o,
6982 Handle<Object> name,
6983 PropertyDescriptor* desc,
6984 ShouldThrow should_throw) {
6985 // 1. Assert: IsPropertyKey(P) is true. ("P" is |name|.)
6986 // 2. If P is "length", then:
6987 // TODO(jkummerow): Check if we need slow string comparison.
6988 if (*name == isolate->heap()->length_string()) {
6989 // 2a. Return ArraySetLength(A, Desc).
6990 return ArraySetLength(isolate, o, desc, should_throw);
6991 }
6992 // 3. Else if P is an array index, then:
6993 uint32_t index = 0;
6994 if (PropertyKeyToArrayIndex(name, &index)) {
6995 // 3a. Let oldLenDesc be OrdinaryGetOwnProperty(A, "length").
6996 PropertyDescriptor old_len_desc;
6997 Maybe<bool> success = GetOwnPropertyDescriptor(
6998 isolate, o, isolate->factory()->length_string(), &old_len_desc);
6999 // 3b. (Assert)
7000 DCHECK(success.FromJust());
7001 USE(success);
7002 // 3c. Let oldLen be oldLenDesc.[[Value]].
7003 uint32_t old_len = 0;
7004 CHECK(old_len_desc.value()->ToArrayLength(&old_len));
7005 // 3d. Let index be ToUint32(P).
7006 // (Already done above.)
7007 // 3e. (Assert)
7008 // 3f. If index >= oldLen and oldLenDesc.[[Writable]] is false,
7009 // return false.
7010 if (index >= old_len && old_len_desc.has_writable() &&
7011 !old_len_desc.writable()) {
7012 RETURN_FAILURE(isolate, should_throw,
7013 NewTypeError(MessageTemplate::kDefineDisallowed, name));
7014 }
7015 // 3g. Let succeeded be OrdinaryDefineOwnProperty(A, P, Desc).
7016 Maybe<bool> succeeded =
7017 OrdinaryDefineOwnProperty(isolate, o, name, desc, should_throw);
7018 // 3h. Assert: succeeded is not an abrupt completion.
7019 // In our case, if should_throw == THROW_ON_ERROR, it can be!
7020 // 3i. If succeeded is false, return false.
7021 if (succeeded.IsNothing() || !succeeded.FromJust()) return succeeded;
7022 // 3j. If index >= oldLen, then:
7023 if (index >= old_len) {
7024 // 3j i. Set oldLenDesc.[[Value]] to index + 1.
7025 old_len_desc.set_value(isolate->factory()->NewNumberFromUint(index + 1));
7026 // 3j ii. Let succeeded be
7027 // OrdinaryDefineOwnProperty(A, "length", oldLenDesc).
7028 succeeded = OrdinaryDefineOwnProperty(isolate, o,
7029 isolate->factory()->length_string(),
7030 &old_len_desc, should_throw);
7031 // 3j iii. Assert: succeeded is true.
7032 DCHECK(succeeded.FromJust());
7033 USE(succeeded);
7034 }
7035 // 3k. Return true.
7036 return Just(true);
7037 }
7038
7039 // 4. Return OrdinaryDefineOwnProperty(A, P, Desc).
7040 return OrdinaryDefineOwnProperty(isolate, o, name, desc, should_throw);
7041 }
7042
7043
7044 // Part of ES6 9.4.2.4 ArraySetLength.
7045 // static
AnythingToArrayLength(Isolate * isolate,Handle<Object> length_object,uint32_t * output)7046 bool JSArray::AnythingToArrayLength(Isolate* isolate,
7047 Handle<Object> length_object,
7048 uint32_t* output) {
7049 // Fast path: check numbers and strings that can be converted directly
7050 // and unobservably.
7051 if (length_object->ToArrayLength(output)) return true;
7052 if (length_object->IsString() &&
7053 Handle<String>::cast(length_object)->AsArrayIndex(output)) {
7054 return true;
7055 }
7056 // Slow path: follow steps in ES6 9.4.2.4 "ArraySetLength".
7057 // 3. Let newLen be ToUint32(Desc.[[Value]]).
7058 Handle<Object> uint32_v;
7059 if (!Object::ToUint32(isolate, length_object).ToHandle(&uint32_v)) {
7060 // 4. ReturnIfAbrupt(newLen).
7061 return false;
7062 }
7063 // 5. Let numberLen be ToNumber(Desc.[[Value]]).
7064 Handle<Object> number_v;
7065 if (!Object::ToNumber(length_object).ToHandle(&number_v)) {
7066 // 6. ReturnIfAbrupt(newLen).
7067 return false;
7068 }
7069 // 7. If newLen != numberLen, throw a RangeError exception.
7070 if (uint32_v->Number() != number_v->Number()) {
7071 Handle<Object> exception =
7072 isolate->factory()->NewRangeError(MessageTemplate::kInvalidArrayLength);
7073 isolate->Throw(*exception);
7074 return false;
7075 }
7076 CHECK(uint32_v->ToArrayLength(output));
7077 return true;
7078 }
7079
7080
7081 // ES6 9.4.2.4
7082 // static
ArraySetLength(Isolate * isolate,Handle<JSArray> a,PropertyDescriptor * desc,ShouldThrow should_throw)7083 Maybe<bool> JSArray::ArraySetLength(Isolate* isolate, Handle<JSArray> a,
7084 PropertyDescriptor* desc,
7085 ShouldThrow should_throw) {
7086 // 1. If the [[Value]] field of Desc is absent, then
7087 if (!desc->has_value()) {
7088 // 1a. Return OrdinaryDefineOwnProperty(A, "length", Desc).
7089 return OrdinaryDefineOwnProperty(
7090 isolate, a, isolate->factory()->length_string(), desc, should_throw);
7091 }
7092 // 2. Let newLenDesc be a copy of Desc.
7093 // (Actual copying is not necessary.)
7094 PropertyDescriptor* new_len_desc = desc;
7095 // 3. - 7. Convert Desc.[[Value]] to newLen.
7096 uint32_t new_len = 0;
7097 if (!AnythingToArrayLength(isolate, desc->value(), &new_len)) {
7098 DCHECK(isolate->has_pending_exception());
7099 return Nothing<bool>();
7100 }
7101 // 8. Set newLenDesc.[[Value]] to newLen.
7102 // (Done below, if needed.)
7103 // 9. Let oldLenDesc be OrdinaryGetOwnProperty(A, "length").
7104 PropertyDescriptor old_len_desc;
7105 Maybe<bool> success = GetOwnPropertyDescriptor(
7106 isolate, a, isolate->factory()->length_string(), &old_len_desc);
7107 // 10. (Assert)
7108 DCHECK(success.FromJust());
7109 USE(success);
7110 // 11. Let oldLen be oldLenDesc.[[Value]].
7111 uint32_t old_len = 0;
7112 CHECK(old_len_desc.value()->ToArrayLength(&old_len));
7113 // 12. If newLen >= oldLen, then
7114 if (new_len >= old_len) {
7115 // 8. Set newLenDesc.[[Value]] to newLen.
7116 // 12a. Return OrdinaryDefineOwnProperty(A, "length", newLenDesc).
7117 new_len_desc->set_value(isolate->factory()->NewNumberFromUint(new_len));
7118 return OrdinaryDefineOwnProperty(isolate, a,
7119 isolate->factory()->length_string(),
7120 new_len_desc, should_throw);
7121 }
7122 // 13. If oldLenDesc.[[Writable]] is false, return false.
7123 if (!old_len_desc.writable()) {
7124 RETURN_FAILURE(isolate, should_throw,
7125 NewTypeError(MessageTemplate::kRedefineDisallowed,
7126 isolate->factory()->length_string()));
7127 }
7128 // 14. If newLenDesc.[[Writable]] is absent or has the value true,
7129 // let newWritable be true.
7130 bool new_writable = false;
7131 if (!new_len_desc->has_writable() || new_len_desc->writable()) {
7132 new_writable = true;
7133 } else {
7134 // 15. Else,
7135 // 15a. Need to defer setting the [[Writable]] attribute to false in case
7136 // any elements cannot be deleted.
7137 // 15b. Let newWritable be false. (It's initialized as "false" anyway.)
7138 // 15c. Set newLenDesc.[[Writable]] to true.
7139 // (Not needed.)
7140 }
7141 // Most of steps 16 through 19 is implemented by JSArray::SetLength.
7142 JSArray::SetLength(a, new_len);
7143 // Steps 19d-ii, 20.
7144 if (!new_writable) {
7145 PropertyDescriptor readonly;
7146 readonly.set_writable(false);
7147 Maybe<bool> success = OrdinaryDefineOwnProperty(
7148 isolate, a, isolate->factory()->length_string(), &readonly,
7149 should_throw);
7150 DCHECK(success.FromJust());
7151 USE(success);
7152 }
7153 uint32_t actual_new_len = 0;
7154 CHECK(a->length()->ToArrayLength(&actual_new_len));
7155 // Steps 19d-v, 21. Return false if there were non-deletable elements.
7156 bool result = actual_new_len == new_len;
7157 if (!result) {
7158 RETURN_FAILURE(
7159 isolate, should_throw,
7160 NewTypeError(MessageTemplate::kStrictDeleteProperty,
7161 isolate->factory()->NewNumberFromUint(actual_new_len - 1),
7162 a));
7163 }
7164 return Just(result);
7165 }
7166
7167
7168 // ES6 9.5.6
7169 // static
DefineOwnProperty(Isolate * isolate,Handle<JSProxy> proxy,Handle<Object> key,PropertyDescriptor * desc,ShouldThrow should_throw)7170 Maybe<bool> JSProxy::DefineOwnProperty(Isolate* isolate, Handle<JSProxy> proxy,
7171 Handle<Object> key,
7172 PropertyDescriptor* desc,
7173 ShouldThrow should_throw) {
7174 STACK_CHECK(isolate, Nothing<bool>());
7175 if (key->IsSymbol() && Handle<Symbol>::cast(key)->IsPrivate()) {
7176 return SetPrivateProperty(isolate, proxy, Handle<Symbol>::cast(key), desc,
7177 should_throw);
7178 }
7179 Handle<String> trap_name = isolate->factory()->defineProperty_string();
7180 // 1. Assert: IsPropertyKey(P) is true.
7181 DCHECK(key->IsName() || key->IsNumber());
7182 // 2. Let handler be the value of the [[ProxyHandler]] internal slot of O.
7183 Handle<Object> handler(proxy->handler(), isolate);
7184 // 3. If handler is null, throw a TypeError exception.
7185 // 4. Assert: Type(handler) is Object.
7186 if (proxy->IsRevoked()) {
7187 isolate->Throw(*isolate->factory()->NewTypeError(
7188 MessageTemplate::kProxyRevoked, trap_name));
7189 return Nothing<bool>();
7190 }
7191 // 5. Let target be the value of the [[ProxyTarget]] internal slot of O.
7192 Handle<JSReceiver> target(proxy->target(), isolate);
7193 // 6. Let trap be ? GetMethod(handler, "defineProperty").
7194 Handle<Object> trap;
7195 ASSIGN_RETURN_ON_EXCEPTION_VALUE(
7196 isolate, trap,
7197 Object::GetMethod(Handle<JSReceiver>::cast(handler), trap_name),
7198 Nothing<bool>());
7199 // 7. If trap is undefined, then:
7200 if (trap->IsUndefined(isolate)) {
7201 // 7a. Return target.[[DefineOwnProperty]](P, Desc).
7202 return JSReceiver::DefineOwnProperty(isolate, target, key, desc,
7203 should_throw);
7204 }
7205 // 8. Let descObj be FromPropertyDescriptor(Desc).
7206 Handle<Object> desc_obj = desc->ToObject(isolate);
7207 // 9. Let booleanTrapResult be
7208 // ToBoolean(? Call(trap, handler, «target, P, descObj»)).
7209 Handle<Name> property_name =
7210 key->IsName()
7211 ? Handle<Name>::cast(key)
7212 : Handle<Name>::cast(isolate->factory()->NumberToString(key));
7213 // Do not leak private property names.
7214 DCHECK(!property_name->IsPrivate());
7215 Handle<Object> trap_result_obj;
7216 Handle<Object> args[] = {target, property_name, desc_obj};
7217 ASSIGN_RETURN_ON_EXCEPTION_VALUE(
7218 isolate, trap_result_obj,
7219 Execution::Call(isolate, trap, handler, arraysize(args), args),
7220 Nothing<bool>());
7221 // 10. If booleanTrapResult is false, return false.
7222 if (!trap_result_obj->BooleanValue()) {
7223 RETURN_FAILURE(isolate, should_throw,
7224 NewTypeError(MessageTemplate::kProxyTrapReturnedFalsishFor,
7225 trap_name, property_name));
7226 }
7227 // 11. Let targetDesc be ? target.[[GetOwnProperty]](P).
7228 PropertyDescriptor target_desc;
7229 Maybe<bool> target_found =
7230 JSReceiver::GetOwnPropertyDescriptor(isolate, target, key, &target_desc);
7231 MAYBE_RETURN(target_found, Nothing<bool>());
7232 // 12. Let extensibleTarget be ? IsExtensible(target).
7233 Maybe<bool> maybe_extensible = JSReceiver::IsExtensible(target);
7234 MAYBE_RETURN(maybe_extensible, Nothing<bool>());
7235 bool extensible_target = maybe_extensible.FromJust();
7236 // 13. If Desc has a [[Configurable]] field and if Desc.[[Configurable]]
7237 // is false, then:
7238 // 13a. Let settingConfigFalse be true.
7239 // 14. Else let settingConfigFalse be false.
7240 bool setting_config_false = desc->has_configurable() && !desc->configurable();
7241 // 15. If targetDesc is undefined, then
7242 if (!target_found.FromJust()) {
7243 // 15a. If extensibleTarget is false, throw a TypeError exception.
7244 if (!extensible_target) {
7245 isolate->Throw(*isolate->factory()->NewTypeError(
7246 MessageTemplate::kProxyDefinePropertyNonExtensible, property_name));
7247 return Nothing<bool>();
7248 }
7249 // 15b. If settingConfigFalse is true, throw a TypeError exception.
7250 if (setting_config_false) {
7251 isolate->Throw(*isolate->factory()->NewTypeError(
7252 MessageTemplate::kProxyDefinePropertyNonConfigurable, property_name));
7253 return Nothing<bool>();
7254 }
7255 } else {
7256 // 16. Else targetDesc is not undefined,
7257 // 16a. If IsCompatiblePropertyDescriptor(extensibleTarget, Desc,
7258 // targetDesc) is false, throw a TypeError exception.
7259 Maybe<bool> valid =
7260 IsCompatiblePropertyDescriptor(isolate, extensible_target, desc,
7261 &target_desc, property_name, DONT_THROW);
7262 MAYBE_RETURN(valid, Nothing<bool>());
7263 if (!valid.FromJust()) {
7264 isolate->Throw(*isolate->factory()->NewTypeError(
7265 MessageTemplate::kProxyDefinePropertyIncompatible, property_name));
7266 return Nothing<bool>();
7267 }
7268 // 16b. If settingConfigFalse is true and targetDesc.[[Configurable]] is
7269 // true, throw a TypeError exception.
7270 if (setting_config_false && target_desc.configurable()) {
7271 isolate->Throw(*isolate->factory()->NewTypeError(
7272 MessageTemplate::kProxyDefinePropertyNonConfigurable, property_name));
7273 return Nothing<bool>();
7274 }
7275 }
7276 // 17. Return true.
7277 return Just(true);
7278 }
7279
7280
7281 // static
SetPrivateProperty(Isolate * isolate,Handle<JSProxy> proxy,Handle<Symbol> private_name,PropertyDescriptor * desc,ShouldThrow should_throw)7282 Maybe<bool> JSProxy::SetPrivateProperty(Isolate* isolate, Handle<JSProxy> proxy,
7283 Handle<Symbol> private_name,
7284 PropertyDescriptor* desc,
7285 ShouldThrow should_throw) {
7286 // Despite the generic name, this can only add private data properties.
7287 if (!PropertyDescriptor::IsDataDescriptor(desc) ||
7288 desc->ToAttributes() != DONT_ENUM) {
7289 RETURN_FAILURE(isolate, should_throw,
7290 NewTypeError(MessageTemplate::kProxyPrivate));
7291 }
7292 DCHECK(proxy->map()->is_dictionary_map());
7293 Handle<Object> value =
7294 desc->has_value()
7295 ? desc->value()
7296 : Handle<Object>::cast(isolate->factory()->undefined_value());
7297
7298 LookupIterator it(proxy, private_name, proxy);
7299
7300 if (it.IsFound()) {
7301 DCHECK_EQ(LookupIterator::DATA, it.state());
7302 DCHECK_EQ(DONT_ENUM, it.property_attributes());
7303 it.WriteDataValue(value);
7304 return Just(true);
7305 }
7306
7307 Handle<NameDictionary> dict(proxy->property_dictionary());
7308 PropertyDetails details(DONT_ENUM, DATA, 0, PropertyCellType::kNoCell);
7309 Handle<NameDictionary> result =
7310 NameDictionary::Add(dict, private_name, value, details);
7311 if (!dict.is_identical_to(result)) proxy->set_properties(*result);
7312 return Just(true);
7313 }
7314
7315
7316 // static
GetOwnPropertyDescriptor(Isolate * isolate,Handle<JSReceiver> object,Handle<Object> key,PropertyDescriptor * desc)7317 Maybe<bool> JSReceiver::GetOwnPropertyDescriptor(Isolate* isolate,
7318 Handle<JSReceiver> object,
7319 Handle<Object> key,
7320 PropertyDescriptor* desc) {
7321 bool success = false;
7322 DCHECK(key->IsName() || key->IsNumber()); // |key| is a PropertyKey...
7323 LookupIterator it = LookupIterator::PropertyOrElement(
7324 isolate, object, key, &success, LookupIterator::OWN);
7325 DCHECK(success); // ...so creating a LookupIterator can't fail.
7326 return GetOwnPropertyDescriptor(&it, desc);
7327 }
7328
7329 namespace {
7330
GetPropertyDescriptorWithInterceptor(LookupIterator * it,PropertyDescriptor * desc)7331 Maybe<bool> GetPropertyDescriptorWithInterceptor(LookupIterator* it,
7332 PropertyDescriptor* desc) {
7333 if (it->state() == LookupIterator::INTERCEPTOR) {
7334 Isolate* isolate = it->isolate();
7335 Handle<InterceptorInfo> interceptor = it->GetInterceptor();
7336 if (!interceptor->descriptor()->IsUndefined(isolate)) {
7337 Handle<Object> result;
7338 Handle<JSObject> holder = it->GetHolder<JSObject>();
7339
7340 Handle<Object> receiver = it->GetReceiver();
7341 if (!receiver->IsJSReceiver()) {
7342 ASSIGN_RETURN_ON_EXCEPTION_VALUE(
7343 isolate, receiver, Object::ConvertReceiver(isolate, receiver),
7344 Nothing<bool>());
7345 }
7346
7347 PropertyCallbackArguments args(isolate, interceptor->data(), *receiver,
7348 *holder, Object::DONT_THROW);
7349 if (it->IsElement()) {
7350 uint32_t index = it->index();
7351 v8::IndexedPropertyDescriptorCallback descriptorCallback =
7352 v8::ToCData<v8::IndexedPropertyDescriptorCallback>(
7353 interceptor->descriptor());
7354
7355 result = args.Call(descriptorCallback, index);
7356 } else {
7357 Handle<Name> name = it->name();
7358 DCHECK(!name->IsPrivate());
7359 v8::GenericNamedPropertyDescriptorCallback descriptorCallback =
7360 v8::ToCData<v8::GenericNamedPropertyDescriptorCallback>(
7361 interceptor->descriptor());
7362 result = args.Call(descriptorCallback, name);
7363 }
7364 if (!result.is_null()) {
7365 // Request successfully intercepted, try to set the property
7366 // descriptor.
7367 Utils::ApiCheck(
7368 PropertyDescriptor::ToPropertyDescriptor(isolate, result, desc),
7369 it->IsElement() ? "v8::IndexedPropertyDescriptorCallback"
7370 : "v8::NamedPropertyDescriptorCallback",
7371 "Invalid property descriptor.");
7372
7373 return Just(true);
7374 }
7375 }
7376 }
7377 return Just(false);
7378 }
7379 } // namespace
7380
7381 // ES6 9.1.5.1
7382 // Returns true on success, false if the property didn't exist, nothing if
7383 // an exception was thrown.
7384 // static
GetOwnPropertyDescriptor(LookupIterator * it,PropertyDescriptor * desc)7385 Maybe<bool> JSReceiver::GetOwnPropertyDescriptor(LookupIterator* it,
7386 PropertyDescriptor* desc) {
7387 Isolate* isolate = it->isolate();
7388 // "Virtual" dispatch.
7389 if (it->IsFound() && it->GetHolder<JSReceiver>()->IsJSProxy()) {
7390 return JSProxy::GetOwnPropertyDescriptor(isolate, it->GetHolder<JSProxy>(),
7391 it->GetName(), desc);
7392 }
7393
7394 Maybe<bool> intercepted = GetPropertyDescriptorWithInterceptor(it, desc);
7395 MAYBE_RETURN(intercepted, Nothing<bool>());
7396 if (intercepted.FromJust()) {
7397 return Just(true);
7398 }
7399
7400 // Request was not intercepted, continue as normal.
7401 // 1. (Assert)
7402 // 2. If O does not have an own property with key P, return undefined.
7403 Maybe<PropertyAttributes> maybe = JSObject::GetPropertyAttributes(it);
7404 MAYBE_RETURN(maybe, Nothing<bool>());
7405 PropertyAttributes attrs = maybe.FromJust();
7406 if (attrs == ABSENT) return Just(false);
7407 DCHECK(!isolate->has_pending_exception());
7408
7409 // 3. Let D be a newly created Property Descriptor with no fields.
7410 DCHECK(desc->is_empty());
7411 // 4. Let X be O's own property whose key is P.
7412 // 5. If X is a data property, then
7413 bool is_accessor_pair = it->state() == LookupIterator::ACCESSOR &&
7414 it->GetAccessors()->IsAccessorPair();
7415 if (!is_accessor_pair) {
7416 // 5a. Set D.[[Value]] to the value of X's [[Value]] attribute.
7417 Handle<Object> value;
7418 if (!Object::GetProperty(it).ToHandle(&value)) {
7419 DCHECK(isolate->has_pending_exception());
7420 return Nothing<bool>();
7421 }
7422 desc->set_value(value);
7423 // 5b. Set D.[[Writable]] to the value of X's [[Writable]] attribute
7424 desc->set_writable((attrs & READ_ONLY) == 0);
7425 } else {
7426 // 6. Else X is an accessor property, so
7427 Handle<AccessorPair> accessors =
7428 Handle<AccessorPair>::cast(it->GetAccessors());
7429 // 6a. Set D.[[Get]] to the value of X's [[Get]] attribute.
7430 desc->set_get(AccessorPair::GetComponent(accessors, ACCESSOR_GETTER));
7431 // 6b. Set D.[[Set]] to the value of X's [[Set]] attribute.
7432 desc->set_set(AccessorPair::GetComponent(accessors, ACCESSOR_SETTER));
7433 }
7434
7435 // 7. Set D.[[Enumerable]] to the value of X's [[Enumerable]] attribute.
7436 desc->set_enumerable((attrs & DONT_ENUM) == 0);
7437 // 8. Set D.[[Configurable]] to the value of X's [[Configurable]] attribute.
7438 desc->set_configurable((attrs & DONT_DELETE) == 0);
7439 // 9. Return D.
7440 DCHECK(PropertyDescriptor::IsAccessorDescriptor(desc) !=
7441 PropertyDescriptor::IsDataDescriptor(desc));
7442 return Just(true);
7443 }
7444
7445
7446 // ES6 9.5.5
7447 // static
GetOwnPropertyDescriptor(Isolate * isolate,Handle<JSProxy> proxy,Handle<Name> name,PropertyDescriptor * desc)7448 Maybe<bool> JSProxy::GetOwnPropertyDescriptor(Isolate* isolate,
7449 Handle<JSProxy> proxy,
7450 Handle<Name> name,
7451 PropertyDescriptor* desc) {
7452 DCHECK(!name->IsPrivate());
7453 STACK_CHECK(isolate, Nothing<bool>());
7454
7455 Handle<String> trap_name =
7456 isolate->factory()->getOwnPropertyDescriptor_string();
7457 // 1. (Assert)
7458 // 2. Let handler be the value of the [[ProxyHandler]] internal slot of O.
7459 Handle<Object> handler(proxy->handler(), isolate);
7460 // 3. If handler is null, throw a TypeError exception.
7461 // 4. Assert: Type(handler) is Object.
7462 if (proxy->IsRevoked()) {
7463 isolate->Throw(*isolate->factory()->NewTypeError(
7464 MessageTemplate::kProxyRevoked, trap_name));
7465 return Nothing<bool>();
7466 }
7467 // 5. Let target be the value of the [[ProxyTarget]] internal slot of O.
7468 Handle<JSReceiver> target(proxy->target(), isolate);
7469 // 6. Let trap be ? GetMethod(handler, "getOwnPropertyDescriptor").
7470 Handle<Object> trap;
7471 ASSIGN_RETURN_ON_EXCEPTION_VALUE(
7472 isolate, trap,
7473 Object::GetMethod(Handle<JSReceiver>::cast(handler), trap_name),
7474 Nothing<bool>());
7475 // 7. If trap is undefined, then
7476 if (trap->IsUndefined(isolate)) {
7477 // 7a. Return target.[[GetOwnProperty]](P).
7478 return JSReceiver::GetOwnPropertyDescriptor(isolate, target, name, desc);
7479 }
7480 // 8. Let trapResultObj be ? Call(trap, handler, «target, P»).
7481 Handle<Object> trap_result_obj;
7482 Handle<Object> args[] = {target, name};
7483 ASSIGN_RETURN_ON_EXCEPTION_VALUE(
7484 isolate, trap_result_obj,
7485 Execution::Call(isolate, trap, handler, arraysize(args), args),
7486 Nothing<bool>());
7487 // 9. If Type(trapResultObj) is neither Object nor Undefined, throw a
7488 // TypeError exception.
7489 if (!trap_result_obj->IsJSReceiver() &&
7490 !trap_result_obj->IsUndefined(isolate)) {
7491 isolate->Throw(*isolate->factory()->NewTypeError(
7492 MessageTemplate::kProxyGetOwnPropertyDescriptorInvalid, name));
7493 return Nothing<bool>();
7494 }
7495 // 10. Let targetDesc be ? target.[[GetOwnProperty]](P).
7496 PropertyDescriptor target_desc;
7497 Maybe<bool> found =
7498 JSReceiver::GetOwnPropertyDescriptor(isolate, target, name, &target_desc);
7499 MAYBE_RETURN(found, Nothing<bool>());
7500 // 11. If trapResultObj is undefined, then
7501 if (trap_result_obj->IsUndefined(isolate)) {
7502 // 11a. If targetDesc is undefined, return undefined.
7503 if (!found.FromJust()) return Just(false);
7504 // 11b. If targetDesc.[[Configurable]] is false, throw a TypeError
7505 // exception.
7506 if (!target_desc.configurable()) {
7507 isolate->Throw(*isolate->factory()->NewTypeError(
7508 MessageTemplate::kProxyGetOwnPropertyDescriptorUndefined, name));
7509 return Nothing<bool>();
7510 }
7511 // 11c. Let extensibleTarget be ? IsExtensible(target).
7512 Maybe<bool> extensible_target = JSReceiver::IsExtensible(target);
7513 MAYBE_RETURN(extensible_target, Nothing<bool>());
7514 // 11d. (Assert)
7515 // 11e. If extensibleTarget is false, throw a TypeError exception.
7516 if (!extensible_target.FromJust()) {
7517 isolate->Throw(*isolate->factory()->NewTypeError(
7518 MessageTemplate::kProxyGetOwnPropertyDescriptorNonExtensible, name));
7519 return Nothing<bool>();
7520 }
7521 // 11f. Return undefined.
7522 return Just(false);
7523 }
7524 // 12. Let extensibleTarget be ? IsExtensible(target).
7525 Maybe<bool> extensible_target = JSReceiver::IsExtensible(target);
7526 MAYBE_RETURN(extensible_target, Nothing<bool>());
7527 // 13. Let resultDesc be ? ToPropertyDescriptor(trapResultObj).
7528 if (!PropertyDescriptor::ToPropertyDescriptor(isolate, trap_result_obj,
7529 desc)) {
7530 DCHECK(isolate->has_pending_exception());
7531 return Nothing<bool>();
7532 }
7533 // 14. Call CompletePropertyDescriptor(resultDesc).
7534 PropertyDescriptor::CompletePropertyDescriptor(isolate, desc);
7535 // 15. Let valid be IsCompatiblePropertyDescriptor (extensibleTarget,
7536 // resultDesc, targetDesc).
7537 Maybe<bool> valid =
7538 IsCompatiblePropertyDescriptor(isolate, extensible_target.FromJust(),
7539 desc, &target_desc, name, DONT_THROW);
7540 MAYBE_RETURN(valid, Nothing<bool>());
7541 // 16. If valid is false, throw a TypeError exception.
7542 if (!valid.FromJust()) {
7543 isolate->Throw(*isolate->factory()->NewTypeError(
7544 MessageTemplate::kProxyGetOwnPropertyDescriptorIncompatible, name));
7545 return Nothing<bool>();
7546 }
7547 // 17. If resultDesc.[[Configurable]] is false, then
7548 if (!desc->configurable()) {
7549 // 17a. If targetDesc is undefined or targetDesc.[[Configurable]] is true:
7550 if (target_desc.is_empty() || target_desc.configurable()) {
7551 // 17a i. Throw a TypeError exception.
7552 isolate->Throw(*isolate->factory()->NewTypeError(
7553 MessageTemplate::kProxyGetOwnPropertyDescriptorNonConfigurable,
7554 name));
7555 return Nothing<bool>();
7556 }
7557 }
7558 // 18. Return resultDesc.
7559 return Just(true);
7560 }
7561
7562
ReferencesObjectFromElements(FixedArray * elements,ElementsKind kind,Object * object)7563 bool JSObject::ReferencesObjectFromElements(FixedArray* elements,
7564 ElementsKind kind,
7565 Object* object) {
7566 Isolate* isolate = elements->GetIsolate();
7567 if (IsFastObjectElementsKind(kind) || kind == FAST_STRING_WRAPPER_ELEMENTS) {
7568 int length = IsJSArray()
7569 ? Smi::cast(JSArray::cast(this)->length())->value()
7570 : elements->length();
7571 for (int i = 0; i < length; ++i) {
7572 Object* element = elements->get(i);
7573 if (!element->IsTheHole(isolate) && element == object) return true;
7574 }
7575 } else {
7576 DCHECK(kind == DICTIONARY_ELEMENTS || kind == SLOW_STRING_WRAPPER_ELEMENTS);
7577 Object* key =
7578 SeededNumberDictionary::cast(elements)->SlowReverseLookup(object);
7579 if (!key->IsUndefined(isolate)) return true;
7580 }
7581 return false;
7582 }
7583
7584
7585 // Check whether this object references another object.
ReferencesObject(Object * obj)7586 bool JSObject::ReferencesObject(Object* obj) {
7587 Map* map_of_this = map();
7588 Heap* heap = GetHeap();
7589 DisallowHeapAllocation no_allocation;
7590
7591 // Is the object the constructor for this object?
7592 if (map_of_this->GetConstructor() == obj) {
7593 return true;
7594 }
7595
7596 // Is the object the prototype for this object?
7597 if (map_of_this->prototype() == obj) {
7598 return true;
7599 }
7600
7601 // Check if the object is among the named properties.
7602 Object* key = SlowReverseLookup(obj);
7603 if (!key->IsUndefined(heap->isolate())) {
7604 return true;
7605 }
7606
7607 // Check if the object is among the indexed properties.
7608 ElementsKind kind = GetElementsKind();
7609 switch (kind) {
7610 // Raw pixels and external arrays do not reference other
7611 // objects.
7612 #define TYPED_ARRAY_CASE(Type, type, TYPE, ctype, size) \
7613 case TYPE##_ELEMENTS: \
7614 break;
7615
7616 TYPED_ARRAYS(TYPED_ARRAY_CASE)
7617 #undef TYPED_ARRAY_CASE
7618
7619 case FAST_DOUBLE_ELEMENTS:
7620 case FAST_HOLEY_DOUBLE_ELEMENTS:
7621 break;
7622 case FAST_SMI_ELEMENTS:
7623 case FAST_HOLEY_SMI_ELEMENTS:
7624 break;
7625 case FAST_ELEMENTS:
7626 case FAST_HOLEY_ELEMENTS:
7627 case DICTIONARY_ELEMENTS:
7628 case FAST_STRING_WRAPPER_ELEMENTS:
7629 case SLOW_STRING_WRAPPER_ELEMENTS: {
7630 FixedArray* elements = FixedArray::cast(this->elements());
7631 if (ReferencesObjectFromElements(elements, kind, obj)) return true;
7632 break;
7633 }
7634 case FAST_SLOPPY_ARGUMENTS_ELEMENTS:
7635 case SLOW_SLOPPY_ARGUMENTS_ELEMENTS: {
7636 FixedArray* parameter_map = FixedArray::cast(elements());
7637 // Check the mapped parameters.
7638 int length = parameter_map->length();
7639 for (int i = 2; i < length; ++i) {
7640 Object* value = parameter_map->get(i);
7641 if (!value->IsTheHole(heap->isolate()) && value == obj) return true;
7642 }
7643 // Check the arguments.
7644 FixedArray* arguments = FixedArray::cast(parameter_map->get(1));
7645 kind = arguments->IsDictionary() ? DICTIONARY_ELEMENTS :
7646 FAST_HOLEY_ELEMENTS;
7647 if (ReferencesObjectFromElements(arguments, kind, obj)) return true;
7648 break;
7649 }
7650 case NO_ELEMENTS:
7651 break;
7652 }
7653
7654 // For functions check the context.
7655 if (IsJSFunction()) {
7656 // Get the constructor function for arguments array.
7657 Map* arguments_map =
7658 heap->isolate()->context()->native_context()->sloppy_arguments_map();
7659 JSFunction* arguments_function =
7660 JSFunction::cast(arguments_map->GetConstructor());
7661
7662 // Get the context and don't check if it is the native context.
7663 JSFunction* f = JSFunction::cast(this);
7664 Context* context = f->context();
7665 if (context->IsNativeContext()) {
7666 return false;
7667 }
7668
7669 // Check the non-special context slots.
7670 for (int i = Context::MIN_CONTEXT_SLOTS; i < context->length(); i++) {
7671 // Only check JS objects.
7672 if (context->get(i)->IsJSObject()) {
7673 JSObject* ctxobj = JSObject::cast(context->get(i));
7674 // If it is an arguments array check the content.
7675 if (ctxobj->map()->GetConstructor() == arguments_function) {
7676 if (ctxobj->ReferencesObject(obj)) {
7677 return true;
7678 }
7679 } else if (ctxobj == obj) {
7680 return true;
7681 }
7682 }
7683 }
7684
7685 // Check the context extension (if any) if it can have references.
7686 if (context->has_extension() && !context->IsCatchContext()) {
7687 // With harmony scoping, a JSFunction may have a script context.
7688 // TODO(mvstanton): walk into the ScopeInfo.
7689 if (context->IsScriptContext()) {
7690 return false;
7691 }
7692
7693 return context->extension_object()->ReferencesObject(obj);
7694 }
7695 }
7696
7697 // No references to object.
7698 return false;
7699 }
7700
7701
SetIntegrityLevel(Handle<JSReceiver> receiver,IntegrityLevel level,ShouldThrow should_throw)7702 Maybe<bool> JSReceiver::SetIntegrityLevel(Handle<JSReceiver> receiver,
7703 IntegrityLevel level,
7704 ShouldThrow should_throw) {
7705 DCHECK(level == SEALED || level == FROZEN);
7706
7707 if (receiver->IsJSObject()) {
7708 Handle<JSObject> object = Handle<JSObject>::cast(receiver);
7709 if (!object->HasSloppyArgumentsElements()) { // Fast path.
7710 if (level == SEALED) {
7711 return JSObject::PreventExtensionsWithTransition<SEALED>(object,
7712 should_throw);
7713 } else {
7714 return JSObject::PreventExtensionsWithTransition<FROZEN>(object,
7715 should_throw);
7716 }
7717 }
7718 }
7719
7720 Isolate* isolate = receiver->GetIsolate();
7721
7722 MAYBE_RETURN(JSReceiver::PreventExtensions(receiver, should_throw),
7723 Nothing<bool>());
7724
7725 Handle<FixedArray> keys;
7726 ASSIGN_RETURN_ON_EXCEPTION_VALUE(
7727 isolate, keys, JSReceiver::OwnPropertyKeys(receiver), Nothing<bool>());
7728
7729 PropertyDescriptor no_conf;
7730 no_conf.set_configurable(false);
7731
7732 PropertyDescriptor no_conf_no_write;
7733 no_conf_no_write.set_configurable(false);
7734 no_conf_no_write.set_writable(false);
7735
7736 if (level == SEALED) {
7737 for (int i = 0; i < keys->length(); ++i) {
7738 Handle<Object> key(keys->get(i), isolate);
7739 MAYBE_RETURN(
7740 DefineOwnProperty(isolate, receiver, key, &no_conf, THROW_ON_ERROR),
7741 Nothing<bool>());
7742 }
7743 return Just(true);
7744 }
7745
7746 for (int i = 0; i < keys->length(); ++i) {
7747 Handle<Object> key(keys->get(i), isolate);
7748 PropertyDescriptor current_desc;
7749 Maybe<bool> owned = JSReceiver::GetOwnPropertyDescriptor(
7750 isolate, receiver, key, ¤t_desc);
7751 MAYBE_RETURN(owned, Nothing<bool>());
7752 if (owned.FromJust()) {
7753 PropertyDescriptor desc =
7754 PropertyDescriptor::IsAccessorDescriptor(¤t_desc)
7755 ? no_conf
7756 : no_conf_no_write;
7757 MAYBE_RETURN(
7758 DefineOwnProperty(isolate, receiver, key, &desc, THROW_ON_ERROR),
7759 Nothing<bool>());
7760 }
7761 }
7762 return Just(true);
7763 }
7764
7765
TestIntegrityLevel(Handle<JSReceiver> object,IntegrityLevel level)7766 Maybe<bool> JSReceiver::TestIntegrityLevel(Handle<JSReceiver> object,
7767 IntegrityLevel level) {
7768 DCHECK(level == SEALED || level == FROZEN);
7769 Isolate* isolate = object->GetIsolate();
7770
7771 Maybe<bool> extensible = JSReceiver::IsExtensible(object);
7772 MAYBE_RETURN(extensible, Nothing<bool>());
7773 if (extensible.FromJust()) return Just(false);
7774
7775 Handle<FixedArray> keys;
7776 ASSIGN_RETURN_ON_EXCEPTION_VALUE(
7777 isolate, keys, JSReceiver::OwnPropertyKeys(object), Nothing<bool>());
7778
7779 for (int i = 0; i < keys->length(); ++i) {
7780 Handle<Object> key(keys->get(i), isolate);
7781 PropertyDescriptor current_desc;
7782 Maybe<bool> owned = JSReceiver::GetOwnPropertyDescriptor(
7783 isolate, object, key, ¤t_desc);
7784 MAYBE_RETURN(owned, Nothing<bool>());
7785 if (owned.FromJust()) {
7786 if (current_desc.configurable()) return Just(false);
7787 if (level == FROZEN &&
7788 PropertyDescriptor::IsDataDescriptor(¤t_desc) &&
7789 current_desc.writable()) {
7790 return Just(false);
7791 }
7792 }
7793 }
7794 return Just(true);
7795 }
7796
7797
PreventExtensions(Handle<JSReceiver> object,ShouldThrow should_throw)7798 Maybe<bool> JSReceiver::PreventExtensions(Handle<JSReceiver> object,
7799 ShouldThrow should_throw) {
7800 if (object->IsJSProxy()) {
7801 return JSProxy::PreventExtensions(Handle<JSProxy>::cast(object),
7802 should_throw);
7803 }
7804 DCHECK(object->IsJSObject());
7805 return JSObject::PreventExtensions(Handle<JSObject>::cast(object),
7806 should_throw);
7807 }
7808
7809
PreventExtensions(Handle<JSProxy> proxy,ShouldThrow should_throw)7810 Maybe<bool> JSProxy::PreventExtensions(Handle<JSProxy> proxy,
7811 ShouldThrow should_throw) {
7812 Isolate* isolate = proxy->GetIsolate();
7813 STACK_CHECK(isolate, Nothing<bool>());
7814 Factory* factory = isolate->factory();
7815 Handle<String> trap_name = factory->preventExtensions_string();
7816
7817 if (proxy->IsRevoked()) {
7818 isolate->Throw(
7819 *factory->NewTypeError(MessageTemplate::kProxyRevoked, trap_name));
7820 return Nothing<bool>();
7821 }
7822 Handle<JSReceiver> target(proxy->target(), isolate);
7823 Handle<JSReceiver> handler(JSReceiver::cast(proxy->handler()), isolate);
7824
7825 Handle<Object> trap;
7826 ASSIGN_RETURN_ON_EXCEPTION_VALUE(
7827 isolate, trap, Object::GetMethod(handler, trap_name), Nothing<bool>());
7828 if (trap->IsUndefined(isolate)) {
7829 return JSReceiver::PreventExtensions(target, should_throw);
7830 }
7831
7832 Handle<Object> trap_result;
7833 Handle<Object> args[] = {target};
7834 ASSIGN_RETURN_ON_EXCEPTION_VALUE(
7835 isolate, trap_result,
7836 Execution::Call(isolate, trap, handler, arraysize(args), args),
7837 Nothing<bool>());
7838 if (!trap_result->BooleanValue()) {
7839 RETURN_FAILURE(
7840 isolate, should_throw,
7841 NewTypeError(MessageTemplate::kProxyTrapReturnedFalsish, trap_name));
7842 }
7843
7844 // Enforce the invariant.
7845 Maybe<bool> target_result = JSReceiver::IsExtensible(target);
7846 MAYBE_RETURN(target_result, Nothing<bool>());
7847 if (target_result.FromJust()) {
7848 isolate->Throw(*factory->NewTypeError(
7849 MessageTemplate::kProxyPreventExtensionsExtensible));
7850 return Nothing<bool>();
7851 }
7852 return Just(true);
7853 }
7854
7855
PreventExtensions(Handle<JSObject> object,ShouldThrow should_throw)7856 Maybe<bool> JSObject::PreventExtensions(Handle<JSObject> object,
7857 ShouldThrow should_throw) {
7858 Isolate* isolate = object->GetIsolate();
7859
7860 if (!object->HasSloppyArgumentsElements()) {
7861 return PreventExtensionsWithTransition<NONE>(object, should_throw);
7862 }
7863
7864 if (object->IsAccessCheckNeeded() &&
7865 !isolate->MayAccess(handle(isolate->context()), object)) {
7866 isolate->ReportFailedAccessCheck(object);
7867 RETURN_VALUE_IF_SCHEDULED_EXCEPTION(isolate, Nothing<bool>());
7868 RETURN_FAILURE(isolate, should_throw,
7869 NewTypeError(MessageTemplate::kNoAccess));
7870 }
7871
7872 if (!object->map()->is_extensible()) return Just(true);
7873
7874 if (object->IsJSGlobalProxy()) {
7875 PrototypeIterator iter(isolate, object);
7876 if (iter.IsAtEnd()) return Just(true);
7877 DCHECK(PrototypeIterator::GetCurrent(iter)->IsJSGlobalObject());
7878 return PreventExtensions(PrototypeIterator::GetCurrent<JSObject>(iter),
7879 should_throw);
7880 }
7881
7882 if (!object->HasFixedTypedArrayElements()) {
7883 // If there are fast elements we normalize.
7884 Handle<SeededNumberDictionary> dictionary = NormalizeElements(object);
7885 DCHECK(object->HasDictionaryElements() ||
7886 object->HasSlowArgumentsElements());
7887
7888 // Make sure that we never go back to fast case.
7889 object->RequireSlowElements(*dictionary);
7890 }
7891
7892 // Do a map transition, other objects with this map may still
7893 // be extensible.
7894 // TODO(adamk): Extend the NormalizedMapCache to handle non-extensible maps.
7895 Handle<Map> new_map = Map::Copy(handle(object->map()), "PreventExtensions");
7896
7897 new_map->set_is_extensible(false);
7898 JSObject::MigrateToMap(object, new_map);
7899 DCHECK(!object->map()->is_extensible());
7900
7901 return Just(true);
7902 }
7903
7904
IsExtensible(Handle<JSReceiver> object)7905 Maybe<bool> JSReceiver::IsExtensible(Handle<JSReceiver> object) {
7906 if (object->IsJSProxy()) {
7907 return JSProxy::IsExtensible(Handle<JSProxy>::cast(object));
7908 }
7909 return Just(JSObject::IsExtensible(Handle<JSObject>::cast(object)));
7910 }
7911
7912
IsExtensible(Handle<JSProxy> proxy)7913 Maybe<bool> JSProxy::IsExtensible(Handle<JSProxy> proxy) {
7914 Isolate* isolate = proxy->GetIsolate();
7915 STACK_CHECK(isolate, Nothing<bool>());
7916 Factory* factory = isolate->factory();
7917 Handle<String> trap_name = factory->isExtensible_string();
7918
7919 if (proxy->IsRevoked()) {
7920 isolate->Throw(
7921 *factory->NewTypeError(MessageTemplate::kProxyRevoked, trap_name));
7922 return Nothing<bool>();
7923 }
7924 Handle<JSReceiver> target(proxy->target(), isolate);
7925 Handle<JSReceiver> handler(JSReceiver::cast(proxy->handler()), isolate);
7926
7927 Handle<Object> trap;
7928 ASSIGN_RETURN_ON_EXCEPTION_VALUE(
7929 isolate, trap, Object::GetMethod(handler, trap_name), Nothing<bool>());
7930 if (trap->IsUndefined(isolate)) {
7931 return JSReceiver::IsExtensible(target);
7932 }
7933
7934 Handle<Object> trap_result;
7935 Handle<Object> args[] = {target};
7936 ASSIGN_RETURN_ON_EXCEPTION_VALUE(
7937 isolate, trap_result,
7938 Execution::Call(isolate, trap, handler, arraysize(args), args),
7939 Nothing<bool>());
7940
7941 // Enforce the invariant.
7942 Maybe<bool> target_result = JSReceiver::IsExtensible(target);
7943 MAYBE_RETURN(target_result, Nothing<bool>());
7944 if (target_result.FromJust() != trap_result->BooleanValue()) {
7945 isolate->Throw(
7946 *factory->NewTypeError(MessageTemplate::kProxyIsExtensibleInconsistent,
7947 factory->ToBoolean(target_result.FromJust())));
7948 return Nothing<bool>();
7949 }
7950 return target_result;
7951 }
7952
7953
IsExtensible(Handle<JSObject> object)7954 bool JSObject::IsExtensible(Handle<JSObject> object) {
7955 Isolate* isolate = object->GetIsolate();
7956 if (object->IsAccessCheckNeeded() &&
7957 !isolate->MayAccess(handle(isolate->context()), object)) {
7958 return true;
7959 }
7960 if (object->IsJSGlobalProxy()) {
7961 PrototypeIterator iter(isolate, *object);
7962 if (iter.IsAtEnd()) return false;
7963 DCHECK(iter.GetCurrent()->IsJSGlobalObject());
7964 return iter.GetCurrent<JSObject>()->map()->is_extensible();
7965 }
7966 return object->map()->is_extensible();
7967 }
7968
7969 namespace {
7970
7971 template <typename Dictionary>
DictionaryDetailsAtPut(Isolate * isolate,Handle<Dictionary> dictionary,int entry,PropertyDetails details)7972 void DictionaryDetailsAtPut(Isolate* isolate, Handle<Dictionary> dictionary,
7973 int entry, PropertyDetails details) {
7974 dictionary->DetailsAtPut(entry, details);
7975 }
7976
7977 template <>
DictionaryDetailsAtPut(Isolate * isolate,Handle<GlobalDictionary> dictionary,int entry,PropertyDetails details)7978 void DictionaryDetailsAtPut<GlobalDictionary>(
7979 Isolate* isolate, Handle<GlobalDictionary> dictionary, int entry,
7980 PropertyDetails details) {
7981 Object* value = dictionary->ValueAt(entry);
7982 DCHECK(value->IsPropertyCell());
7983 value = PropertyCell::cast(value)->value();
7984 if (value->IsTheHole(isolate)) return;
7985 PropertyCell::PrepareForValue(dictionary, entry, handle(value, isolate),
7986 details);
7987 }
7988
7989 template <typename Dictionary>
ApplyAttributesToDictionary(Isolate * isolate,Handle<Dictionary> dictionary,const PropertyAttributes attributes)7990 void ApplyAttributesToDictionary(Isolate* isolate,
7991 Handle<Dictionary> dictionary,
7992 const PropertyAttributes attributes) {
7993 int capacity = dictionary->Capacity();
7994 for (int i = 0; i < capacity; i++) {
7995 Object* k = dictionary->KeyAt(i);
7996 if (dictionary->IsKey(isolate, k) &&
7997 !(k->IsSymbol() && Symbol::cast(k)->is_private())) {
7998 PropertyDetails details = dictionary->DetailsAt(i);
7999 int attrs = attributes;
8000 // READ_ONLY is an invalid attribute for JS setters/getters.
8001 if ((attributes & READ_ONLY) && details.type() == ACCESSOR_CONSTANT) {
8002 Object* v = dictionary->ValueAt(i);
8003 if (v->IsPropertyCell()) v = PropertyCell::cast(v)->value();
8004 if (v->IsAccessorPair()) attrs &= ~READ_ONLY;
8005 }
8006 details = details.CopyAddAttributes(
8007 static_cast<PropertyAttributes>(attrs));
8008 DictionaryDetailsAtPut<Dictionary>(isolate, dictionary, i, details);
8009 }
8010 }
8011 }
8012
8013 } // namespace
8014
8015 template <PropertyAttributes attrs>
PreventExtensionsWithTransition(Handle<JSObject> object,ShouldThrow should_throw)8016 Maybe<bool> JSObject::PreventExtensionsWithTransition(
8017 Handle<JSObject> object, ShouldThrow should_throw) {
8018 STATIC_ASSERT(attrs == NONE || attrs == SEALED || attrs == FROZEN);
8019
8020 // Sealing/freezing sloppy arguments should be handled elsewhere.
8021 DCHECK(!object->HasSloppyArgumentsElements());
8022
8023 Isolate* isolate = object->GetIsolate();
8024 if (object->IsAccessCheckNeeded() &&
8025 !isolate->MayAccess(handle(isolate->context()), object)) {
8026 isolate->ReportFailedAccessCheck(object);
8027 RETURN_VALUE_IF_SCHEDULED_EXCEPTION(isolate, Nothing<bool>());
8028 RETURN_FAILURE(isolate, should_throw,
8029 NewTypeError(MessageTemplate::kNoAccess));
8030 }
8031
8032 if (attrs == NONE && !object->map()->is_extensible()) return Just(true);
8033
8034 if (object->IsJSGlobalProxy()) {
8035 PrototypeIterator iter(isolate, object);
8036 if (iter.IsAtEnd()) return Just(true);
8037 DCHECK(PrototypeIterator::GetCurrent(iter)->IsJSGlobalObject());
8038 return PreventExtensionsWithTransition<attrs>(
8039 PrototypeIterator::GetCurrent<JSObject>(iter), should_throw);
8040 }
8041
8042 Handle<SeededNumberDictionary> new_element_dictionary;
8043 if (!object->HasFixedTypedArrayElements() &&
8044 !object->HasDictionaryElements() &&
8045 !object->HasSlowStringWrapperElements()) {
8046 int length =
8047 object->IsJSArray()
8048 ? Smi::cast(Handle<JSArray>::cast(object)->length())->value()
8049 : object->elements()->length();
8050 new_element_dictionary =
8051 length == 0 ? isolate->factory()->empty_slow_element_dictionary()
8052 : object->GetElementsAccessor()->Normalize(object);
8053 }
8054
8055 Handle<Symbol> transition_marker;
8056 if (attrs == NONE) {
8057 transition_marker = isolate->factory()->nonextensible_symbol();
8058 } else if (attrs == SEALED) {
8059 transition_marker = isolate->factory()->sealed_symbol();
8060 } else {
8061 DCHECK(attrs == FROZEN);
8062 transition_marker = isolate->factory()->frozen_symbol();
8063 }
8064
8065 Handle<Map> old_map(object->map(), isolate);
8066 Map* transition =
8067 TransitionArray::SearchSpecial(*old_map, *transition_marker);
8068 if (transition != NULL) {
8069 Handle<Map> transition_map(transition, isolate);
8070 DCHECK(transition_map->has_dictionary_elements() ||
8071 transition_map->has_fixed_typed_array_elements() ||
8072 transition_map->elements_kind() == SLOW_STRING_WRAPPER_ELEMENTS);
8073 DCHECK(!transition_map->is_extensible());
8074 JSObject::MigrateToMap(object, transition_map);
8075 } else if (TransitionArray::CanHaveMoreTransitions(old_map)) {
8076 // Create a new descriptor array with the appropriate property attributes
8077 Handle<Map> new_map = Map::CopyForPreventExtensions(
8078 old_map, attrs, transition_marker, "CopyForPreventExtensions");
8079 JSObject::MigrateToMap(object, new_map);
8080 } else {
8081 DCHECK(old_map->is_dictionary_map() || !old_map->is_prototype_map());
8082 // Slow path: need to normalize properties for safety
8083 NormalizeProperties(object, CLEAR_INOBJECT_PROPERTIES, 0,
8084 "SlowPreventExtensions");
8085
8086 // Create a new map, since other objects with this map may be extensible.
8087 // TODO(adamk): Extend the NormalizedMapCache to handle non-extensible maps.
8088 Handle<Map> new_map =
8089 Map::Copy(handle(object->map()), "SlowCopyForPreventExtensions");
8090 new_map->set_is_extensible(false);
8091 if (!new_element_dictionary.is_null()) {
8092 ElementsKind new_kind =
8093 IsStringWrapperElementsKind(old_map->elements_kind())
8094 ? SLOW_STRING_WRAPPER_ELEMENTS
8095 : DICTIONARY_ELEMENTS;
8096 new_map->set_elements_kind(new_kind);
8097 }
8098 JSObject::MigrateToMap(object, new_map);
8099
8100 if (attrs != NONE) {
8101 if (object->IsJSGlobalObject()) {
8102 Handle<GlobalDictionary> dictionary(object->global_dictionary(),
8103 isolate);
8104 ApplyAttributesToDictionary(isolate, dictionary, attrs);
8105 } else {
8106 Handle<NameDictionary> dictionary(object->property_dictionary(),
8107 isolate);
8108 ApplyAttributesToDictionary(isolate, dictionary, attrs);
8109 }
8110 }
8111 }
8112
8113 // Both seal and preventExtensions always go through without modifications to
8114 // typed array elements. Freeze works only if there are no actual elements.
8115 if (object->HasFixedTypedArrayElements()) {
8116 if (attrs == FROZEN &&
8117 JSArrayBufferView::cast(*object)->byte_length()->Number() > 0) {
8118 isolate->Throw(*isolate->factory()->NewTypeError(
8119 MessageTemplate::kCannotFreezeArrayBufferView));
8120 return Nothing<bool>();
8121 }
8122 return Just(true);
8123 }
8124
8125 DCHECK(object->map()->has_dictionary_elements() ||
8126 object->map()->elements_kind() == SLOW_STRING_WRAPPER_ELEMENTS);
8127 if (!new_element_dictionary.is_null()) {
8128 object->set_elements(*new_element_dictionary);
8129 }
8130
8131 if (object->elements() != isolate->heap()->empty_slow_element_dictionary()) {
8132 Handle<SeededNumberDictionary> dictionary(object->element_dictionary(),
8133 isolate);
8134 // Make sure we never go back to the fast case
8135 object->RequireSlowElements(*dictionary);
8136 if (attrs != NONE) {
8137 ApplyAttributesToDictionary(isolate, dictionary, attrs);
8138 }
8139 }
8140
8141 return Just(true);
8142 }
8143
8144
FastPropertyAt(Handle<JSObject> object,Representation representation,FieldIndex index)8145 Handle<Object> JSObject::FastPropertyAt(Handle<JSObject> object,
8146 Representation representation,
8147 FieldIndex index) {
8148 Isolate* isolate = object->GetIsolate();
8149 if (object->IsUnboxedDoubleField(index)) {
8150 double value = object->RawFastDoublePropertyAt(index);
8151 return isolate->factory()->NewHeapNumber(value);
8152 }
8153 Handle<Object> raw_value(object->RawFastPropertyAt(index), isolate);
8154 return Object::WrapForRead(isolate, raw_value, representation);
8155 }
8156
8157 template <class ContextObject>
8158 class JSObjectWalkVisitor {
8159 public:
JSObjectWalkVisitor(ContextObject * site_context,bool copying,JSObject::DeepCopyHints hints)8160 JSObjectWalkVisitor(ContextObject* site_context, bool copying,
8161 JSObject::DeepCopyHints hints)
8162 : site_context_(site_context),
8163 copying_(copying),
8164 hints_(hints) {}
8165
8166 MUST_USE_RESULT MaybeHandle<JSObject> StructureWalk(Handle<JSObject> object);
8167
8168 protected:
VisitElementOrProperty(Handle<JSObject> object,Handle<JSObject> value)8169 MUST_USE_RESULT inline MaybeHandle<JSObject> VisitElementOrProperty(
8170 Handle<JSObject> object,
8171 Handle<JSObject> value) {
8172 Handle<AllocationSite> current_site = site_context()->EnterNewScope();
8173 MaybeHandle<JSObject> copy_of_value = StructureWalk(value);
8174 site_context()->ExitScope(current_site, value);
8175 return copy_of_value;
8176 }
8177
site_context()8178 inline ContextObject* site_context() { return site_context_; }
isolate()8179 inline Isolate* isolate() { return site_context()->isolate(); }
8180
copying() const8181 inline bool copying() const { return copying_; }
8182
8183 private:
8184 ContextObject* site_context_;
8185 const bool copying_;
8186 const JSObject::DeepCopyHints hints_;
8187 };
8188
8189 template <class ContextObject>
StructureWalk(Handle<JSObject> object)8190 MaybeHandle<JSObject> JSObjectWalkVisitor<ContextObject>::StructureWalk(
8191 Handle<JSObject> object) {
8192 Isolate* isolate = this->isolate();
8193 bool copying = this->copying();
8194 bool shallow = hints_ == JSObject::kObjectIsShallow;
8195
8196 if (!shallow) {
8197 StackLimitCheck check(isolate);
8198
8199 if (check.HasOverflowed()) {
8200 isolate->StackOverflow();
8201 return MaybeHandle<JSObject>();
8202 }
8203 }
8204
8205 if (object->map()->is_deprecated()) {
8206 JSObject::MigrateInstance(object);
8207 }
8208
8209 Handle<JSObject> copy;
8210 if (copying) {
8211 // JSFunction objects are not allowed to be in normal boilerplates at all.
8212 DCHECK(!object->IsJSFunction());
8213 Handle<AllocationSite> site_to_pass;
8214 if (site_context()->ShouldCreateMemento(object)) {
8215 site_to_pass = site_context()->current();
8216 }
8217 copy = isolate->factory()->CopyJSObjectWithAllocationSite(
8218 object, site_to_pass);
8219 } else {
8220 copy = object;
8221 }
8222
8223 DCHECK(copying || copy.is_identical_to(object));
8224
8225 ElementsKind kind = copy->GetElementsKind();
8226 if (copying && IsFastSmiOrObjectElementsKind(kind) &&
8227 FixedArray::cast(copy->elements())->map() ==
8228 isolate->heap()->fixed_cow_array_map()) {
8229 isolate->counters()->cow_arrays_created_runtime()->Increment();
8230 }
8231
8232 if (!shallow) {
8233 HandleScope scope(isolate);
8234
8235 // Deep copy own properties.
8236 if (copy->HasFastProperties()) {
8237 Handle<DescriptorArray> descriptors(copy->map()->instance_descriptors());
8238 int limit = copy->map()->NumberOfOwnDescriptors();
8239 for (int i = 0; i < limit; i++) {
8240 PropertyDetails details = descriptors->GetDetails(i);
8241 if (details.type() != DATA) continue;
8242 FieldIndex index = FieldIndex::ForDescriptor(copy->map(), i);
8243 if (object->IsUnboxedDoubleField(index)) {
8244 if (copying) {
8245 double value = object->RawFastDoublePropertyAt(index);
8246 copy->RawFastDoublePropertyAtPut(index, value);
8247 }
8248 } else {
8249 Handle<Object> value(object->RawFastPropertyAt(index), isolate);
8250 if (value->IsJSObject()) {
8251 ASSIGN_RETURN_ON_EXCEPTION(
8252 isolate, value,
8253 VisitElementOrProperty(copy, Handle<JSObject>::cast(value)),
8254 JSObject);
8255 if (copying) {
8256 copy->FastPropertyAtPut(index, *value);
8257 }
8258 } else {
8259 if (copying) {
8260 Representation representation = details.representation();
8261 value = Object::NewStorageFor(isolate, value, representation);
8262 copy->FastPropertyAtPut(index, *value);
8263 }
8264 }
8265 }
8266 }
8267 } else {
8268 // Only deep copy fields from the object literal expression.
8269 // In particular, don't try to copy the length attribute of
8270 // an array.
8271 PropertyFilter filter = static_cast<PropertyFilter>(
8272 ONLY_WRITABLE | ONLY_ENUMERABLE | ONLY_CONFIGURABLE);
8273 KeyAccumulator accumulator(isolate, KeyCollectionMode::kOwnOnly, filter);
8274 accumulator.CollectOwnPropertyNames(copy, copy);
8275 Handle<FixedArray> names = accumulator.GetKeys();
8276 for (int i = 0; i < names->length(); i++) {
8277 DCHECK(names->get(i)->IsName());
8278 Handle<Name> name(Name::cast(names->get(i)));
8279 Handle<Object> value =
8280 JSObject::GetProperty(copy, name).ToHandleChecked();
8281 if (value->IsJSObject()) {
8282 Handle<JSObject> result;
8283 ASSIGN_RETURN_ON_EXCEPTION(
8284 isolate, result,
8285 VisitElementOrProperty(copy, Handle<JSObject>::cast(value)),
8286 JSObject);
8287 if (copying) {
8288 // Creating object copy for literals. No strict mode needed.
8289 JSObject::SetProperty(copy, name, result, SLOPPY).Assert();
8290 }
8291 }
8292 }
8293 }
8294
8295 // Deep copy own elements.
8296 switch (kind) {
8297 case FAST_ELEMENTS:
8298 case FAST_HOLEY_ELEMENTS: {
8299 Handle<FixedArray> elements(FixedArray::cast(copy->elements()));
8300 if (elements->map() == isolate->heap()->fixed_cow_array_map()) {
8301 #ifdef DEBUG
8302 for (int i = 0; i < elements->length(); i++) {
8303 DCHECK(!elements->get(i)->IsJSObject());
8304 }
8305 #endif
8306 } else {
8307 for (int i = 0; i < elements->length(); i++) {
8308 Handle<Object> value(elements->get(i), isolate);
8309 if (value->IsJSObject()) {
8310 Handle<JSObject> result;
8311 ASSIGN_RETURN_ON_EXCEPTION(
8312 isolate, result,
8313 VisitElementOrProperty(copy, Handle<JSObject>::cast(value)),
8314 JSObject);
8315 if (copying) {
8316 elements->set(i, *result);
8317 }
8318 }
8319 }
8320 }
8321 break;
8322 }
8323 case DICTIONARY_ELEMENTS: {
8324 Handle<SeededNumberDictionary> element_dictionary(
8325 copy->element_dictionary());
8326 int capacity = element_dictionary->Capacity();
8327 for (int i = 0; i < capacity; i++) {
8328 Object* k = element_dictionary->KeyAt(i);
8329 if (element_dictionary->IsKey(isolate, k)) {
8330 Handle<Object> value(element_dictionary->ValueAt(i), isolate);
8331 if (value->IsJSObject()) {
8332 Handle<JSObject> result;
8333 ASSIGN_RETURN_ON_EXCEPTION(
8334 isolate, result,
8335 VisitElementOrProperty(copy, Handle<JSObject>::cast(value)),
8336 JSObject);
8337 if (copying) {
8338 element_dictionary->ValueAtPut(i, *result);
8339 }
8340 }
8341 }
8342 }
8343 break;
8344 }
8345 case FAST_SLOPPY_ARGUMENTS_ELEMENTS:
8346 case SLOW_SLOPPY_ARGUMENTS_ELEMENTS:
8347 UNIMPLEMENTED();
8348 break;
8349 case FAST_STRING_WRAPPER_ELEMENTS:
8350 case SLOW_STRING_WRAPPER_ELEMENTS:
8351 UNREACHABLE();
8352 break;
8353
8354 #define TYPED_ARRAY_CASE(Type, type, TYPE, ctype, size) \
8355 case TYPE##_ELEMENTS: \
8356
8357 TYPED_ARRAYS(TYPED_ARRAY_CASE)
8358 #undef TYPED_ARRAY_CASE
8359 // Typed elements cannot be created using an object literal.
8360 UNREACHABLE();
8361 break;
8362
8363 case FAST_SMI_ELEMENTS:
8364 case FAST_HOLEY_SMI_ELEMENTS:
8365 case FAST_DOUBLE_ELEMENTS:
8366 case FAST_HOLEY_DOUBLE_ELEMENTS:
8367 case NO_ELEMENTS:
8368 // No contained objects, nothing to do.
8369 break;
8370 }
8371 }
8372
8373 return copy;
8374 }
8375
8376
DeepWalk(Handle<JSObject> object,AllocationSiteCreationContext * site_context)8377 MaybeHandle<JSObject> JSObject::DeepWalk(
8378 Handle<JSObject> object,
8379 AllocationSiteCreationContext* site_context) {
8380 JSObjectWalkVisitor<AllocationSiteCreationContext> v(site_context, false,
8381 kNoHints);
8382 MaybeHandle<JSObject> result = v.StructureWalk(object);
8383 Handle<JSObject> for_assert;
8384 DCHECK(!result.ToHandle(&for_assert) || for_assert.is_identical_to(object));
8385 return result;
8386 }
8387
8388
DeepCopy(Handle<JSObject> object,AllocationSiteUsageContext * site_context,DeepCopyHints hints)8389 MaybeHandle<JSObject> JSObject::DeepCopy(
8390 Handle<JSObject> object,
8391 AllocationSiteUsageContext* site_context,
8392 DeepCopyHints hints) {
8393 JSObjectWalkVisitor<AllocationSiteUsageContext> v(site_context, true, hints);
8394 MaybeHandle<JSObject> copy = v.StructureWalk(object);
8395 Handle<JSObject> for_assert;
8396 DCHECK(!copy.ToHandle(&for_assert) || !for_assert.is_identical_to(object));
8397 return copy;
8398 }
8399
8400 // static
ToPrimitive(Handle<JSReceiver> receiver,ToPrimitiveHint hint)8401 MaybeHandle<Object> JSReceiver::ToPrimitive(Handle<JSReceiver> receiver,
8402 ToPrimitiveHint hint) {
8403 Isolate* const isolate = receiver->GetIsolate();
8404 Handle<Object> exotic_to_prim;
8405 ASSIGN_RETURN_ON_EXCEPTION(
8406 isolate, exotic_to_prim,
8407 GetMethod(receiver, isolate->factory()->to_primitive_symbol()), Object);
8408 if (!exotic_to_prim->IsUndefined(isolate)) {
8409 Handle<Object> hint_string =
8410 isolate->factory()->ToPrimitiveHintString(hint);
8411 Handle<Object> result;
8412 ASSIGN_RETURN_ON_EXCEPTION(
8413 isolate, result,
8414 Execution::Call(isolate, exotic_to_prim, receiver, 1, &hint_string),
8415 Object);
8416 if (result->IsPrimitive()) return result;
8417 THROW_NEW_ERROR(isolate,
8418 NewTypeError(MessageTemplate::kCannotConvertToPrimitive),
8419 Object);
8420 }
8421 return OrdinaryToPrimitive(receiver, (hint == ToPrimitiveHint::kString)
8422 ? OrdinaryToPrimitiveHint::kString
8423 : OrdinaryToPrimitiveHint::kNumber);
8424 }
8425
8426
8427 // static
OrdinaryToPrimitive(Handle<JSReceiver> receiver,OrdinaryToPrimitiveHint hint)8428 MaybeHandle<Object> JSReceiver::OrdinaryToPrimitive(
8429 Handle<JSReceiver> receiver, OrdinaryToPrimitiveHint hint) {
8430 Isolate* const isolate = receiver->GetIsolate();
8431 Handle<String> method_names[2];
8432 switch (hint) {
8433 case OrdinaryToPrimitiveHint::kNumber:
8434 method_names[0] = isolate->factory()->valueOf_string();
8435 method_names[1] = isolate->factory()->toString_string();
8436 break;
8437 case OrdinaryToPrimitiveHint::kString:
8438 method_names[0] = isolate->factory()->toString_string();
8439 method_names[1] = isolate->factory()->valueOf_string();
8440 break;
8441 }
8442 for (Handle<String> name : method_names) {
8443 Handle<Object> method;
8444 ASSIGN_RETURN_ON_EXCEPTION(isolate, method,
8445 JSReceiver::GetProperty(receiver, name), Object);
8446 if (method->IsCallable()) {
8447 Handle<Object> result;
8448 ASSIGN_RETURN_ON_EXCEPTION(
8449 isolate, result, Execution::Call(isolate, method, receiver, 0, NULL),
8450 Object);
8451 if (result->IsPrimitive()) return result;
8452 }
8453 }
8454 THROW_NEW_ERROR(isolate,
8455 NewTypeError(MessageTemplate::kCannotConvertToPrimitive),
8456 Object);
8457 }
8458
8459
8460 // TODO(cbruni/jkummerow): Consider moving this into elements.cc.
HasEnumerableElements()8461 bool JSObject::HasEnumerableElements() {
8462 // TODO(cbruni): cleanup
8463 JSObject* object = this;
8464 switch (object->GetElementsKind()) {
8465 case FAST_SMI_ELEMENTS:
8466 case FAST_ELEMENTS:
8467 case FAST_DOUBLE_ELEMENTS: {
8468 int length = object->IsJSArray()
8469 ? Smi::cast(JSArray::cast(object)->length())->value()
8470 : object->elements()->length();
8471 return length > 0;
8472 }
8473 case FAST_HOLEY_SMI_ELEMENTS:
8474 case FAST_HOLEY_ELEMENTS: {
8475 FixedArray* elements = FixedArray::cast(object->elements());
8476 int length = object->IsJSArray()
8477 ? Smi::cast(JSArray::cast(object)->length())->value()
8478 : elements->length();
8479 Isolate* isolate = GetIsolate();
8480 for (int i = 0; i < length; i++) {
8481 if (!elements->is_the_hole(isolate, i)) return true;
8482 }
8483 return false;
8484 }
8485 case FAST_HOLEY_DOUBLE_ELEMENTS: {
8486 int length = object->IsJSArray()
8487 ? Smi::cast(JSArray::cast(object)->length())->value()
8488 : object->elements()->length();
8489 // Zero-length arrays would use the empty FixedArray...
8490 if (length == 0) return false;
8491 // ...so only cast to FixedDoubleArray otherwise.
8492 FixedDoubleArray* elements = FixedDoubleArray::cast(object->elements());
8493 for (int i = 0; i < length; i++) {
8494 if (!elements->is_the_hole(i)) return true;
8495 }
8496 return false;
8497 }
8498 #define TYPED_ARRAY_CASE(Type, type, TYPE, ctype, size) \
8499 case TYPE##_ELEMENTS:
8500
8501 TYPED_ARRAYS(TYPED_ARRAY_CASE)
8502 #undef TYPED_ARRAY_CASE
8503 {
8504 int length = object->elements()->length();
8505 return length > 0;
8506 }
8507 case DICTIONARY_ELEMENTS: {
8508 SeededNumberDictionary* elements =
8509 SeededNumberDictionary::cast(object->elements());
8510 return elements->NumberOfElementsFilterAttributes(ONLY_ENUMERABLE) > 0;
8511 }
8512 case FAST_SLOPPY_ARGUMENTS_ELEMENTS:
8513 case SLOW_SLOPPY_ARGUMENTS_ELEMENTS:
8514 // We're approximating non-empty arguments objects here.
8515 return true;
8516 case FAST_STRING_WRAPPER_ELEMENTS:
8517 case SLOW_STRING_WRAPPER_ELEMENTS:
8518 if (String::cast(JSValue::cast(object)->value())->length() > 0) {
8519 return true;
8520 }
8521 return object->elements()->length() > 0;
8522 case NO_ELEMENTS:
8523 return false;
8524 }
8525 UNREACHABLE();
8526 return true;
8527 }
8528
8529
NumberOfDescribedProperties(DescriptorFlag which,PropertyFilter filter)8530 int Map::NumberOfDescribedProperties(DescriptorFlag which,
8531 PropertyFilter filter) {
8532 int result = 0;
8533 DescriptorArray* descs = instance_descriptors();
8534 int limit = which == ALL_DESCRIPTORS
8535 ? descs->number_of_descriptors()
8536 : NumberOfOwnDescriptors();
8537 for (int i = 0; i < limit; i++) {
8538 if ((descs->GetDetails(i).attributes() & filter) == 0 &&
8539 !descs->GetKey(i)->FilterKey(filter)) {
8540 result++;
8541 }
8542 }
8543 return result;
8544 }
8545
8546
NextFreePropertyIndex()8547 int Map::NextFreePropertyIndex() {
8548 int free_index = 0;
8549 int number_of_own_descriptors = NumberOfOwnDescriptors();
8550 DescriptorArray* descs = instance_descriptors();
8551 for (int i = 0; i < number_of_own_descriptors; i++) {
8552 PropertyDetails details = descs->GetDetails(i);
8553 if (details.location() == kField) {
8554 int candidate = details.field_index() + details.field_width_in_words();
8555 if (candidate > free_index) free_index = candidate;
8556 }
8557 }
8558 return free_index;
8559 }
8560
8561
OnlyHasSimpleProperties()8562 bool Map::OnlyHasSimpleProperties() {
8563 // Wrapped string elements aren't explicitly stored in the elements backing
8564 // store, but are loaded indirectly from the underlying string.
8565 return !IsStringWrapperElementsKind(elements_kind()) &&
8566 instance_type() > LAST_SPECIAL_RECEIVER_TYPE &&
8567 !has_hidden_prototype() && !is_dictionary_map();
8568 }
8569
FastGetOwnValuesOrEntries(Isolate * isolate,Handle<JSReceiver> receiver,bool get_entries,Handle<FixedArray> * result)8570 MUST_USE_RESULT Maybe<bool> FastGetOwnValuesOrEntries(
8571 Isolate* isolate, Handle<JSReceiver> receiver, bool get_entries,
8572 Handle<FixedArray>* result) {
8573 Handle<Map> map(JSReceiver::cast(*receiver)->map(), isolate);
8574
8575 if (!map->IsJSObjectMap()) return Just(false);
8576 if (!map->OnlyHasSimpleProperties()) return Just(false);
8577
8578 Handle<JSObject> object(JSObject::cast(*receiver));
8579
8580 Handle<DescriptorArray> descriptors(map->instance_descriptors(), isolate);
8581 int number_of_own_descriptors = map->NumberOfOwnDescriptors();
8582 int number_of_own_elements =
8583 object->GetElementsAccessor()->GetCapacity(*object, object->elements());
8584 Handle<FixedArray> values_or_entries = isolate->factory()->NewFixedArray(
8585 number_of_own_descriptors + number_of_own_elements);
8586 int count = 0;
8587
8588 if (object->elements() != isolate->heap()->empty_fixed_array()) {
8589 MAYBE_RETURN(object->GetElementsAccessor()->CollectValuesOrEntries(
8590 isolate, object, values_or_entries, get_entries, &count,
8591 ENUMERABLE_STRINGS),
8592 Nothing<bool>());
8593 }
8594
8595 bool stable = object->map() == *map;
8596
8597 for (int index = 0; index < number_of_own_descriptors; index++) {
8598 Handle<Name> next_key(descriptors->GetKey(index), isolate);
8599 if (!next_key->IsString()) continue;
8600 Handle<Object> prop_value;
8601
8602 // Directly decode from the descriptor array if |from| did not change shape.
8603 if (stable) {
8604 PropertyDetails details = descriptors->GetDetails(index);
8605 if (!details.IsEnumerable()) continue;
8606 if (details.kind() == kData) {
8607 if (details.location() == kDescriptor) {
8608 prop_value = handle(descriptors->GetValue(index), isolate);
8609 } else {
8610 Representation representation = details.representation();
8611 FieldIndex field_index = FieldIndex::ForDescriptor(*map, index);
8612 prop_value =
8613 JSObject::FastPropertyAt(object, representation, field_index);
8614 }
8615 } else {
8616 ASSIGN_RETURN_ON_EXCEPTION_VALUE(
8617 isolate, prop_value, JSReceiver::GetProperty(object, next_key),
8618 Nothing<bool>());
8619 stable = object->map() == *map;
8620 }
8621 } else {
8622 // If the map did change, do a slower lookup. We are still guaranteed that
8623 // the object has a simple shape, and that the key is a name.
8624 LookupIterator it(object, next_key, LookupIterator::OWN_SKIP_INTERCEPTOR);
8625 if (!it.IsFound()) continue;
8626 DCHECK(it.state() == LookupIterator::DATA ||
8627 it.state() == LookupIterator::ACCESSOR);
8628 if (!it.IsEnumerable()) continue;
8629 ASSIGN_RETURN_ON_EXCEPTION_VALUE(
8630 isolate, prop_value, Object::GetProperty(&it), Nothing<bool>());
8631 }
8632
8633 if (get_entries) {
8634 prop_value = MakeEntryPair(isolate, next_key, prop_value);
8635 }
8636
8637 values_or_entries->set(count, *prop_value);
8638 count++;
8639 }
8640
8641 if (count < values_or_entries->length()) values_or_entries->Shrink(count);
8642 *result = values_or_entries;
8643 return Just(true);
8644 }
8645
GetOwnValuesOrEntries(Isolate * isolate,Handle<JSReceiver> object,PropertyFilter filter,bool get_entries)8646 MaybeHandle<FixedArray> GetOwnValuesOrEntries(Isolate* isolate,
8647 Handle<JSReceiver> object,
8648 PropertyFilter filter,
8649 bool get_entries) {
8650 Handle<FixedArray> values_or_entries;
8651 if (filter == ENUMERABLE_STRINGS) {
8652 Maybe<bool> fast_values_or_entries = FastGetOwnValuesOrEntries(
8653 isolate, object, get_entries, &values_or_entries);
8654 if (fast_values_or_entries.IsNothing()) return MaybeHandle<FixedArray>();
8655 if (fast_values_or_entries.FromJust()) return values_or_entries;
8656 }
8657
8658 PropertyFilter key_filter =
8659 static_cast<PropertyFilter>(filter & ~ONLY_ENUMERABLE);
8660
8661 Handle<FixedArray> keys;
8662 ASSIGN_RETURN_ON_EXCEPTION_VALUE(
8663 isolate, keys,
8664 KeyAccumulator::GetKeys(object, KeyCollectionMode::kOwnOnly, key_filter,
8665 GetKeysConversion::kConvertToString),
8666 MaybeHandle<FixedArray>());
8667
8668 values_or_entries = isolate->factory()->NewFixedArray(keys->length());
8669 int length = 0;
8670
8671 for (int i = 0; i < keys->length(); ++i) {
8672 Handle<Name> key = Handle<Name>::cast(handle(keys->get(i), isolate));
8673
8674 if (filter & ONLY_ENUMERABLE) {
8675 PropertyDescriptor descriptor;
8676 Maybe<bool> did_get_descriptor = JSReceiver::GetOwnPropertyDescriptor(
8677 isolate, object, key, &descriptor);
8678 MAYBE_RETURN(did_get_descriptor, MaybeHandle<FixedArray>());
8679 if (!did_get_descriptor.FromJust() || !descriptor.enumerable()) continue;
8680 }
8681
8682 Handle<Object> value;
8683 ASSIGN_RETURN_ON_EXCEPTION_VALUE(
8684 isolate, value, JSReceiver::GetPropertyOrElement(object, key),
8685 MaybeHandle<FixedArray>());
8686
8687 if (get_entries) {
8688 Handle<FixedArray> entry_storage =
8689 isolate->factory()->NewUninitializedFixedArray(2);
8690 entry_storage->set(0, *key);
8691 entry_storage->set(1, *value);
8692 value = isolate->factory()->NewJSArrayWithElements(entry_storage,
8693 FAST_ELEMENTS, 2);
8694 }
8695
8696 values_or_entries->set(length, *value);
8697 length++;
8698 }
8699 if (length < values_or_entries->length()) values_or_entries->Shrink(length);
8700 return values_or_entries;
8701 }
8702
GetOwnValues(Handle<JSReceiver> object,PropertyFilter filter)8703 MaybeHandle<FixedArray> JSReceiver::GetOwnValues(Handle<JSReceiver> object,
8704 PropertyFilter filter) {
8705 return GetOwnValuesOrEntries(object->GetIsolate(), object, filter, false);
8706 }
8707
GetOwnEntries(Handle<JSReceiver> object,PropertyFilter filter)8708 MaybeHandle<FixedArray> JSReceiver::GetOwnEntries(Handle<JSReceiver> object,
8709 PropertyFilter filter) {
8710 return GetOwnValuesOrEntries(object->GetIsolate(), object, filter, true);
8711 }
8712
DictionaryElementsInPrototypeChainOnly()8713 bool Map::DictionaryElementsInPrototypeChainOnly() {
8714 if (IsDictionaryElementsKind(elements_kind())) {
8715 return false;
8716 }
8717
8718 for (PrototypeIterator iter(this); !iter.IsAtEnd(); iter.Advance()) {
8719 // Be conservative, don't walk into proxies.
8720 if (iter.GetCurrent()->IsJSProxy()) return true;
8721 // String wrappers have non-configurable, non-writable elements.
8722 if (iter.GetCurrent()->IsStringWrapper()) return true;
8723 JSObject* current = iter.GetCurrent<JSObject>();
8724
8725 if (current->HasDictionaryElements() &&
8726 current->element_dictionary()->requires_slow_elements()) {
8727 return true;
8728 }
8729
8730 if (current->HasSlowArgumentsElements()) {
8731 FixedArray* parameter_map = FixedArray::cast(current->elements());
8732 Object* arguments = parameter_map->get(1);
8733 if (SeededNumberDictionary::cast(arguments)->requires_slow_elements()) {
8734 return true;
8735 }
8736 }
8737 }
8738
8739 return false;
8740 }
8741
8742
DefineAccessor(Handle<JSObject> object,Handle<Name> name,Handle<Object> getter,Handle<Object> setter,PropertyAttributes attributes)8743 MaybeHandle<Object> JSObject::DefineAccessor(Handle<JSObject> object,
8744 Handle<Name> name,
8745 Handle<Object> getter,
8746 Handle<Object> setter,
8747 PropertyAttributes attributes) {
8748 Isolate* isolate = object->GetIsolate();
8749
8750 LookupIterator it = LookupIterator::PropertyOrElement(
8751 isolate, object, name, LookupIterator::OWN_SKIP_INTERCEPTOR);
8752 return DefineAccessor(&it, getter, setter, attributes);
8753 }
8754
8755
DefineAccessor(LookupIterator * it,Handle<Object> getter,Handle<Object> setter,PropertyAttributes attributes)8756 MaybeHandle<Object> JSObject::DefineAccessor(LookupIterator* it,
8757 Handle<Object> getter,
8758 Handle<Object> setter,
8759 PropertyAttributes attributes) {
8760 Isolate* isolate = it->isolate();
8761
8762 it->UpdateProtector();
8763
8764 if (it->state() == LookupIterator::ACCESS_CHECK) {
8765 if (!it->HasAccess()) {
8766 isolate->ReportFailedAccessCheck(it->GetHolder<JSObject>());
8767 RETURN_EXCEPTION_IF_SCHEDULED_EXCEPTION(isolate, Object);
8768 return isolate->factory()->undefined_value();
8769 }
8770 it->Next();
8771 }
8772
8773 Handle<JSObject> object = Handle<JSObject>::cast(it->GetReceiver());
8774 // Ignore accessors on typed arrays.
8775 if (it->IsElement() && object->HasFixedTypedArrayElements()) {
8776 return it->factory()->undefined_value();
8777 }
8778
8779 DCHECK(getter->IsCallable() || getter->IsUndefined(isolate) ||
8780 getter->IsNull(isolate) || getter->IsFunctionTemplateInfo());
8781 DCHECK(setter->IsCallable() || setter->IsUndefined(isolate) ||
8782 setter->IsNull(isolate) || setter->IsFunctionTemplateInfo());
8783 it->TransitionToAccessorProperty(getter, setter, attributes);
8784
8785 return isolate->factory()->undefined_value();
8786 }
8787
8788
SetAccessor(Handle<JSObject> object,Handle<AccessorInfo> info)8789 MaybeHandle<Object> JSObject::SetAccessor(Handle<JSObject> object,
8790 Handle<AccessorInfo> info) {
8791 Isolate* isolate = object->GetIsolate();
8792 Handle<Name> name(Name::cast(info->name()), isolate);
8793
8794 LookupIterator it = LookupIterator::PropertyOrElement(
8795 isolate, object, name, LookupIterator::OWN_SKIP_INTERCEPTOR);
8796
8797 // Duplicate ACCESS_CHECK outside of GetPropertyAttributes for the case that
8798 // the FailedAccessCheckCallbackFunction doesn't throw an exception.
8799 //
8800 // TODO(verwaest): Force throw an exception if the callback doesn't, so we can
8801 // remove reliance on default return values.
8802 if (it.state() == LookupIterator::ACCESS_CHECK) {
8803 if (!it.HasAccess()) {
8804 isolate->ReportFailedAccessCheck(object);
8805 RETURN_EXCEPTION_IF_SCHEDULED_EXCEPTION(isolate, Object);
8806 return it.factory()->undefined_value();
8807 }
8808 it.Next();
8809 }
8810
8811 // Ignore accessors on typed arrays.
8812 if (it.IsElement() && object->HasFixedTypedArrayElements()) {
8813 return it.factory()->undefined_value();
8814 }
8815
8816 CHECK(GetPropertyAttributes(&it).IsJust());
8817
8818 // ES5 forbids turning a property into an accessor if it's not
8819 // configurable. See 8.6.1 (Table 5).
8820 if (it.IsFound() && !it.IsConfigurable()) {
8821 return it.factory()->undefined_value();
8822 }
8823
8824 it.TransitionToAccessorPair(info, info->property_attributes());
8825
8826 return object;
8827 }
8828
SlowReverseLookup(Object * value)8829 Object* JSObject::SlowReverseLookup(Object* value) {
8830 if (HasFastProperties()) {
8831 int number_of_own_descriptors = map()->NumberOfOwnDescriptors();
8832 DescriptorArray* descs = map()->instance_descriptors();
8833 bool value_is_number = value->IsNumber();
8834 for (int i = 0; i < number_of_own_descriptors; i++) {
8835 if (descs->GetType(i) == DATA) {
8836 FieldIndex field_index = FieldIndex::ForDescriptor(map(), i);
8837 if (IsUnboxedDoubleField(field_index)) {
8838 if (value_is_number) {
8839 double property = RawFastDoublePropertyAt(field_index);
8840 if (property == value->Number()) {
8841 return descs->GetKey(i);
8842 }
8843 }
8844 } else {
8845 Object* property = RawFastPropertyAt(field_index);
8846 if (field_index.is_double()) {
8847 DCHECK(property->IsMutableHeapNumber());
8848 if (value_is_number && property->Number() == value->Number()) {
8849 return descs->GetKey(i);
8850 }
8851 } else if (property == value) {
8852 return descs->GetKey(i);
8853 }
8854 }
8855 } else if (descs->GetType(i) == DATA_CONSTANT) {
8856 if (descs->GetConstant(i) == value) {
8857 return descs->GetKey(i);
8858 }
8859 }
8860 }
8861 return GetHeap()->undefined_value();
8862 } else if (IsJSGlobalObject()) {
8863 return global_dictionary()->SlowReverseLookup(value);
8864 } else {
8865 return property_dictionary()->SlowReverseLookup(value);
8866 }
8867 }
8868
8869
RawCopy(Handle<Map> map,int instance_size)8870 Handle<Map> Map::RawCopy(Handle<Map> map, int instance_size) {
8871 Isolate* isolate = map->GetIsolate();
8872 Handle<Map> result =
8873 isolate->factory()->NewMap(map->instance_type(), instance_size);
8874 Handle<Object> prototype(map->prototype(), isolate);
8875 Map::SetPrototype(result, prototype);
8876 result->set_constructor_or_backpointer(map->GetConstructor());
8877 result->set_bit_field(map->bit_field());
8878 result->set_bit_field2(map->bit_field2());
8879 int new_bit_field3 = map->bit_field3();
8880 new_bit_field3 = OwnsDescriptors::update(new_bit_field3, true);
8881 new_bit_field3 = NumberOfOwnDescriptorsBits::update(new_bit_field3, 0);
8882 new_bit_field3 = EnumLengthBits::update(new_bit_field3,
8883 kInvalidEnumCacheSentinel);
8884 new_bit_field3 = Deprecated::update(new_bit_field3, false);
8885 if (!map->is_dictionary_map()) {
8886 new_bit_field3 = IsUnstable::update(new_bit_field3, false);
8887 }
8888 result->set_bit_field3(new_bit_field3);
8889 return result;
8890 }
8891
8892
Normalize(Handle<Map> fast_map,PropertyNormalizationMode mode,const char * reason)8893 Handle<Map> Map::Normalize(Handle<Map> fast_map, PropertyNormalizationMode mode,
8894 const char* reason) {
8895 DCHECK(!fast_map->is_dictionary_map());
8896
8897 Isolate* isolate = fast_map->GetIsolate();
8898 Handle<Object> maybe_cache(isolate->native_context()->normalized_map_cache(),
8899 isolate);
8900 bool use_cache =
8901 !fast_map->is_prototype_map() && !maybe_cache->IsUndefined(isolate);
8902 Handle<NormalizedMapCache> cache;
8903 if (use_cache) cache = Handle<NormalizedMapCache>::cast(maybe_cache);
8904
8905 Handle<Map> new_map;
8906 if (use_cache && cache->Get(fast_map, mode).ToHandle(&new_map)) {
8907 #ifdef VERIFY_HEAP
8908 if (FLAG_verify_heap) new_map->DictionaryMapVerify();
8909 #endif
8910 #ifdef ENABLE_SLOW_DCHECKS
8911 if (FLAG_enable_slow_asserts) {
8912 // The cached map should match newly created normalized map bit-by-bit,
8913 // except for the code cache, which can contain some ics which can be
8914 // applied to the shared map, dependent code and weak cell cache.
8915 Handle<Map> fresh = Map::CopyNormalized(fast_map, mode);
8916
8917 if (new_map->is_prototype_map()) {
8918 // For prototype maps, the PrototypeInfo is not copied.
8919 DCHECK(memcmp(fresh->address(), new_map->address(),
8920 kTransitionsOrPrototypeInfoOffset) == 0);
8921 DCHECK(fresh->raw_transitions() == Smi::kZero);
8922 STATIC_ASSERT(kDescriptorsOffset ==
8923 kTransitionsOrPrototypeInfoOffset + kPointerSize);
8924 DCHECK(memcmp(HeapObject::RawField(*fresh, kDescriptorsOffset),
8925 HeapObject::RawField(*new_map, kDescriptorsOffset),
8926 kCodeCacheOffset - kDescriptorsOffset) == 0);
8927 } else {
8928 DCHECK(memcmp(fresh->address(), new_map->address(),
8929 Map::kCodeCacheOffset) == 0);
8930 }
8931 STATIC_ASSERT(Map::kDependentCodeOffset ==
8932 Map::kCodeCacheOffset + kPointerSize);
8933 STATIC_ASSERT(Map::kWeakCellCacheOffset ==
8934 Map::kDependentCodeOffset + kPointerSize);
8935 int offset = Map::kWeakCellCacheOffset + kPointerSize;
8936 DCHECK(memcmp(fresh->address() + offset,
8937 new_map->address() + offset,
8938 Map::kSize - offset) == 0);
8939 }
8940 #endif
8941 } else {
8942 new_map = Map::CopyNormalized(fast_map, mode);
8943 if (use_cache) {
8944 cache->Set(fast_map, new_map);
8945 isolate->counters()->maps_normalized()->Increment();
8946 }
8947 #if TRACE_MAPS
8948 if (FLAG_trace_maps) {
8949 PrintF("[TraceMaps: Normalize from= %p to= %p reason= %s ]\n",
8950 reinterpret_cast<void*>(*fast_map),
8951 reinterpret_cast<void*>(*new_map), reason);
8952 }
8953 #endif
8954 }
8955 fast_map->NotifyLeafMapLayoutChange();
8956 return new_map;
8957 }
8958
8959
CopyNormalized(Handle<Map> map,PropertyNormalizationMode mode)8960 Handle<Map> Map::CopyNormalized(Handle<Map> map,
8961 PropertyNormalizationMode mode) {
8962 int new_instance_size = map->instance_size();
8963 if (mode == CLEAR_INOBJECT_PROPERTIES) {
8964 new_instance_size -= map->GetInObjectProperties() * kPointerSize;
8965 }
8966
8967 Handle<Map> result = RawCopy(map, new_instance_size);
8968
8969 if (mode != CLEAR_INOBJECT_PROPERTIES) {
8970 result->SetInObjectProperties(map->GetInObjectProperties());
8971 }
8972
8973 result->set_dictionary_map(true);
8974 result->set_migration_target(false);
8975 result->set_construction_counter(kNoSlackTracking);
8976
8977 #ifdef VERIFY_HEAP
8978 if (FLAG_verify_heap) result->DictionaryMapVerify();
8979 #endif
8980
8981 return result;
8982 }
8983
8984 // Return an immutable prototype exotic object version of the input map.
8985 // Never even try to cache it in the transition tree, as it is intended
8986 // for the global object and its prototype chain, and excluding it saves
8987 // memory on the map transition tree.
8988
8989 // static
TransitionToImmutableProto(Handle<Map> map)8990 Handle<Map> Map::TransitionToImmutableProto(Handle<Map> map) {
8991 Handle<Map> new_map = Map::Copy(map, "ImmutablePrototype");
8992 new_map->set_immutable_proto(true);
8993 return new_map;
8994 }
8995
CopyInitialMap(Handle<Map> map,int instance_size,int in_object_properties,int unused_property_fields)8996 Handle<Map> Map::CopyInitialMap(Handle<Map> map, int instance_size,
8997 int in_object_properties,
8998 int unused_property_fields) {
8999 #ifdef DEBUG
9000 Isolate* isolate = map->GetIsolate();
9001 // Strict function maps have Function as a constructor but the
9002 // Function's initial map is a sloppy function map. Same holds for
9003 // GeneratorFunction and its initial map.
9004 Object* constructor = map->GetConstructor();
9005 DCHECK(constructor->IsJSFunction());
9006 DCHECK(*map == JSFunction::cast(constructor)->initial_map() ||
9007 *map == *isolate->strict_function_map() ||
9008 *map == *isolate->strict_generator_function_map());
9009 #endif
9010 // Initial maps must always own their descriptors and it's descriptor array
9011 // does not contain descriptors that do not belong to the map.
9012 DCHECK(map->owns_descriptors());
9013 DCHECK_EQ(map->NumberOfOwnDescriptors(),
9014 map->instance_descriptors()->number_of_descriptors());
9015
9016 Handle<Map> result = RawCopy(map, instance_size);
9017
9018 // Please note instance_type and instance_size are set when allocated.
9019 result->SetInObjectProperties(in_object_properties);
9020 result->set_unused_property_fields(unused_property_fields);
9021
9022 int number_of_own_descriptors = map->NumberOfOwnDescriptors();
9023 if (number_of_own_descriptors > 0) {
9024 // The copy will use the same descriptors array.
9025 result->UpdateDescriptors(map->instance_descriptors(),
9026 map->GetLayoutDescriptor());
9027 result->SetNumberOfOwnDescriptors(number_of_own_descriptors);
9028
9029 DCHECK_EQ(result->NumberOfFields(),
9030 in_object_properties - unused_property_fields);
9031 }
9032
9033 return result;
9034 }
9035
9036
CopyDropDescriptors(Handle<Map> map)9037 Handle<Map> Map::CopyDropDescriptors(Handle<Map> map) {
9038 Handle<Map> result = RawCopy(map, map->instance_size());
9039
9040 // Please note instance_type and instance_size are set when allocated.
9041 if (map->IsJSObjectMap()) {
9042 result->SetInObjectProperties(map->GetInObjectProperties());
9043 result->set_unused_property_fields(map->unused_property_fields());
9044 }
9045 result->ClearCodeCache(map->GetHeap());
9046 map->NotifyLeafMapLayoutChange();
9047 return result;
9048 }
9049
9050
ShareDescriptor(Handle<Map> map,Handle<DescriptorArray> descriptors,Descriptor * descriptor)9051 Handle<Map> Map::ShareDescriptor(Handle<Map> map,
9052 Handle<DescriptorArray> descriptors,
9053 Descriptor* descriptor) {
9054 // Sanity check. This path is only to be taken if the map owns its descriptor
9055 // array, implying that its NumberOfOwnDescriptors equals the number of
9056 // descriptors in the descriptor array.
9057 DCHECK_EQ(map->NumberOfOwnDescriptors(),
9058 map->instance_descriptors()->number_of_descriptors());
9059
9060 Handle<Map> result = CopyDropDescriptors(map);
9061 Handle<Name> name = descriptor->GetKey();
9062
9063 // Ensure there's space for the new descriptor in the shared descriptor array.
9064 if (descriptors->NumberOfSlackDescriptors() == 0) {
9065 int old_size = descriptors->number_of_descriptors();
9066 if (old_size == 0) {
9067 descriptors = DescriptorArray::Allocate(map->GetIsolate(), 0, 1);
9068 } else {
9069 int slack = SlackForArraySize(old_size, kMaxNumberOfDescriptors);
9070 EnsureDescriptorSlack(map, slack);
9071 descriptors = handle(map->instance_descriptors());
9072 }
9073 }
9074
9075 Handle<LayoutDescriptor> layout_descriptor =
9076 FLAG_unbox_double_fields
9077 ? LayoutDescriptor::ShareAppend(map, descriptor->GetDetails())
9078 : handle(LayoutDescriptor::FastPointerLayout(), map->GetIsolate());
9079
9080 {
9081 DisallowHeapAllocation no_gc;
9082 descriptors->Append(descriptor);
9083 result->InitializeDescriptors(*descriptors, *layout_descriptor);
9084 }
9085
9086 DCHECK(result->NumberOfOwnDescriptors() == map->NumberOfOwnDescriptors() + 1);
9087 ConnectTransition(map, result, name, SIMPLE_PROPERTY_TRANSITION);
9088
9089 return result;
9090 }
9091
9092
9093 #if TRACE_MAPS
9094
9095 // static
TraceTransition(const char * what,Map * from,Map * to,Name * name)9096 void Map::TraceTransition(const char* what, Map* from, Map* to, Name* name) {
9097 if (FLAG_trace_maps) {
9098 PrintF("[TraceMaps: %s from= %p to= %p name= ", what,
9099 reinterpret_cast<void*>(from), reinterpret_cast<void*>(to));
9100 name->NameShortPrint();
9101 PrintF(" ]\n");
9102 }
9103 }
9104
9105
9106 // static
TraceAllTransitions(Map * map)9107 void Map::TraceAllTransitions(Map* map) {
9108 Object* transitions = map->raw_transitions();
9109 int num_transitions = TransitionArray::NumberOfTransitions(transitions);
9110 for (int i = -0; i < num_transitions; ++i) {
9111 Map* target = TransitionArray::GetTarget(transitions, i);
9112 Name* key = TransitionArray::GetKey(transitions, i);
9113 Map::TraceTransition("Transition", map, target, key);
9114 Map::TraceAllTransitions(target);
9115 }
9116 }
9117
9118 #endif // TRACE_MAPS
9119
9120
ConnectTransition(Handle<Map> parent,Handle<Map> child,Handle<Name> name,SimpleTransitionFlag flag)9121 void Map::ConnectTransition(Handle<Map> parent, Handle<Map> child,
9122 Handle<Name> name, SimpleTransitionFlag flag) {
9123 if (!parent->GetBackPointer()->IsUndefined(parent->GetIsolate())) {
9124 parent->set_owns_descriptors(false);
9125 } else {
9126 // |parent| is initial map and it must keep the ownership, there must be no
9127 // descriptors in the descriptors array that do not belong to the map.
9128 DCHECK(parent->owns_descriptors());
9129 DCHECK_EQ(parent->NumberOfOwnDescriptors(),
9130 parent->instance_descriptors()->number_of_descriptors());
9131 }
9132 if (parent->is_prototype_map()) {
9133 DCHECK(child->is_prototype_map());
9134 #if TRACE_MAPS
9135 Map::TraceTransition("NoTransition", *parent, *child, *name);
9136 #endif
9137 } else {
9138 TransitionArray::Insert(parent, name, child, flag);
9139 #if TRACE_MAPS
9140 Map::TraceTransition("Transition", *parent, *child, *name);
9141 #endif
9142 }
9143 }
9144
9145
CopyReplaceDescriptors(Handle<Map> map,Handle<DescriptorArray> descriptors,Handle<LayoutDescriptor> layout_descriptor,TransitionFlag flag,MaybeHandle<Name> maybe_name,const char * reason,SimpleTransitionFlag simple_flag)9146 Handle<Map> Map::CopyReplaceDescriptors(
9147 Handle<Map> map, Handle<DescriptorArray> descriptors,
9148 Handle<LayoutDescriptor> layout_descriptor, TransitionFlag flag,
9149 MaybeHandle<Name> maybe_name, const char* reason,
9150 SimpleTransitionFlag simple_flag) {
9151 DCHECK(descriptors->IsSortedNoDuplicates());
9152
9153 Handle<Map> result = CopyDropDescriptors(map);
9154
9155 if (!map->is_prototype_map()) {
9156 if (flag == INSERT_TRANSITION &&
9157 TransitionArray::CanHaveMoreTransitions(map)) {
9158 result->InitializeDescriptors(*descriptors, *layout_descriptor);
9159
9160 Handle<Name> name;
9161 CHECK(maybe_name.ToHandle(&name));
9162 ConnectTransition(map, result, name, simple_flag);
9163 } else {
9164 int length = descriptors->number_of_descriptors();
9165 for (int i = 0; i < length; i++) {
9166 descriptors->SetRepresentation(i, Representation::Tagged());
9167 if (descriptors->GetDetails(i).type() == DATA) {
9168 descriptors->SetValue(i, FieldType::Any());
9169 }
9170 }
9171 result->InitializeDescriptors(*descriptors,
9172 LayoutDescriptor::FastPointerLayout());
9173 }
9174 } else {
9175 result->InitializeDescriptors(*descriptors, *layout_descriptor);
9176 }
9177 #if TRACE_MAPS
9178 if (FLAG_trace_maps &&
9179 // Mirror conditions above that did not call ConnectTransition().
9180 (map->is_prototype_map() ||
9181 !(flag == INSERT_TRANSITION &&
9182 TransitionArray::CanHaveMoreTransitions(map)))) {
9183 PrintF("[TraceMaps: ReplaceDescriptors from= %p to= %p reason= %s ]\n",
9184 reinterpret_cast<void*>(*map), reinterpret_cast<void*>(*result),
9185 reason);
9186 }
9187 #endif
9188
9189 return result;
9190 }
9191
9192
9193 // Creates transition tree starting from |split_map| and adding all descriptors
9194 // starting from descriptor with index |split_map|.NumberOfOwnDescriptors().
9195 // The way how it is done is tricky because of GC and special descriptors
9196 // marking logic.
AddMissingTransitions(Handle<Map> split_map,Handle<DescriptorArray> descriptors,Handle<LayoutDescriptor> full_layout_descriptor)9197 Handle<Map> Map::AddMissingTransitions(
9198 Handle<Map> split_map, Handle<DescriptorArray> descriptors,
9199 Handle<LayoutDescriptor> full_layout_descriptor) {
9200 DCHECK(descriptors->IsSortedNoDuplicates());
9201 int split_nof = split_map->NumberOfOwnDescriptors();
9202 int nof_descriptors = descriptors->number_of_descriptors();
9203 DCHECK_LT(split_nof, nof_descriptors);
9204
9205 // Start with creating last map which will own full descriptors array.
9206 // This is necessary to guarantee that GC will mark the whole descriptor
9207 // array if any of the allocations happening below fail.
9208 // Number of unused properties is temporarily incorrect and the layout
9209 // descriptor could unnecessarily be in slow mode but we will fix after
9210 // all the other intermediate maps are created.
9211 Handle<Map> last_map = CopyDropDescriptors(split_map);
9212 last_map->InitializeDescriptors(*descriptors, *full_layout_descriptor);
9213 last_map->set_unused_property_fields(0);
9214
9215 // During creation of intermediate maps we violate descriptors sharing
9216 // invariant since the last map is not yet connected to the transition tree
9217 // we create here. But it is safe because GC never trims map's descriptors
9218 // if there are no dead transitions from that map and this is exactly the
9219 // case for all the intermediate maps we create here.
9220 Handle<Map> map = split_map;
9221 for (int i = split_nof; i < nof_descriptors - 1; ++i) {
9222 Handle<Map> new_map = CopyDropDescriptors(map);
9223 InstallDescriptors(map, new_map, i, descriptors, full_layout_descriptor);
9224 map = new_map;
9225 }
9226 map->NotifyLeafMapLayoutChange();
9227 InstallDescriptors(map, last_map, nof_descriptors - 1, descriptors,
9228 full_layout_descriptor);
9229 return last_map;
9230 }
9231
9232
9233 // Since this method is used to rewrite an existing transition tree, it can
9234 // always insert transitions without checking.
InstallDescriptors(Handle<Map> parent,Handle<Map> child,int new_descriptor,Handle<DescriptorArray> descriptors,Handle<LayoutDescriptor> full_layout_descriptor)9235 void Map::InstallDescriptors(Handle<Map> parent, Handle<Map> child,
9236 int new_descriptor,
9237 Handle<DescriptorArray> descriptors,
9238 Handle<LayoutDescriptor> full_layout_descriptor) {
9239 DCHECK(descriptors->IsSortedNoDuplicates());
9240
9241 child->set_instance_descriptors(*descriptors);
9242 child->SetNumberOfOwnDescriptors(new_descriptor + 1);
9243
9244 int unused_property_fields = parent->unused_property_fields();
9245 PropertyDetails details = descriptors->GetDetails(new_descriptor);
9246 if (details.location() == kField) {
9247 unused_property_fields = parent->unused_property_fields() - 1;
9248 if (unused_property_fields < 0) {
9249 unused_property_fields += JSObject::kFieldsAdded;
9250 }
9251 }
9252 child->set_unused_property_fields(unused_property_fields);
9253
9254 if (FLAG_unbox_double_fields) {
9255 Handle<LayoutDescriptor> layout_descriptor =
9256 LayoutDescriptor::AppendIfFastOrUseFull(parent, details,
9257 full_layout_descriptor);
9258 child->set_layout_descriptor(*layout_descriptor);
9259 #ifdef VERIFY_HEAP
9260 // TODO(ishell): remove these checks from VERIFY_HEAP mode.
9261 if (FLAG_verify_heap) {
9262 CHECK(child->layout_descriptor()->IsConsistentWithMap(*child));
9263 }
9264 #else
9265 SLOW_DCHECK(child->layout_descriptor()->IsConsistentWithMap(*child));
9266 #endif
9267 child->set_visitor_id(Heap::GetStaticVisitorIdForMap(*child));
9268 }
9269
9270 Handle<Name> name = handle(descriptors->GetKey(new_descriptor));
9271 ConnectTransition(parent, child, name, SIMPLE_PROPERTY_TRANSITION);
9272 }
9273
9274
CopyAsElementsKind(Handle<Map> map,ElementsKind kind,TransitionFlag flag)9275 Handle<Map> Map::CopyAsElementsKind(Handle<Map> map, ElementsKind kind,
9276 TransitionFlag flag) {
9277 Map* maybe_elements_transition_map = NULL;
9278 if (flag == INSERT_TRANSITION) {
9279 // Ensure we are requested to add elements kind transition "near the root".
9280 DCHECK_EQ(map->FindRootMap()->NumberOfOwnDescriptors(),
9281 map->NumberOfOwnDescriptors());
9282
9283 maybe_elements_transition_map = map->ElementsTransitionMap();
9284 DCHECK(maybe_elements_transition_map == NULL ||
9285 (maybe_elements_transition_map->elements_kind() ==
9286 DICTIONARY_ELEMENTS &&
9287 kind == DICTIONARY_ELEMENTS));
9288 DCHECK(!IsFastElementsKind(kind) ||
9289 IsMoreGeneralElementsKindTransition(map->elements_kind(), kind));
9290 DCHECK(kind != map->elements_kind());
9291 }
9292
9293 bool insert_transition = flag == INSERT_TRANSITION &&
9294 TransitionArray::CanHaveMoreTransitions(map) &&
9295 maybe_elements_transition_map == NULL;
9296
9297 if (insert_transition) {
9298 Handle<Map> new_map = CopyForTransition(map, "CopyAsElementsKind");
9299 new_map->set_elements_kind(kind);
9300
9301 Isolate* isolate = map->GetIsolate();
9302 Handle<Name> name = isolate->factory()->elements_transition_symbol();
9303 ConnectTransition(map, new_map, name, SPECIAL_TRANSITION);
9304 return new_map;
9305 }
9306
9307 // Create a new free-floating map only if we are not allowed to store it.
9308 Handle<Map> new_map = Copy(map, "CopyAsElementsKind");
9309 new_map->set_elements_kind(kind);
9310 return new_map;
9311 }
9312
9313
AsLanguageMode(Handle<Map> initial_map,LanguageMode language_mode,FunctionKind kind)9314 Handle<Map> Map::AsLanguageMode(Handle<Map> initial_map,
9315 LanguageMode language_mode, FunctionKind kind) {
9316 DCHECK_EQ(JS_FUNCTION_TYPE, initial_map->instance_type());
9317 // Initial map for sloppy mode function is stored in the function
9318 // constructor. Initial maps for strict mode are cached as special transitions
9319 // using |strict_function_transition_symbol| as a key.
9320 if (language_mode == SLOPPY) return initial_map;
9321 Isolate* isolate = initial_map->GetIsolate();
9322
9323 int map_index = Context::FunctionMapIndex(language_mode, kind);
9324 Handle<Map> function_map(
9325 Map::cast(isolate->native_context()->get(map_index)));
9326
9327 STATIC_ASSERT(LANGUAGE_END == 2);
9328 DCHECK_EQ(STRICT, language_mode);
9329 Handle<Symbol> transition_symbol =
9330 isolate->factory()->strict_function_transition_symbol();
9331 Map* maybe_transition =
9332 TransitionArray::SearchSpecial(*initial_map, *transition_symbol);
9333 if (maybe_transition != NULL) {
9334 return handle(maybe_transition, isolate);
9335 }
9336 initial_map->NotifyLeafMapLayoutChange();
9337
9338 // Create new map taking descriptors from the |function_map| and all
9339 // the other details from the |initial_map|.
9340 Handle<Map> map =
9341 Map::CopyInitialMap(function_map, initial_map->instance_size(),
9342 initial_map->GetInObjectProperties(),
9343 initial_map->unused_property_fields());
9344 map->SetConstructor(initial_map->GetConstructor());
9345 map->set_prototype(initial_map->prototype());
9346
9347 if (TransitionArray::CanHaveMoreTransitions(initial_map)) {
9348 Map::ConnectTransition(initial_map, map, transition_symbol,
9349 SPECIAL_TRANSITION);
9350 }
9351 return map;
9352 }
9353
9354
CopyForTransition(Handle<Map> map,const char * reason)9355 Handle<Map> Map::CopyForTransition(Handle<Map> map, const char* reason) {
9356 DCHECK(!map->is_prototype_map());
9357 Handle<Map> new_map = CopyDropDescriptors(map);
9358
9359 if (map->owns_descriptors()) {
9360 // In case the map owned its own descriptors, share the descriptors and
9361 // transfer ownership to the new map.
9362 // The properties did not change, so reuse descriptors.
9363 new_map->InitializeDescriptors(map->instance_descriptors(),
9364 map->GetLayoutDescriptor());
9365 } else {
9366 // In case the map did not own its own descriptors, a split is forced by
9367 // copying the map; creating a new descriptor array cell.
9368 Handle<DescriptorArray> descriptors(map->instance_descriptors());
9369 int number_of_own_descriptors = map->NumberOfOwnDescriptors();
9370 Handle<DescriptorArray> new_descriptors =
9371 DescriptorArray::CopyUpTo(descriptors, number_of_own_descriptors);
9372 Handle<LayoutDescriptor> new_layout_descriptor(map->GetLayoutDescriptor(),
9373 map->GetIsolate());
9374 new_map->InitializeDescriptors(*new_descriptors, *new_layout_descriptor);
9375 }
9376
9377 #if TRACE_MAPS
9378 if (FLAG_trace_maps) {
9379 PrintF("[TraceMaps: CopyForTransition from= %p to= %p reason= %s ]\n",
9380 reinterpret_cast<void*>(*map), reinterpret_cast<void*>(*new_map),
9381 reason);
9382 }
9383 #endif
9384
9385 return new_map;
9386 }
9387
9388
Copy(Handle<Map> map,const char * reason)9389 Handle<Map> Map::Copy(Handle<Map> map, const char* reason) {
9390 Handle<DescriptorArray> descriptors(map->instance_descriptors());
9391 int number_of_own_descriptors = map->NumberOfOwnDescriptors();
9392 Handle<DescriptorArray> new_descriptors =
9393 DescriptorArray::CopyUpTo(descriptors, number_of_own_descriptors);
9394 Handle<LayoutDescriptor> new_layout_descriptor(map->GetLayoutDescriptor(),
9395 map->GetIsolate());
9396 return CopyReplaceDescriptors(map, new_descriptors, new_layout_descriptor,
9397 OMIT_TRANSITION, MaybeHandle<Name>(), reason,
9398 SPECIAL_TRANSITION);
9399 }
9400
9401
Create(Isolate * isolate,int inobject_properties)9402 Handle<Map> Map::Create(Isolate* isolate, int inobject_properties) {
9403 Handle<Map> copy =
9404 Copy(handle(isolate->object_function()->initial_map()), "MapCreate");
9405
9406 // Check that we do not overflow the instance size when adding the extra
9407 // inobject properties. If the instance size overflows, we allocate as many
9408 // properties as we can as inobject properties.
9409 int max_extra_properties =
9410 (JSObject::kMaxInstanceSize - JSObject::kHeaderSize) >> kPointerSizeLog2;
9411
9412 if (inobject_properties > max_extra_properties) {
9413 inobject_properties = max_extra_properties;
9414 }
9415
9416 int new_instance_size =
9417 JSObject::kHeaderSize + kPointerSize * inobject_properties;
9418
9419 // Adjust the map with the extra inobject properties.
9420 copy->SetInObjectProperties(inobject_properties);
9421 copy->set_unused_property_fields(inobject_properties);
9422 copy->set_instance_size(new_instance_size);
9423 copy->set_visitor_id(Heap::GetStaticVisitorIdForMap(*copy));
9424 return copy;
9425 }
9426
9427
CopyForPreventExtensions(Handle<Map> map,PropertyAttributes attrs_to_add,Handle<Symbol> transition_marker,const char * reason)9428 Handle<Map> Map::CopyForPreventExtensions(Handle<Map> map,
9429 PropertyAttributes attrs_to_add,
9430 Handle<Symbol> transition_marker,
9431 const char* reason) {
9432 int num_descriptors = map->NumberOfOwnDescriptors();
9433 Isolate* isolate = map->GetIsolate();
9434 Handle<DescriptorArray> new_desc = DescriptorArray::CopyUpToAddAttributes(
9435 handle(map->instance_descriptors(), isolate), num_descriptors,
9436 attrs_to_add);
9437 Handle<LayoutDescriptor> new_layout_descriptor(map->GetLayoutDescriptor(),
9438 isolate);
9439 Handle<Map> new_map = CopyReplaceDescriptors(
9440 map, new_desc, new_layout_descriptor, INSERT_TRANSITION,
9441 transition_marker, reason, SPECIAL_TRANSITION);
9442 new_map->set_is_extensible(false);
9443 if (!IsFixedTypedArrayElementsKind(map->elements_kind())) {
9444 ElementsKind new_kind = IsStringWrapperElementsKind(map->elements_kind())
9445 ? SLOW_STRING_WRAPPER_ELEMENTS
9446 : DICTIONARY_ELEMENTS;
9447 new_map->set_elements_kind(new_kind);
9448 }
9449 return new_map;
9450 }
9451
GetFieldType(int descriptor_number)9452 FieldType* DescriptorArray::GetFieldType(int descriptor_number) {
9453 DCHECK(GetDetails(descriptor_number).location() == kField);
9454 Object* value = GetValue(descriptor_number);
9455 if (value->IsWeakCell()) {
9456 if (WeakCell::cast(value)->cleared()) return FieldType::None();
9457 value = WeakCell::cast(value)->value();
9458 }
9459 return FieldType::cast(value);
9460 }
9461
9462 namespace {
9463
CanHoldValue(DescriptorArray * descriptors,int descriptor,Object * value)9464 bool CanHoldValue(DescriptorArray* descriptors, int descriptor, Object* value) {
9465 PropertyDetails details = descriptors->GetDetails(descriptor);
9466 switch (details.type()) {
9467 case DATA:
9468 return value->FitsRepresentation(details.representation()) &&
9469 descriptors->GetFieldType(descriptor)->NowContains(value);
9470
9471 case DATA_CONSTANT:
9472 DCHECK(descriptors->GetConstant(descriptor) != value ||
9473 value->FitsRepresentation(details.representation()));
9474 return descriptors->GetConstant(descriptor) == value;
9475
9476 case ACCESSOR:
9477 case ACCESSOR_CONSTANT:
9478 return false;
9479 }
9480
9481 UNREACHABLE();
9482 return false;
9483 }
9484
UpdateDescriptorForValue(Handle<Map> map,int descriptor,Handle<Object> value)9485 Handle<Map> UpdateDescriptorForValue(Handle<Map> map, int descriptor,
9486 Handle<Object> value) {
9487 if (CanHoldValue(map->instance_descriptors(), descriptor, *value)) return map;
9488
9489 Isolate* isolate = map->GetIsolate();
9490 PropertyAttributes attributes =
9491 map->instance_descriptors()->GetDetails(descriptor).attributes();
9492 Representation representation = value->OptimalRepresentation();
9493 Handle<FieldType> type = value->OptimalType(isolate, representation);
9494
9495 return Map::ReconfigureProperty(map, descriptor, kData, attributes,
9496 representation, type, FORCE_FIELD);
9497 }
9498
9499 } // namespace
9500
9501 // static
PrepareForDataProperty(Handle<Map> map,int descriptor,Handle<Object> value)9502 Handle<Map> Map::PrepareForDataProperty(Handle<Map> map, int descriptor,
9503 Handle<Object> value) {
9504 // Dictionaries can store any property value.
9505 DCHECK(!map->is_dictionary_map());
9506 // Update to the newest map before storing the property.
9507 return UpdateDescriptorForValue(Update(map), descriptor, value);
9508 }
9509
9510
TransitionToDataProperty(Handle<Map> map,Handle<Name> name,Handle<Object> value,PropertyAttributes attributes,StoreFromKeyed store_mode)9511 Handle<Map> Map::TransitionToDataProperty(Handle<Map> map, Handle<Name> name,
9512 Handle<Object> value,
9513 PropertyAttributes attributes,
9514 StoreFromKeyed store_mode) {
9515 RuntimeCallTimerScope stats_scope(
9516 *map, map->is_prototype_map()
9517 ? &RuntimeCallStats::PrototypeMap_TransitionToDataProperty
9518 : &RuntimeCallStats::Map_TransitionToDataProperty);
9519
9520 DCHECK(name->IsUniqueName());
9521 DCHECK(!map->is_dictionary_map());
9522
9523 // Migrate to the newest map before storing the property.
9524 map = Update(map);
9525
9526 Map* maybe_transition =
9527 TransitionArray::SearchTransition(*map, kData, *name, attributes);
9528 if (maybe_transition != NULL) {
9529 Handle<Map> transition(maybe_transition);
9530 int descriptor = transition->LastAdded();
9531
9532 DCHECK_EQ(attributes, transition->instance_descriptors()
9533 ->GetDetails(descriptor)
9534 .attributes());
9535
9536 return UpdateDescriptorForValue(transition, descriptor, value);
9537 }
9538
9539 TransitionFlag flag = INSERT_TRANSITION;
9540 MaybeHandle<Map> maybe_map;
9541 if (value->IsJSFunction()) {
9542 maybe_map = Map::CopyWithConstant(map, name, value, attributes, flag);
9543 } else if (!map->TooManyFastProperties(store_mode)) {
9544 Isolate* isolate = name->GetIsolate();
9545 Representation representation = value->OptimalRepresentation();
9546 Handle<FieldType> type = value->OptimalType(isolate, representation);
9547 maybe_map =
9548 Map::CopyWithField(map, name, type, attributes, representation, flag);
9549 }
9550
9551 Handle<Map> result;
9552 if (!maybe_map.ToHandle(&result)) {
9553 #if TRACE_MAPS
9554 if (FLAG_trace_maps) {
9555 Vector<char> name_buffer = Vector<char>::New(100);
9556 name->NameShortPrint(name_buffer);
9557 Vector<char> buffer = Vector<char>::New(128);
9558 SNPrintF(buffer, "TooManyFastProperties %s", name_buffer.start());
9559 return Map::Normalize(map, CLEAR_INOBJECT_PROPERTIES, buffer.start());
9560 }
9561 #endif
9562 return Map::Normalize(map, CLEAR_INOBJECT_PROPERTIES,
9563 "TooManyFastProperties");
9564 }
9565
9566 return result;
9567 }
9568
9569
ReconfigureExistingProperty(Handle<Map> map,int descriptor,PropertyKind kind,PropertyAttributes attributes)9570 Handle<Map> Map::ReconfigureExistingProperty(Handle<Map> map, int descriptor,
9571 PropertyKind kind,
9572 PropertyAttributes attributes) {
9573 // Dictionaries have to be reconfigured in-place.
9574 DCHECK(!map->is_dictionary_map());
9575
9576 if (!map->GetBackPointer()->IsMap()) {
9577 // There is no benefit from reconstructing transition tree for maps without
9578 // back pointers.
9579 return CopyGeneralizeAllRepresentations(
9580 map, map->elements_kind(), descriptor, FORCE_FIELD, kind, attributes,
9581 "GenAll_AttributesMismatchProtoMap");
9582 }
9583
9584 if (FLAG_trace_generalization) {
9585 map->PrintReconfiguration(stdout, descriptor, kind, attributes);
9586 }
9587
9588 Isolate* isolate = map->GetIsolate();
9589 Handle<Map> new_map = ReconfigureProperty(
9590 map, descriptor, kind, attributes, Representation::None(),
9591 FieldType::None(isolate), FORCE_FIELD);
9592 return new_map;
9593 }
9594
TransitionToAccessorProperty(Isolate * isolate,Handle<Map> map,Handle<Name> name,int descriptor,Handle<Object> getter,Handle<Object> setter,PropertyAttributes attributes)9595 Handle<Map> Map::TransitionToAccessorProperty(Isolate* isolate, Handle<Map> map,
9596 Handle<Name> name, int descriptor,
9597 Handle<Object> getter,
9598 Handle<Object> setter,
9599 PropertyAttributes attributes) {
9600 RuntimeCallTimerScope stats_scope(
9601 isolate,
9602 map->is_prototype_map()
9603 ? &RuntimeCallStats::PrototypeMap_TransitionToAccessorProperty
9604 : &RuntimeCallStats::Map_TransitionToAccessorProperty);
9605
9606 // At least one of the accessors needs to be a new value.
9607 DCHECK(!getter->IsNull(isolate) || !setter->IsNull(isolate));
9608 DCHECK(name->IsUniqueName());
9609
9610 // Dictionary maps can always have additional data properties.
9611 if (map->is_dictionary_map()) return map;
9612
9613 // Migrate to the newest map before transitioning to the new property.
9614 map = Update(map);
9615
9616 PropertyNormalizationMode mode = map->is_prototype_map()
9617 ? KEEP_INOBJECT_PROPERTIES
9618 : CLEAR_INOBJECT_PROPERTIES;
9619
9620 Map* maybe_transition =
9621 TransitionArray::SearchTransition(*map, kAccessor, *name, attributes);
9622 if (maybe_transition != NULL) {
9623 Handle<Map> transition(maybe_transition, isolate);
9624 DescriptorArray* descriptors = transition->instance_descriptors();
9625 int descriptor = transition->LastAdded();
9626 DCHECK(descriptors->GetKey(descriptor)->Equals(*name));
9627
9628 DCHECK_EQ(kAccessor, descriptors->GetDetails(descriptor).kind());
9629 DCHECK_EQ(attributes, descriptors->GetDetails(descriptor).attributes());
9630
9631 Handle<Object> maybe_pair(descriptors->GetValue(descriptor), isolate);
9632 if (!maybe_pair->IsAccessorPair()) {
9633 return Map::Normalize(map, mode, "TransitionToAccessorFromNonPair");
9634 }
9635
9636 Handle<AccessorPair> pair = Handle<AccessorPair>::cast(maybe_pair);
9637 if (!pair->Equals(*getter, *setter)) {
9638 return Map::Normalize(map, mode, "TransitionToDifferentAccessor");
9639 }
9640
9641 return transition;
9642 }
9643
9644 Handle<AccessorPair> pair;
9645 DescriptorArray* old_descriptors = map->instance_descriptors();
9646 if (descriptor != DescriptorArray::kNotFound) {
9647 if (descriptor != map->LastAdded()) {
9648 return Map::Normalize(map, mode, "AccessorsOverwritingNonLast");
9649 }
9650 PropertyDetails old_details = old_descriptors->GetDetails(descriptor);
9651 if (old_details.type() != ACCESSOR_CONSTANT) {
9652 return Map::Normalize(map, mode, "AccessorsOverwritingNonAccessors");
9653 }
9654
9655 if (old_details.attributes() != attributes) {
9656 return Map::Normalize(map, mode, "AccessorsWithAttributes");
9657 }
9658
9659 Handle<Object> maybe_pair(old_descriptors->GetValue(descriptor), isolate);
9660 if (!maybe_pair->IsAccessorPair()) {
9661 return Map::Normalize(map, mode, "AccessorsOverwritingNonPair");
9662 }
9663
9664 Handle<AccessorPair> current_pair = Handle<AccessorPair>::cast(maybe_pair);
9665 if (current_pair->Equals(*getter, *setter)) return map;
9666
9667 bool overwriting_accessor = false;
9668 if (!getter->IsNull(isolate) &&
9669 !current_pair->get(ACCESSOR_GETTER)->IsNull(isolate) &&
9670 current_pair->get(ACCESSOR_GETTER) != *getter) {
9671 overwriting_accessor = true;
9672 }
9673 if (!setter->IsNull(isolate) &&
9674 !current_pair->get(ACCESSOR_SETTER)->IsNull(isolate) &&
9675 current_pair->get(ACCESSOR_SETTER) != *setter) {
9676 overwriting_accessor = true;
9677 }
9678 if (overwriting_accessor) {
9679 return Map::Normalize(map, mode, "AccessorsOverwritingAccessors");
9680 }
9681
9682 pair = AccessorPair::Copy(Handle<AccessorPair>::cast(maybe_pair));
9683 } else if (map->NumberOfOwnDescriptors() >= kMaxNumberOfDescriptors ||
9684 map->TooManyFastProperties(CERTAINLY_NOT_STORE_FROM_KEYED)) {
9685 return Map::Normalize(map, CLEAR_INOBJECT_PROPERTIES, "TooManyAccessors");
9686 } else {
9687 pair = isolate->factory()->NewAccessorPair();
9688 }
9689
9690 pair->SetComponents(*getter, *setter);
9691
9692 TransitionFlag flag = INSERT_TRANSITION;
9693 AccessorConstantDescriptor new_desc(name, pair, attributes);
9694 return Map::CopyInsertDescriptor(map, &new_desc, flag);
9695 }
9696
9697
CopyAddDescriptor(Handle<Map> map,Descriptor * descriptor,TransitionFlag flag)9698 Handle<Map> Map::CopyAddDescriptor(Handle<Map> map,
9699 Descriptor* descriptor,
9700 TransitionFlag flag) {
9701 Handle<DescriptorArray> descriptors(map->instance_descriptors());
9702
9703 // Share descriptors only if map owns descriptors and it not an initial map.
9704 if (flag == INSERT_TRANSITION && map->owns_descriptors() &&
9705 !map->GetBackPointer()->IsUndefined(map->GetIsolate()) &&
9706 TransitionArray::CanHaveMoreTransitions(map)) {
9707 return ShareDescriptor(map, descriptors, descriptor);
9708 }
9709
9710 int nof = map->NumberOfOwnDescriptors();
9711 Handle<DescriptorArray> new_descriptors =
9712 DescriptorArray::CopyUpTo(descriptors, nof, 1);
9713 new_descriptors->Append(descriptor);
9714
9715 Handle<LayoutDescriptor> new_layout_descriptor =
9716 FLAG_unbox_double_fields
9717 ? LayoutDescriptor::New(map, new_descriptors, nof + 1)
9718 : handle(LayoutDescriptor::FastPointerLayout(), map->GetIsolate());
9719
9720 return CopyReplaceDescriptors(map, new_descriptors, new_layout_descriptor,
9721 flag, descriptor->GetKey(), "CopyAddDescriptor",
9722 SIMPLE_PROPERTY_TRANSITION);
9723 }
9724
9725
CopyInsertDescriptor(Handle<Map> map,Descriptor * descriptor,TransitionFlag flag)9726 Handle<Map> Map::CopyInsertDescriptor(Handle<Map> map,
9727 Descriptor* descriptor,
9728 TransitionFlag flag) {
9729 Handle<DescriptorArray> old_descriptors(map->instance_descriptors());
9730
9731 // We replace the key if it is already present.
9732 int index = old_descriptors->SearchWithCache(map->GetIsolate(),
9733 *descriptor->GetKey(), *map);
9734 if (index != DescriptorArray::kNotFound) {
9735 return CopyReplaceDescriptor(map, old_descriptors, descriptor, index, flag);
9736 }
9737 return CopyAddDescriptor(map, descriptor, flag);
9738 }
9739
9740
CopyUpTo(Handle<DescriptorArray> desc,int enumeration_index,int slack)9741 Handle<DescriptorArray> DescriptorArray::CopyUpTo(
9742 Handle<DescriptorArray> desc,
9743 int enumeration_index,
9744 int slack) {
9745 return DescriptorArray::CopyUpToAddAttributes(
9746 desc, enumeration_index, NONE, slack);
9747 }
9748
9749
CopyUpToAddAttributes(Handle<DescriptorArray> desc,int enumeration_index,PropertyAttributes attributes,int slack)9750 Handle<DescriptorArray> DescriptorArray::CopyUpToAddAttributes(
9751 Handle<DescriptorArray> desc,
9752 int enumeration_index,
9753 PropertyAttributes attributes,
9754 int slack) {
9755 if (enumeration_index + slack == 0) {
9756 return desc->GetIsolate()->factory()->empty_descriptor_array();
9757 }
9758
9759 int size = enumeration_index;
9760
9761 Handle<DescriptorArray> descriptors =
9762 DescriptorArray::Allocate(desc->GetIsolate(), size, slack);
9763
9764 if (attributes != NONE) {
9765 for (int i = 0; i < size; ++i) {
9766 Object* value = desc->GetValue(i);
9767 Name* key = desc->GetKey(i);
9768 PropertyDetails details = desc->GetDetails(i);
9769 // Bulk attribute changes never affect private properties.
9770 if (!key->IsPrivate()) {
9771 int mask = DONT_DELETE | DONT_ENUM;
9772 // READ_ONLY is an invalid attribute for JS setters/getters.
9773 if (details.type() != ACCESSOR_CONSTANT || !value->IsAccessorPair()) {
9774 mask |= READ_ONLY;
9775 }
9776 details = details.CopyAddAttributes(
9777 static_cast<PropertyAttributes>(attributes & mask));
9778 }
9779 Descriptor inner_desc(
9780 handle(key), handle(value, desc->GetIsolate()), details);
9781 descriptors->SetDescriptor(i, &inner_desc);
9782 }
9783 } else {
9784 for (int i = 0; i < size; ++i) {
9785 descriptors->CopyFrom(i, *desc);
9786 }
9787 }
9788
9789 if (desc->number_of_descriptors() != enumeration_index) descriptors->Sort();
9790
9791 return descriptors;
9792 }
9793
9794
IsEqualUpTo(DescriptorArray * desc,int nof_descriptors)9795 bool DescriptorArray::IsEqualUpTo(DescriptorArray* desc, int nof_descriptors) {
9796 for (int i = 0; i < nof_descriptors; i++) {
9797 if (GetKey(i) != desc->GetKey(i) || GetValue(i) != desc->GetValue(i)) {
9798 return false;
9799 }
9800 PropertyDetails details = GetDetails(i);
9801 PropertyDetails other_details = desc->GetDetails(i);
9802 if (details.type() != other_details.type() ||
9803 !details.representation().Equals(other_details.representation())) {
9804 return false;
9805 }
9806 }
9807 return true;
9808 }
9809
9810
CopyReplaceDescriptor(Handle<Map> map,Handle<DescriptorArray> descriptors,Descriptor * descriptor,int insertion_index,TransitionFlag flag)9811 Handle<Map> Map::CopyReplaceDescriptor(Handle<Map> map,
9812 Handle<DescriptorArray> descriptors,
9813 Descriptor* descriptor,
9814 int insertion_index,
9815 TransitionFlag flag) {
9816 Handle<Name> key = descriptor->GetKey();
9817 DCHECK(*key == descriptors->GetKey(insertion_index));
9818
9819 Handle<DescriptorArray> new_descriptors = DescriptorArray::CopyUpTo(
9820 descriptors, map->NumberOfOwnDescriptors());
9821
9822 new_descriptors->Replace(insertion_index, descriptor);
9823 Handle<LayoutDescriptor> new_layout_descriptor = LayoutDescriptor::New(
9824 map, new_descriptors, new_descriptors->number_of_descriptors());
9825
9826 SimpleTransitionFlag simple_flag =
9827 (insertion_index == descriptors->number_of_descriptors() - 1)
9828 ? SIMPLE_PROPERTY_TRANSITION
9829 : PROPERTY_TRANSITION;
9830 return CopyReplaceDescriptors(map, new_descriptors, new_layout_descriptor,
9831 flag, key, "CopyReplaceDescriptor",
9832 simple_flag);
9833 }
9834
9835 // Helper class to manage a Map's code cache. The layout depends on the number
9836 // of entries; this is worthwhile because most code caches are very small,
9837 // but some are huge (thousands of entries).
9838 // For zero entries, the EmptyFixedArray is used.
9839 // For one entry, we use a 2-element FixedArray containing [name, code].
9840 // For 2..100 entries, we use a FixedArray with linear lookups, the layout is:
9841 // [0] - number of slots that are currently in use
9842 // [1] - first name
9843 // [2] - first code
9844 // [3] - second name
9845 // [4] - second code
9846 // etc.
9847 // For more than 128 entries, we use a CodeCacheHashTable.
9848 class CodeCache : public AllStatic {
9849 public:
9850 // Returns the new cache, to be stored on the map.
Put(Isolate * isolate,Handle<FixedArray> cache,Handle<Name> name,Handle<Code> code)9851 static Handle<FixedArray> Put(Isolate* isolate, Handle<FixedArray> cache,
9852 Handle<Name> name, Handle<Code> code) {
9853 int length = cache->length();
9854 if (length == 0) return PutFirstElement(isolate, name, code);
9855 if (length == kEntrySize) {
9856 return PutSecondElement(isolate, cache, name, code);
9857 }
9858 if (length <= kLinearMaxSize) {
9859 Handle<FixedArray> result = PutLinearElement(isolate, cache, name, code);
9860 if (!result.is_null()) return result;
9861 // Fall through if linear storage is getting too large.
9862 }
9863 return PutHashTableElement(isolate, cache, name, code);
9864 }
9865
Lookup(FixedArray * cache,Name * name,Code::Flags flags)9866 static Code* Lookup(FixedArray* cache, Name* name, Code::Flags flags) {
9867 int length = cache->length();
9868 if (length == 0) return nullptr;
9869 if (length == kEntrySize) return OneElementLookup(cache, name, flags);
9870 if (!cache->IsCodeCacheHashTable()) {
9871 return LinearLookup(cache, name, flags);
9872 } else {
9873 return CodeCacheHashTable::cast(cache)->Lookup(name, flags);
9874 }
9875 }
9876
9877 private:
9878 static const int kNameIndex = 0;
9879 static const int kCodeIndex = 1;
9880 static const int kEntrySize = 2;
9881
9882 static const int kLinearUsageIndex = 0;
9883 static const int kLinearReservedSlots = 1;
9884 static const int kLinearInitialCapacity = 2;
9885 static const int kLinearMaxSize = 257; // == LinearSizeFor(128);
9886
9887 static const int kHashTableInitialCapacity = 200; // Number of entries.
9888
LinearSizeFor(int entries)9889 static int LinearSizeFor(int entries) {
9890 return kLinearReservedSlots + kEntrySize * entries;
9891 }
9892
LinearNewSize(int old_size)9893 static int LinearNewSize(int old_size) {
9894 int old_entries = (old_size - kLinearReservedSlots) / kEntrySize;
9895 return LinearSizeFor(old_entries * 2);
9896 }
9897
OneElementLookup(FixedArray * cache,Name * name,Code::Flags flags)9898 static Code* OneElementLookup(FixedArray* cache, Name* name,
9899 Code::Flags flags) {
9900 DCHECK_EQ(cache->length(), kEntrySize);
9901 if (cache->get(kNameIndex) != name) return nullptr;
9902 Code* maybe_code = Code::cast(cache->get(kCodeIndex));
9903 if (maybe_code->flags() != flags) return nullptr;
9904 return maybe_code;
9905 }
9906
LinearLookup(FixedArray * cache,Name * name,Code::Flags flags)9907 static Code* LinearLookup(FixedArray* cache, Name* name, Code::Flags flags) {
9908 DCHECK_GE(cache->length(), kEntrySize);
9909 DCHECK(!cache->IsCodeCacheHashTable());
9910 int usage = GetLinearUsage(cache);
9911 for (int i = kLinearReservedSlots; i < usage; i += kEntrySize) {
9912 if (cache->get(i + kNameIndex) != name) continue;
9913 Code* code = Code::cast(cache->get(i + kCodeIndex));
9914 if (code->flags() == flags) return code;
9915 }
9916 return nullptr;
9917 }
9918
PutFirstElement(Isolate * isolate,Handle<Name> name,Handle<Code> code)9919 static Handle<FixedArray> PutFirstElement(Isolate* isolate, Handle<Name> name,
9920 Handle<Code> code) {
9921 Handle<FixedArray> cache = isolate->factory()->NewFixedArray(kEntrySize);
9922 cache->set(kNameIndex, *name);
9923 cache->set(kCodeIndex, *code);
9924 return cache;
9925 }
9926
PutSecondElement(Isolate * isolate,Handle<FixedArray> cache,Handle<Name> name,Handle<Code> code)9927 static Handle<FixedArray> PutSecondElement(Isolate* isolate,
9928 Handle<FixedArray> cache,
9929 Handle<Name> name,
9930 Handle<Code> code) {
9931 DCHECK_EQ(cache->length(), kEntrySize);
9932 Handle<FixedArray> new_cache = isolate->factory()->NewFixedArray(
9933 LinearSizeFor(kLinearInitialCapacity));
9934 new_cache->set(kLinearReservedSlots + kNameIndex, cache->get(kNameIndex));
9935 new_cache->set(kLinearReservedSlots + kCodeIndex, cache->get(kCodeIndex));
9936 new_cache->set(LinearSizeFor(1) + kNameIndex, *name);
9937 new_cache->set(LinearSizeFor(1) + kCodeIndex, *code);
9938 new_cache->set(kLinearUsageIndex, Smi::FromInt(LinearSizeFor(2)));
9939 return new_cache;
9940 }
9941
PutLinearElement(Isolate * isolate,Handle<FixedArray> cache,Handle<Name> name,Handle<Code> code)9942 static Handle<FixedArray> PutLinearElement(Isolate* isolate,
9943 Handle<FixedArray> cache,
9944 Handle<Name> name,
9945 Handle<Code> code) {
9946 int length = cache->length();
9947 int usage = GetLinearUsage(*cache);
9948 DCHECK_LE(usage, length);
9949 // Check if we need to grow.
9950 if (usage == length) {
9951 int new_length = LinearNewSize(length);
9952 if (new_length > kLinearMaxSize) return Handle<FixedArray>::null();
9953 Handle<FixedArray> new_cache =
9954 isolate->factory()->NewFixedArray(new_length);
9955 for (int i = kLinearReservedSlots; i < length; i++) {
9956 new_cache->set(i, cache->get(i));
9957 }
9958 cache = new_cache;
9959 }
9960 // Store new entry.
9961 DCHECK_GE(cache->length(), usage + kEntrySize);
9962 cache->set(usage + kNameIndex, *name);
9963 cache->set(usage + kCodeIndex, *code);
9964 cache->set(kLinearUsageIndex, Smi::FromInt(usage + kEntrySize));
9965 return cache;
9966 }
9967
PutHashTableElement(Isolate * isolate,Handle<FixedArray> cache,Handle<Name> name,Handle<Code> code)9968 static Handle<FixedArray> PutHashTableElement(Isolate* isolate,
9969 Handle<FixedArray> cache,
9970 Handle<Name> name,
9971 Handle<Code> code) {
9972 // Check if we need to transition from linear to hash table storage.
9973 if (!cache->IsCodeCacheHashTable()) {
9974 // Check that the initial hash table capacity is large enough.
9975 DCHECK_EQ(kLinearMaxSize, LinearSizeFor(128));
9976 STATIC_ASSERT(kHashTableInitialCapacity > 128);
9977
9978 int length = cache->length();
9979 // Only migrate from linear storage when it's full.
9980 DCHECK_EQ(length, GetLinearUsage(*cache));
9981 DCHECK_EQ(length, kLinearMaxSize);
9982 Handle<CodeCacheHashTable> table =
9983 CodeCacheHashTable::New(isolate, kHashTableInitialCapacity);
9984 HandleScope scope(isolate);
9985 for (int i = kLinearReservedSlots; i < length; i += kEntrySize) {
9986 Handle<Name> old_name(Name::cast(cache->get(i + kNameIndex)), isolate);
9987 Handle<Code> old_code(Code::cast(cache->get(i + kCodeIndex)), isolate);
9988 CodeCacheHashTable::Put(table, old_name, old_code);
9989 }
9990 cache = table;
9991 }
9992 // Store new entry.
9993 DCHECK(cache->IsCodeCacheHashTable());
9994 return CodeCacheHashTable::Put(Handle<CodeCacheHashTable>::cast(cache),
9995 name, code);
9996 }
9997
GetLinearUsage(FixedArray * linear_cache)9998 static inline int GetLinearUsage(FixedArray* linear_cache) {
9999 DCHECK_GT(linear_cache->length(), kEntrySize);
10000 return Smi::cast(linear_cache->get(kLinearUsageIndex))->value();
10001 }
10002 };
10003
UpdateCodeCache(Handle<Map> map,Handle<Name> name,Handle<Code> code)10004 void Map::UpdateCodeCache(Handle<Map> map,
10005 Handle<Name> name,
10006 Handle<Code> code) {
10007 Isolate* isolate = map->GetIsolate();
10008 Handle<FixedArray> cache(map->code_cache(), isolate);
10009 Handle<FixedArray> new_cache = CodeCache::Put(isolate, cache, name, code);
10010 map->set_code_cache(*new_cache);
10011 }
10012
LookupInCodeCache(Name * name,Code::Flags flags)10013 Code* Map::LookupInCodeCache(Name* name, Code::Flags flags) {
10014 return CodeCache::Lookup(code_cache(), name, flags);
10015 }
10016
10017
10018 // The key in the code cache hash table consists of the property name and the
10019 // code object. The actual match is on the name and the code flags. If a key
10020 // is created using the flags and not a code object it can only be used for
10021 // lookup not to create a new entry.
10022 class CodeCacheHashTableKey : public HashTableKey {
10023 public:
CodeCacheHashTableKey(Handle<Name> name,Code::Flags flags)10024 CodeCacheHashTableKey(Handle<Name> name, Code::Flags flags)
10025 : name_(name), flags_(flags), code_() {
10026 DCHECK(name_->IsUniqueName());
10027 }
10028
CodeCacheHashTableKey(Handle<Name> name,Handle<Code> code)10029 CodeCacheHashTableKey(Handle<Name> name, Handle<Code> code)
10030 : name_(name), flags_(code->flags()), code_(code) {
10031 DCHECK(name_->IsUniqueName());
10032 }
10033
IsMatch(Object * other)10034 bool IsMatch(Object* other) override {
10035 DCHECK(other->IsFixedArray());
10036 FixedArray* pair = FixedArray::cast(other);
10037 Name* name = Name::cast(pair->get(0));
10038 Code::Flags flags = Code::cast(pair->get(1))->flags();
10039 if (flags != flags_) return false;
10040 DCHECK(name->IsUniqueName());
10041 return *name_ == name;
10042 }
10043
NameFlagsHashHelper(Name * name,Code::Flags flags)10044 static uint32_t NameFlagsHashHelper(Name* name, Code::Flags flags) {
10045 return name->Hash() ^ flags;
10046 }
10047
Hash()10048 uint32_t Hash() override { return NameFlagsHashHelper(*name_, flags_); }
10049
HashForObject(Object * obj)10050 uint32_t HashForObject(Object* obj) override {
10051 FixedArray* pair = FixedArray::cast(obj);
10052 Name* name = Name::cast(pair->get(0));
10053 Code* code = Code::cast(pair->get(1));
10054 return NameFlagsHashHelper(name, code->flags());
10055 }
10056
AsHandle(Isolate * isolate)10057 MUST_USE_RESULT Handle<Object> AsHandle(Isolate* isolate) override {
10058 Handle<Code> code = code_.ToHandleChecked();
10059 Handle<FixedArray> pair = isolate->factory()->NewFixedArray(2);
10060 pair->set(0, *name_);
10061 pair->set(1, *code);
10062 return pair;
10063 }
10064
10065 private:
10066 Handle<Name> name_;
10067 Code::Flags flags_;
10068 // TODO(jkummerow): We should be able to get by without this.
10069 MaybeHandle<Code> code_;
10070 };
10071
10072
Put(Handle<CodeCacheHashTable> cache,Handle<Name> name,Handle<Code> code)10073 Handle<CodeCacheHashTable> CodeCacheHashTable::Put(
10074 Handle<CodeCacheHashTable> cache, Handle<Name> name, Handle<Code> code) {
10075 CodeCacheHashTableKey key(name, code);
10076
10077 Handle<CodeCacheHashTable> new_cache = EnsureCapacity(cache, 1, &key);
10078
10079 int entry = new_cache->FindInsertionEntry(key.Hash());
10080 Handle<Object> k = key.AsHandle(cache->GetIsolate());
10081
10082 new_cache->set(EntryToIndex(entry), *k);
10083 new_cache->ElementAdded();
10084 return new_cache;
10085 }
10086
Lookup(Name * name,Code::Flags flags)10087 Code* CodeCacheHashTable::Lookup(Name* name, Code::Flags flags) {
10088 DisallowHeapAllocation no_alloc;
10089 CodeCacheHashTableKey key(handle(name), flags);
10090 int entry = FindEntry(&key);
10091 if (entry == kNotFound) return nullptr;
10092 return Code::cast(FixedArray::cast(get(EntryToIndex(entry)))->get(1));
10093 }
10094
SetAndGrow(Handle<FixedArray> array,int index,Handle<Object> value)10095 Handle<FixedArray> FixedArray::SetAndGrow(Handle<FixedArray> array, int index,
10096 Handle<Object> value) {
10097 if (index < array->length()) {
10098 array->set(index, *value);
10099 return array;
10100 }
10101 int capacity = array->length();
10102 do {
10103 capacity = JSObject::NewElementsCapacity(capacity);
10104 } while (capacity <= index);
10105 Handle<FixedArray> new_array =
10106 array->GetIsolate()->factory()->NewUninitializedFixedArray(capacity);
10107 array->CopyTo(0, *new_array, 0, array->length());
10108 new_array->FillWithHoles(array->length(), new_array->length());
10109 new_array->set(index, *value);
10110 return new_array;
10111 }
10112
Shrink(int new_length)10113 void FixedArray::Shrink(int new_length) {
10114 DCHECK(0 <= new_length && new_length <= length());
10115 if (new_length < length()) {
10116 GetHeap()->RightTrimFixedArray<Heap::CONCURRENT_TO_SWEEPER>(
10117 this, length() - new_length);
10118 }
10119 }
10120
10121
CopyTo(int pos,FixedArray * dest,int dest_pos,int len)10122 void FixedArray::CopyTo(int pos, FixedArray* dest, int dest_pos, int len) {
10123 DisallowHeapAllocation no_gc;
10124 WriteBarrierMode mode = dest->GetWriteBarrierMode(no_gc);
10125 for (int index = 0; index < len; index++) {
10126 dest->set(dest_pos+index, get(pos+index), mode);
10127 }
10128 }
10129
10130
10131 #ifdef DEBUG
IsEqualTo(FixedArray * other)10132 bool FixedArray::IsEqualTo(FixedArray* other) {
10133 if (length() != other->length()) return false;
10134 for (int i = 0 ; i < length(); ++i) {
10135 if (get(i) != other->get(i)) return false;
10136 }
10137 return true;
10138 }
10139 #endif
10140
10141
10142 // static
Set(Handle<WeakFixedArray> array,int index,Handle<HeapObject> value)10143 void WeakFixedArray::Set(Handle<WeakFixedArray> array, int index,
10144 Handle<HeapObject> value) {
10145 DCHECK(array->IsEmptySlot(index)); // Don't overwrite anything.
10146 Handle<WeakCell> cell =
10147 value->IsMap() ? Map::WeakCellForMap(Handle<Map>::cast(value))
10148 : array->GetIsolate()->factory()->NewWeakCell(value);
10149 Handle<FixedArray>::cast(array)->set(index + kFirstIndex, *cell);
10150 if (FLAG_trace_weak_arrays) {
10151 PrintF("[WeakFixedArray: storing at index %d ]\n", index);
10152 }
10153 array->set_last_used_index(index);
10154 }
10155
10156
10157 // static
Add(Handle<Object> maybe_array,Handle<HeapObject> value,int * assigned_index)10158 Handle<WeakFixedArray> WeakFixedArray::Add(Handle<Object> maybe_array,
10159 Handle<HeapObject> value,
10160 int* assigned_index) {
10161 Handle<WeakFixedArray> array =
10162 (maybe_array.is_null() || !maybe_array->IsWeakFixedArray())
10163 ? Allocate(value->GetIsolate(), 1, Handle<WeakFixedArray>::null())
10164 : Handle<WeakFixedArray>::cast(maybe_array);
10165 // Try to store the new entry if there's room. Optimize for consecutive
10166 // accesses.
10167 int first_index = array->last_used_index();
10168 int length = array->Length();
10169 if (length > 0) {
10170 for (int i = first_index;;) {
10171 if (array->IsEmptySlot((i))) {
10172 WeakFixedArray::Set(array, i, value);
10173 if (assigned_index != NULL) *assigned_index = i;
10174 return array;
10175 }
10176 if (FLAG_trace_weak_arrays) {
10177 PrintF("[WeakFixedArray: searching for free slot]\n");
10178 }
10179 i = (i + 1) % length;
10180 if (i == first_index) break;
10181 }
10182 }
10183
10184 // No usable slot found, grow the array.
10185 int new_length = length == 0 ? 1 : length + (length >> 1) + 4;
10186 Handle<WeakFixedArray> new_array =
10187 Allocate(array->GetIsolate(), new_length, array);
10188 if (FLAG_trace_weak_arrays) {
10189 PrintF("[WeakFixedArray: growing to size %d ]\n", new_length);
10190 }
10191 WeakFixedArray::Set(new_array, length, value);
10192 if (assigned_index != NULL) *assigned_index = length;
10193 return new_array;
10194 }
10195
10196
10197 template <class CompactionCallback>
Compact()10198 void WeakFixedArray::Compact() {
10199 FixedArray* array = FixedArray::cast(this);
10200 int new_length = kFirstIndex;
10201 for (int i = kFirstIndex; i < array->length(); i++) {
10202 Object* element = array->get(i);
10203 if (element->IsSmi()) continue;
10204 if (WeakCell::cast(element)->cleared()) continue;
10205 Object* value = WeakCell::cast(element)->value();
10206 CompactionCallback::Callback(value, i - kFirstIndex,
10207 new_length - kFirstIndex);
10208 array->set(new_length++, element);
10209 }
10210 array->Shrink(new_length);
10211 set_last_used_index(0);
10212 }
10213
10214
Reset(Object * maybe_array)10215 void WeakFixedArray::Iterator::Reset(Object* maybe_array) {
10216 if (maybe_array->IsWeakFixedArray()) {
10217 list_ = WeakFixedArray::cast(maybe_array);
10218 index_ = 0;
10219 #ifdef DEBUG
10220 last_used_index_ = list_->last_used_index();
10221 #endif // DEBUG
10222 }
10223 }
10224
10225
Callback(Object * value,int old_index,int new_index)10226 void JSObject::PrototypeRegistryCompactionCallback::Callback(Object* value,
10227 int old_index,
10228 int new_index) {
10229 DCHECK(value->IsMap() && Map::cast(value)->is_prototype_map());
10230 Map* map = Map::cast(value);
10231 DCHECK(map->prototype_info()->IsPrototypeInfo());
10232 PrototypeInfo* proto_info = PrototypeInfo::cast(map->prototype_info());
10233 DCHECK_EQ(old_index, proto_info->registry_slot());
10234 proto_info->set_registry_slot(new_index);
10235 }
10236
10237
10238 template void WeakFixedArray::Compact<WeakFixedArray::NullCallback>();
10239 template void
10240 WeakFixedArray::Compact<JSObject::PrototypeRegistryCompactionCallback>();
10241
10242
Remove(Handle<HeapObject> value)10243 bool WeakFixedArray::Remove(Handle<HeapObject> value) {
10244 if (Length() == 0) return false;
10245 // Optimize for the most recently added element to be removed again.
10246 int first_index = last_used_index();
10247 for (int i = first_index;;) {
10248 if (Get(i) == *value) {
10249 Clear(i);
10250 // Users of WeakFixedArray should make sure that there are no duplicates.
10251 return true;
10252 }
10253 i = (i + 1) % Length();
10254 if (i == first_index) return false;
10255 }
10256 UNREACHABLE();
10257 }
10258
10259
10260 // static
Allocate(Isolate * isolate,int size,Handle<WeakFixedArray> initialize_from)10261 Handle<WeakFixedArray> WeakFixedArray::Allocate(
10262 Isolate* isolate, int size, Handle<WeakFixedArray> initialize_from) {
10263 DCHECK(0 <= size);
10264 Handle<FixedArray> result =
10265 isolate->factory()->NewUninitializedFixedArray(size + kFirstIndex);
10266 int index = 0;
10267 if (!initialize_from.is_null()) {
10268 DCHECK(initialize_from->Length() <= size);
10269 Handle<FixedArray> raw_source = Handle<FixedArray>::cast(initialize_from);
10270 // Copy the entries without compacting, since the PrototypeInfo relies on
10271 // the index of the entries not to change.
10272 while (index < raw_source->length()) {
10273 result->set(index, raw_source->get(index));
10274 index++;
10275 }
10276 }
10277 while (index < result->length()) {
10278 result->set(index, Smi::kZero);
10279 index++;
10280 }
10281 return Handle<WeakFixedArray>::cast(result);
10282 }
10283
10284
Add(Handle<ArrayList> array,Handle<Object> obj,AddMode mode)10285 Handle<ArrayList> ArrayList::Add(Handle<ArrayList> array, Handle<Object> obj,
10286 AddMode mode) {
10287 int length = array->Length();
10288 array = EnsureSpace(array, length + 1);
10289 if (mode == kReloadLengthAfterAllocation) {
10290 DCHECK(array->Length() <= length);
10291 length = array->Length();
10292 }
10293 array->Set(length, *obj);
10294 array->SetLength(length + 1);
10295 return array;
10296 }
10297
Add(Handle<ArrayList> array,Handle<Object> obj1,Handle<Object> obj2,AddMode mode)10298 Handle<ArrayList> ArrayList::Add(Handle<ArrayList> array, Handle<Object> obj1,
10299 Handle<Object> obj2, AddMode mode) {
10300 int length = array->Length();
10301 array = EnsureSpace(array, length + 2);
10302 if (mode == kReloadLengthAfterAllocation) {
10303 length = array->Length();
10304 }
10305 array->Set(length, *obj1);
10306 array->Set(length + 1, *obj2);
10307 array->SetLength(length + 2);
10308 return array;
10309 }
10310
10311
IsFull()10312 bool ArrayList::IsFull() {
10313 int capacity = length();
10314 return kFirstIndex + Length() == capacity;
10315 }
10316
10317 namespace {
10318
EnsureSpaceInFixedArray(Handle<FixedArray> array,int length)10319 Handle<FixedArray> EnsureSpaceInFixedArray(Handle<FixedArray> array,
10320 int length) {
10321 int capacity = array->length();
10322 if (capacity < length) {
10323 Isolate* isolate = array->GetIsolate();
10324 int new_capacity = length;
10325 new_capacity = new_capacity + Max(new_capacity / 2, 2);
10326 int grow_by = new_capacity - capacity;
10327 array = Handle<ArrayList>::cast(
10328 isolate->factory()->CopyFixedArrayAndGrow(array, grow_by));
10329 }
10330 return array;
10331 }
10332
10333 } // namespace
10334
EnsureSpace(Handle<ArrayList> array,int length)10335 Handle<ArrayList> ArrayList::EnsureSpace(Handle<ArrayList> array, int length) {
10336 const bool empty = (array->length() == 0);
10337 auto ret = Handle<ArrayList>::cast(
10338 EnsureSpaceInFixedArray(array, kFirstIndex + length));
10339 if (empty) ret->SetLength(0);
10340 return ret;
10341 }
10342
ReserveCaptures(Handle<RegExpMatchInfo> match_info,int capture_count)10343 Handle<RegExpMatchInfo> RegExpMatchInfo::ReserveCaptures(
10344 Handle<RegExpMatchInfo> match_info, int capture_count) {
10345 DCHECK_GE(match_info->length(), kLastMatchOverhead);
10346 const int required_length = kFirstCaptureIndex + capture_count;
10347 Handle<FixedArray> result =
10348 EnsureSpaceInFixedArray(match_info, required_length);
10349 return Handle<RegExpMatchInfo>::cast(result);
10350 }
10351
10352 // static
AppendJSFrame(Handle<FrameArray> in,Handle<Object> receiver,Handle<JSFunction> function,Handle<AbstractCode> code,int offset,int flags)10353 Handle<FrameArray> FrameArray::AppendJSFrame(Handle<FrameArray> in,
10354 Handle<Object> receiver,
10355 Handle<JSFunction> function,
10356 Handle<AbstractCode> code,
10357 int offset, int flags) {
10358 const int frame_count = in->FrameCount();
10359 const int new_length = LengthFor(frame_count + 1);
10360 Handle<FrameArray> array = EnsureSpace(in, new_length);
10361 array->SetReceiver(frame_count, *receiver);
10362 array->SetFunction(frame_count, *function);
10363 array->SetCode(frame_count, *code);
10364 array->SetOffset(frame_count, Smi::FromInt(offset));
10365 array->SetFlags(frame_count, Smi::FromInt(flags));
10366 array->set(kFrameCountIndex, Smi::FromInt(frame_count + 1));
10367 return array;
10368 }
10369
10370 // static
AppendWasmFrame(Handle<FrameArray> in,Handle<Object> wasm_instance,int wasm_function_index,Handle<AbstractCode> code,int offset,int flags)10371 Handle<FrameArray> FrameArray::AppendWasmFrame(Handle<FrameArray> in,
10372 Handle<Object> wasm_instance,
10373 int wasm_function_index,
10374 Handle<AbstractCode> code,
10375 int offset, int flags) {
10376 const int frame_count = in->FrameCount();
10377 const int new_length = LengthFor(frame_count + 1);
10378 Handle<FrameArray> array = EnsureSpace(in, new_length);
10379 array->SetWasmInstance(frame_count, *wasm_instance);
10380 array->SetWasmFunctionIndex(frame_count, Smi::FromInt(wasm_function_index));
10381 array->SetCode(frame_count, *code);
10382 array->SetOffset(frame_count, Smi::FromInt(offset));
10383 array->SetFlags(frame_count, Smi::FromInt(flags));
10384 array->set(kFrameCountIndex, Smi::FromInt(frame_count + 1));
10385 return array;
10386 }
10387
ShrinkToFit()10388 void FrameArray::ShrinkToFit() { Shrink(LengthFor(FrameCount())); }
10389
10390 // static
EnsureSpace(Handle<FrameArray> array,int length)10391 Handle<FrameArray> FrameArray::EnsureSpace(Handle<FrameArray> array,
10392 int length) {
10393 return Handle<FrameArray>::cast(EnsureSpaceInFixedArray(array, length));
10394 }
10395
Allocate(Isolate * isolate,int number_of_descriptors,int slack,PretenureFlag pretenure)10396 Handle<DescriptorArray> DescriptorArray::Allocate(Isolate* isolate,
10397 int number_of_descriptors,
10398 int slack,
10399 PretenureFlag pretenure) {
10400 DCHECK(0 <= number_of_descriptors);
10401 Factory* factory = isolate->factory();
10402 // Do not use DescriptorArray::cast on incomplete object.
10403 int size = number_of_descriptors + slack;
10404 if (size == 0) return factory->empty_descriptor_array();
10405 // Allocate the array of keys.
10406 Handle<FixedArray> result =
10407 factory->NewFixedArray(LengthFor(size), pretenure);
10408
10409 result->set(kDescriptorLengthIndex, Smi::FromInt(number_of_descriptors));
10410 result->set(kEnumCacheIndex, Smi::kZero);
10411 return Handle<DescriptorArray>::cast(result);
10412 }
10413
ClearEnumCache()10414 void DescriptorArray::ClearEnumCache() { set(kEnumCacheIndex, Smi::kZero); }
10415
Replace(int index,Descriptor * descriptor)10416 void DescriptorArray::Replace(int index, Descriptor* descriptor) {
10417 descriptor->SetSortedKeyIndex(GetSortedKeyIndex(index));
10418 Set(index, descriptor);
10419 }
10420
10421
10422 // static
SetEnumCache(Handle<DescriptorArray> descriptors,Isolate * isolate,Handle<FixedArray> new_cache,Handle<FixedArray> new_index_cache)10423 void DescriptorArray::SetEnumCache(Handle<DescriptorArray> descriptors,
10424 Isolate* isolate,
10425 Handle<FixedArray> new_cache,
10426 Handle<FixedArray> new_index_cache) {
10427 DCHECK(!descriptors->IsEmpty());
10428 FixedArray* bridge_storage;
10429 bool needs_new_enum_cache = !descriptors->HasEnumCache();
10430 if (needs_new_enum_cache) {
10431 bridge_storage = *isolate->factory()->NewFixedArray(
10432 DescriptorArray::kEnumCacheBridgeLength);
10433 } else {
10434 bridge_storage = FixedArray::cast(descriptors->get(kEnumCacheIndex));
10435 }
10436 bridge_storage->set(kEnumCacheBridgeCacheIndex, *new_cache);
10437 bridge_storage->set(
10438 kEnumCacheBridgeIndicesCacheIndex,
10439 new_index_cache.is_null() ? Object::cast(Smi::kZero) : *new_index_cache);
10440 if (needs_new_enum_cache) {
10441 descriptors->set(kEnumCacheIndex, bridge_storage);
10442 }
10443 }
10444
10445
CopyFrom(int index,DescriptorArray * src)10446 void DescriptorArray::CopyFrom(int index, DescriptorArray* src) {
10447 Object* value = src->GetValue(index);
10448 PropertyDetails details = src->GetDetails(index);
10449 Descriptor desc(handle(src->GetKey(index)),
10450 handle(value, src->GetIsolate()),
10451 details);
10452 SetDescriptor(index, &desc);
10453 }
10454
10455
Sort()10456 void DescriptorArray::Sort() {
10457 // In-place heap sort.
10458 int len = number_of_descriptors();
10459 // Reset sorting since the descriptor array might contain invalid pointers.
10460 for (int i = 0; i < len; ++i) SetSortedKey(i, i);
10461 // Bottom-up max-heap construction.
10462 // Index of the last node with children
10463 const int max_parent_index = (len / 2) - 1;
10464 for (int i = max_parent_index; i >= 0; --i) {
10465 int parent_index = i;
10466 const uint32_t parent_hash = GetSortedKey(i)->Hash();
10467 while (parent_index <= max_parent_index) {
10468 int child_index = 2 * parent_index + 1;
10469 uint32_t child_hash = GetSortedKey(child_index)->Hash();
10470 if (child_index + 1 < len) {
10471 uint32_t right_child_hash = GetSortedKey(child_index + 1)->Hash();
10472 if (right_child_hash > child_hash) {
10473 child_index++;
10474 child_hash = right_child_hash;
10475 }
10476 }
10477 if (child_hash <= parent_hash) break;
10478 SwapSortedKeys(parent_index, child_index);
10479 // Now element at child_index could be < its children.
10480 parent_index = child_index; // parent_hash remains correct.
10481 }
10482 }
10483
10484 // Extract elements and create sorted array.
10485 for (int i = len - 1; i > 0; --i) {
10486 // Put max element at the back of the array.
10487 SwapSortedKeys(0, i);
10488 // Shift down the new top element.
10489 int parent_index = 0;
10490 const uint32_t parent_hash = GetSortedKey(parent_index)->Hash();
10491 const int max_parent_index = (i / 2) - 1;
10492 while (parent_index <= max_parent_index) {
10493 int child_index = parent_index * 2 + 1;
10494 uint32_t child_hash = GetSortedKey(child_index)->Hash();
10495 if (child_index + 1 < i) {
10496 uint32_t right_child_hash = GetSortedKey(child_index + 1)->Hash();
10497 if (right_child_hash > child_hash) {
10498 child_index++;
10499 child_hash = right_child_hash;
10500 }
10501 }
10502 if (child_hash <= parent_hash) break;
10503 SwapSortedKeys(parent_index, child_index);
10504 parent_index = child_index;
10505 }
10506 }
10507 DCHECK(IsSortedNoDuplicates());
10508 }
10509
10510
Copy(Handle<AccessorPair> pair)10511 Handle<AccessorPair> AccessorPair::Copy(Handle<AccessorPair> pair) {
10512 Handle<AccessorPair> copy = pair->GetIsolate()->factory()->NewAccessorPair();
10513 copy->set_getter(pair->getter());
10514 copy->set_setter(pair->setter());
10515 return copy;
10516 }
10517
GetComponent(Handle<AccessorPair> accessor_pair,AccessorComponent component)10518 Handle<Object> AccessorPair::GetComponent(Handle<AccessorPair> accessor_pair,
10519 AccessorComponent component) {
10520 Object* accessor = accessor_pair->get(component);
10521 if (accessor->IsFunctionTemplateInfo()) {
10522 return ApiNatives::InstantiateFunction(
10523 handle(FunctionTemplateInfo::cast(accessor)))
10524 .ToHandleChecked();
10525 }
10526 Isolate* isolate = accessor_pair->GetIsolate();
10527 if (accessor->IsNull(isolate)) {
10528 return isolate->factory()->undefined_value();
10529 }
10530 return handle(accessor, isolate);
10531 }
10532
New(Isolate * isolate,int deopt_entry_count,PretenureFlag pretenure)10533 Handle<DeoptimizationInputData> DeoptimizationInputData::New(
10534 Isolate* isolate, int deopt_entry_count, PretenureFlag pretenure) {
10535 return Handle<DeoptimizationInputData>::cast(
10536 isolate->factory()->NewFixedArray(LengthFor(deopt_entry_count),
10537 pretenure));
10538 }
10539
10540
New(Isolate * isolate,int number_of_deopt_points,PretenureFlag pretenure)10541 Handle<DeoptimizationOutputData> DeoptimizationOutputData::New(
10542 Isolate* isolate,
10543 int number_of_deopt_points,
10544 PretenureFlag pretenure) {
10545 Handle<FixedArray> result;
10546 if (number_of_deopt_points == 0) {
10547 result = isolate->factory()->empty_fixed_array();
10548 } else {
10549 result = isolate->factory()->NewFixedArray(
10550 LengthOfFixedArray(number_of_deopt_points), pretenure);
10551 }
10552 return Handle<DeoptimizationOutputData>::cast(result);
10553 }
10554
GetInlinedFunction(int index)10555 SharedFunctionInfo* DeoptimizationInputData::GetInlinedFunction(int index) {
10556 if (index == -1) {
10557 return SharedFunctionInfo::cast(this->SharedFunctionInfo());
10558 } else {
10559 return SharedFunctionInfo::cast(LiteralArray()->get(index));
10560 }
10561 }
10562
10563 const int LiteralsArray::kFeedbackVectorOffset =
10564 LiteralsArray::OffsetOfElementAt(LiteralsArray::kVectorIndex);
10565
10566 const int LiteralsArray::kOffsetToFirstLiteral =
10567 LiteralsArray::OffsetOfElementAt(LiteralsArray::kFirstLiteralIndex);
10568
10569 // static
New(Isolate * isolate,Handle<TypeFeedbackVector> vector,int number_of_literals,PretenureFlag pretenure)10570 Handle<LiteralsArray> LiteralsArray::New(Isolate* isolate,
10571 Handle<TypeFeedbackVector> vector,
10572 int number_of_literals,
10573 PretenureFlag pretenure) {
10574 if (vector->is_empty() && number_of_literals == 0) {
10575 return Handle<LiteralsArray>::cast(
10576 isolate->factory()->empty_literals_array());
10577 }
10578 Handle<FixedArray> literals = isolate->factory()->NewFixedArray(
10579 number_of_literals + kFirstLiteralIndex, pretenure);
10580 Handle<LiteralsArray> casted_literals = Handle<LiteralsArray>::cast(literals);
10581 casted_literals->set_feedback_vector(*vector);
10582 return casted_literals;
10583 }
10584
LookupRange(int pc_offset,int * data_out,CatchPrediction * prediction_out)10585 int HandlerTable::LookupRange(int pc_offset, int* data_out,
10586 CatchPrediction* prediction_out) {
10587 int innermost_handler = -1;
10588 #ifdef DEBUG
10589 // Assuming that ranges are well nested, we don't need to track the innermost
10590 // offsets. This is just to verify that the table is actually well nested.
10591 int innermost_start = std::numeric_limits<int>::min();
10592 int innermost_end = std::numeric_limits<int>::max();
10593 #endif
10594 for (int i = 0; i < length(); i += kRangeEntrySize) {
10595 int start_offset = Smi::cast(get(i + kRangeStartIndex))->value();
10596 int end_offset = Smi::cast(get(i + kRangeEndIndex))->value();
10597 int handler_field = Smi::cast(get(i + kRangeHandlerIndex))->value();
10598 int handler_offset = HandlerOffsetField::decode(handler_field);
10599 CatchPrediction prediction = HandlerPredictionField::decode(handler_field);
10600 int handler_data = Smi::cast(get(i + kRangeDataIndex))->value();
10601 if (pc_offset > start_offset && pc_offset <= end_offset) {
10602 DCHECK_GE(start_offset, innermost_start);
10603 DCHECK_LT(end_offset, innermost_end);
10604 innermost_handler = handler_offset;
10605 #ifdef DEBUG
10606 innermost_start = start_offset;
10607 innermost_end = end_offset;
10608 #endif
10609 if (data_out) *data_out = handler_data;
10610 if (prediction_out) *prediction_out = prediction;
10611 }
10612 }
10613 return innermost_handler;
10614 }
10615
10616
10617 // TODO(turbofan): Make sure table is sorted and use binary search.
LookupReturn(int pc_offset)10618 int HandlerTable::LookupReturn(int pc_offset) {
10619 for (int i = 0; i < length(); i += kReturnEntrySize) {
10620 int return_offset = Smi::cast(get(i + kReturnOffsetIndex))->value();
10621 int handler_field = Smi::cast(get(i + kReturnHandlerIndex))->value();
10622 if (pc_offset == return_offset) {
10623 return HandlerOffsetField::decode(handler_field);
10624 }
10625 }
10626 return -1;
10627 }
10628
10629
10630 #ifdef DEBUG
IsEqualTo(DescriptorArray * other)10631 bool DescriptorArray::IsEqualTo(DescriptorArray* other) {
10632 if (IsEmpty()) return other->IsEmpty();
10633 if (other->IsEmpty()) return false;
10634 if (length() != other->length()) return false;
10635 for (int i = 0; i < length(); ++i) {
10636 if (get(i) != other->get(i)) return false;
10637 }
10638 return true;
10639 }
10640 #endif
10641
10642 // static
Trim(Handle<String> string,TrimMode mode)10643 Handle<String> String::Trim(Handle<String> string, TrimMode mode) {
10644 Isolate* const isolate = string->GetIsolate();
10645 string = String::Flatten(string);
10646 int const length = string->length();
10647
10648 // Perform left trimming if requested.
10649 int left = 0;
10650 UnicodeCache* unicode_cache = isolate->unicode_cache();
10651 if (mode == kTrim || mode == kTrimLeft) {
10652 while (left < length &&
10653 unicode_cache->IsWhiteSpaceOrLineTerminator(string->Get(left))) {
10654 left++;
10655 }
10656 }
10657
10658 // Perform right trimming if requested.
10659 int right = length;
10660 if (mode == kTrim || mode == kTrimRight) {
10661 while (
10662 right > left &&
10663 unicode_cache->IsWhiteSpaceOrLineTerminator(string->Get(right - 1))) {
10664 right--;
10665 }
10666 }
10667
10668 return isolate->factory()->NewSubString(string, left, right);
10669 }
10670
LooksValid()10671 bool String::LooksValid() {
10672 if (!GetIsolate()->heap()->Contains(this)) return false;
10673 return true;
10674 }
10675
10676
10677 // static
ToFunctionName(Handle<Name> name)10678 MaybeHandle<String> Name::ToFunctionName(Handle<Name> name) {
10679 if (name->IsString()) return Handle<String>::cast(name);
10680 // ES6 section 9.2.11 SetFunctionName, step 4.
10681 Isolate* const isolate = name->GetIsolate();
10682 Handle<Object> description(Handle<Symbol>::cast(name)->name(), isolate);
10683 if (description->IsUndefined(isolate)) {
10684 return isolate->factory()->empty_string();
10685 }
10686 IncrementalStringBuilder builder(isolate);
10687 builder.AppendCharacter('[');
10688 builder.AppendString(Handle<String>::cast(description));
10689 builder.AppendCharacter(']');
10690 return builder.Finish();
10691 }
10692
10693 // static
ToFunctionName(Handle<Name> name,Handle<String> prefix)10694 MaybeHandle<String> Name::ToFunctionName(Handle<Name> name,
10695 Handle<String> prefix) {
10696 Handle<String> name_string;
10697 Isolate* const isolate = name->GetIsolate();
10698 ASSIGN_RETURN_ON_EXCEPTION(isolate, name_string, ToFunctionName(name),
10699 String);
10700 IncrementalStringBuilder builder(isolate);
10701 builder.AppendString(prefix);
10702 builder.AppendCharacter(' ');
10703 builder.AppendString(name_string);
10704 return builder.Finish();
10705 }
10706
10707 namespace {
10708
AreDigits(const uint8_t * s,int from,int to)10709 bool AreDigits(const uint8_t* s, int from, int to) {
10710 for (int i = from; i < to; i++) {
10711 if (s[i] < '0' || s[i] > '9') return false;
10712 }
10713
10714 return true;
10715 }
10716
10717
ParseDecimalInteger(const uint8_t * s,int from,int to)10718 int ParseDecimalInteger(const uint8_t* s, int from, int to) {
10719 DCHECK(to - from < 10); // Overflow is not possible.
10720 DCHECK(from < to);
10721 int d = s[from] - '0';
10722
10723 for (int i = from + 1; i < to; i++) {
10724 d = 10 * d + (s[i] - '0');
10725 }
10726
10727 return d;
10728 }
10729
10730 } // namespace
10731
10732
10733 // static
ToNumber(Handle<String> subject)10734 Handle<Object> String::ToNumber(Handle<String> subject) {
10735 Isolate* const isolate = subject->GetIsolate();
10736
10737 // Flatten {subject} string first.
10738 subject = String::Flatten(subject);
10739
10740 // Fast array index case.
10741 uint32_t index;
10742 if (subject->AsArrayIndex(&index)) {
10743 return isolate->factory()->NewNumberFromUint(index);
10744 }
10745
10746 // Fast case: short integer or some sorts of junk values.
10747 if (subject->IsSeqOneByteString()) {
10748 int len = subject->length();
10749 if (len == 0) return handle(Smi::kZero, isolate);
10750
10751 DisallowHeapAllocation no_gc;
10752 uint8_t const* data = Handle<SeqOneByteString>::cast(subject)->GetChars();
10753 bool minus = (data[0] == '-');
10754 int start_pos = (minus ? 1 : 0);
10755
10756 if (start_pos == len) {
10757 return isolate->factory()->nan_value();
10758 } else if (data[start_pos] > '9') {
10759 // Fast check for a junk value. A valid string may start from a
10760 // whitespace, a sign ('+' or '-'), the decimal point, a decimal digit
10761 // or the 'I' character ('Infinity'). All of that have codes not greater
10762 // than '9' except 'I' and .
10763 if (data[start_pos] != 'I' && data[start_pos] != 0xa0) {
10764 return isolate->factory()->nan_value();
10765 }
10766 } else if (len - start_pos < 10 && AreDigits(data, start_pos, len)) {
10767 // The maximal/minimal smi has 10 digits. If the string has less digits
10768 // we know it will fit into the smi-data type.
10769 int d = ParseDecimalInteger(data, start_pos, len);
10770 if (minus) {
10771 if (d == 0) return isolate->factory()->minus_zero_value();
10772 d = -d;
10773 } else if (!subject->HasHashCode() && len <= String::kMaxArrayIndexSize &&
10774 (len == 1 || data[0] != '0')) {
10775 // String hash is not calculated yet but all the data are present.
10776 // Update the hash field to speed up sequential convertions.
10777 uint32_t hash = StringHasher::MakeArrayIndexHash(d, len);
10778 #ifdef DEBUG
10779 subject->Hash(); // Force hash calculation.
10780 DCHECK_EQ(static_cast<int>(subject->hash_field()),
10781 static_cast<int>(hash));
10782 #endif
10783 subject->set_hash_field(hash);
10784 }
10785 return handle(Smi::FromInt(d), isolate);
10786 }
10787 }
10788
10789 // Slower case.
10790 int flags = ALLOW_HEX | ALLOW_OCTAL | ALLOW_BINARY;
10791 return isolate->factory()->NewNumber(
10792 StringToDouble(isolate->unicode_cache(), subject, flags));
10793 }
10794
10795
GetFlatContent()10796 String::FlatContent String::GetFlatContent() {
10797 DCHECK(!AllowHeapAllocation::IsAllowed());
10798 int length = this->length();
10799 StringShape shape(this);
10800 String* string = this;
10801 int offset = 0;
10802 if (shape.representation_tag() == kConsStringTag) {
10803 ConsString* cons = ConsString::cast(string);
10804 if (cons->second()->length() != 0) {
10805 return FlatContent();
10806 }
10807 string = cons->first();
10808 shape = StringShape(string);
10809 }
10810 if (shape.representation_tag() == kSlicedStringTag) {
10811 SlicedString* slice = SlicedString::cast(string);
10812 offset = slice->offset();
10813 string = slice->parent();
10814 shape = StringShape(string);
10815 DCHECK(shape.representation_tag() != kConsStringTag &&
10816 shape.representation_tag() != kSlicedStringTag);
10817 }
10818 if (shape.encoding_tag() == kOneByteStringTag) {
10819 const uint8_t* start;
10820 if (shape.representation_tag() == kSeqStringTag) {
10821 start = SeqOneByteString::cast(string)->GetChars();
10822 } else {
10823 start = ExternalOneByteString::cast(string)->GetChars();
10824 }
10825 return FlatContent(start + offset, length);
10826 } else {
10827 DCHECK(shape.encoding_tag() == kTwoByteStringTag);
10828 const uc16* start;
10829 if (shape.representation_tag() == kSeqStringTag) {
10830 start = SeqTwoByteString::cast(string)->GetChars();
10831 } else {
10832 start = ExternalTwoByteString::cast(string)->GetChars();
10833 }
10834 return FlatContent(start + offset, length);
10835 }
10836 }
10837
ToCString(AllowNullsFlag allow_nulls,RobustnessFlag robust_flag,int offset,int length,int * length_return)10838 std::unique_ptr<char[]> String::ToCString(AllowNullsFlag allow_nulls,
10839 RobustnessFlag robust_flag,
10840 int offset, int length,
10841 int* length_return) {
10842 if (robust_flag == ROBUST_STRING_TRAVERSAL && !LooksValid()) {
10843 return std::unique_ptr<char[]>();
10844 }
10845 // Negative length means the to the end of the string.
10846 if (length < 0) length = kMaxInt - offset;
10847
10848 // Compute the size of the UTF-8 string. Start at the specified offset.
10849 StringCharacterStream stream(this, offset);
10850 int character_position = offset;
10851 int utf8_bytes = 0;
10852 int last = unibrow::Utf16::kNoPreviousCharacter;
10853 while (stream.HasMore() && character_position++ < offset + length) {
10854 uint16_t character = stream.GetNext();
10855 utf8_bytes += unibrow::Utf8::Length(character, last);
10856 last = character;
10857 }
10858
10859 if (length_return) {
10860 *length_return = utf8_bytes;
10861 }
10862
10863 char* result = NewArray<char>(utf8_bytes + 1);
10864
10865 // Convert the UTF-16 string to a UTF-8 buffer. Start at the specified offset.
10866 stream.Reset(this, offset);
10867 character_position = offset;
10868 int utf8_byte_position = 0;
10869 last = unibrow::Utf16::kNoPreviousCharacter;
10870 while (stream.HasMore() && character_position++ < offset + length) {
10871 uint16_t character = stream.GetNext();
10872 if (allow_nulls == DISALLOW_NULLS && character == 0) {
10873 character = ' ';
10874 }
10875 utf8_byte_position +=
10876 unibrow::Utf8::Encode(result + utf8_byte_position, character, last);
10877 last = character;
10878 }
10879 result[utf8_byte_position] = 0;
10880 return std::unique_ptr<char[]>(result);
10881 }
10882
ToCString(AllowNullsFlag allow_nulls,RobustnessFlag robust_flag,int * length_return)10883 std::unique_ptr<char[]> String::ToCString(AllowNullsFlag allow_nulls,
10884 RobustnessFlag robust_flag,
10885 int* length_return) {
10886 return ToCString(allow_nulls, robust_flag, 0, -1, length_return);
10887 }
10888
10889
GetTwoByteData(unsigned start)10890 const uc16* String::GetTwoByteData(unsigned start) {
10891 DCHECK(!IsOneByteRepresentationUnderneath());
10892 switch (StringShape(this).representation_tag()) {
10893 case kSeqStringTag:
10894 return SeqTwoByteString::cast(this)->SeqTwoByteStringGetData(start);
10895 case kExternalStringTag:
10896 return ExternalTwoByteString::cast(this)->
10897 ExternalTwoByteStringGetData(start);
10898 case kSlicedStringTag: {
10899 SlicedString* slice = SlicedString::cast(this);
10900 return slice->parent()->GetTwoByteData(start + slice->offset());
10901 }
10902 case kConsStringTag:
10903 UNREACHABLE();
10904 return NULL;
10905 }
10906 UNREACHABLE();
10907 return NULL;
10908 }
10909
10910
SeqTwoByteStringGetData(unsigned start)10911 const uc16* SeqTwoByteString::SeqTwoByteStringGetData(unsigned start) {
10912 return reinterpret_cast<uc16*>(
10913 reinterpret_cast<char*>(this) - kHeapObjectTag + kHeaderSize) + start;
10914 }
10915
10916
PostGarbageCollectionProcessing(Isolate * isolate)10917 void Relocatable::PostGarbageCollectionProcessing(Isolate* isolate) {
10918 Relocatable* current = isolate->relocatable_top();
10919 while (current != NULL) {
10920 current->PostGarbageCollection();
10921 current = current->prev_;
10922 }
10923 }
10924
10925
10926 // Reserve space for statics needing saving and restoring.
ArchiveSpacePerThread()10927 int Relocatable::ArchiveSpacePerThread() {
10928 return sizeof(Relocatable*); // NOLINT
10929 }
10930
10931
10932 // Archive statics that are thread-local.
ArchiveState(Isolate * isolate,char * to)10933 char* Relocatable::ArchiveState(Isolate* isolate, char* to) {
10934 *reinterpret_cast<Relocatable**>(to) = isolate->relocatable_top();
10935 isolate->set_relocatable_top(NULL);
10936 return to + ArchiveSpacePerThread();
10937 }
10938
10939
10940 // Restore statics that are thread-local.
RestoreState(Isolate * isolate,char * from)10941 char* Relocatable::RestoreState(Isolate* isolate, char* from) {
10942 isolate->set_relocatable_top(*reinterpret_cast<Relocatable**>(from));
10943 return from + ArchiveSpacePerThread();
10944 }
10945
10946
Iterate(ObjectVisitor * v,char * thread_storage)10947 char* Relocatable::Iterate(ObjectVisitor* v, char* thread_storage) {
10948 Relocatable* top = *reinterpret_cast<Relocatable**>(thread_storage);
10949 Iterate(v, top);
10950 return thread_storage + ArchiveSpacePerThread();
10951 }
10952
10953
Iterate(Isolate * isolate,ObjectVisitor * v)10954 void Relocatable::Iterate(Isolate* isolate, ObjectVisitor* v) {
10955 Iterate(v, isolate->relocatable_top());
10956 }
10957
10958
Iterate(ObjectVisitor * v,Relocatable * top)10959 void Relocatable::Iterate(ObjectVisitor* v, Relocatable* top) {
10960 Relocatable* current = top;
10961 while (current != NULL) {
10962 current->IterateInstance(v);
10963 current = current->prev_;
10964 }
10965 }
10966
10967
FlatStringReader(Isolate * isolate,Handle<String> str)10968 FlatStringReader::FlatStringReader(Isolate* isolate, Handle<String> str)
10969 : Relocatable(isolate),
10970 str_(str.location()),
10971 length_(str->length()) {
10972 PostGarbageCollection();
10973 }
10974
10975
FlatStringReader(Isolate * isolate,Vector<const char> input)10976 FlatStringReader::FlatStringReader(Isolate* isolate, Vector<const char> input)
10977 : Relocatable(isolate),
10978 str_(0),
10979 is_one_byte_(true),
10980 length_(input.length()),
10981 start_(input.start()) {}
10982
10983
PostGarbageCollection()10984 void FlatStringReader::PostGarbageCollection() {
10985 if (str_ == NULL) return;
10986 Handle<String> str(str_);
10987 DCHECK(str->IsFlat());
10988 DisallowHeapAllocation no_gc;
10989 // This does not actually prevent the vector from being relocated later.
10990 String::FlatContent content = str->GetFlatContent();
10991 DCHECK(content.IsFlat());
10992 is_one_byte_ = content.IsOneByte();
10993 if (is_one_byte_) {
10994 start_ = content.ToOneByteVector().start();
10995 } else {
10996 start_ = content.ToUC16Vector().start();
10997 }
10998 }
10999
11000
Initialize(ConsString * cons_string,int offset)11001 void ConsStringIterator::Initialize(ConsString* cons_string, int offset) {
11002 DCHECK(cons_string != NULL);
11003 root_ = cons_string;
11004 consumed_ = offset;
11005 // Force stack blown condition to trigger restart.
11006 depth_ = 1;
11007 maximum_depth_ = kStackSize + depth_;
11008 DCHECK(StackBlown());
11009 }
11010
11011
Continue(int * offset_out)11012 String* ConsStringIterator::Continue(int* offset_out) {
11013 DCHECK(depth_ != 0);
11014 DCHECK_EQ(0, *offset_out);
11015 bool blew_stack = StackBlown();
11016 String* string = NULL;
11017 // Get the next leaf if there is one.
11018 if (!blew_stack) string = NextLeaf(&blew_stack);
11019 // Restart search from root.
11020 if (blew_stack) {
11021 DCHECK(string == NULL);
11022 string = Search(offset_out);
11023 }
11024 // Ensure future calls return null immediately.
11025 if (string == NULL) Reset(NULL);
11026 return string;
11027 }
11028
11029
Search(int * offset_out)11030 String* ConsStringIterator::Search(int* offset_out) {
11031 ConsString* cons_string = root_;
11032 // Reset the stack, pushing the root string.
11033 depth_ = 1;
11034 maximum_depth_ = 1;
11035 frames_[0] = cons_string;
11036 const int consumed = consumed_;
11037 int offset = 0;
11038 while (true) {
11039 // Loop until the string is found which contains the target offset.
11040 String* string = cons_string->first();
11041 int length = string->length();
11042 int32_t type;
11043 if (consumed < offset + length) {
11044 // Target offset is in the left branch.
11045 // Keep going if we're still in a ConString.
11046 type = string->map()->instance_type();
11047 if ((type & kStringRepresentationMask) == kConsStringTag) {
11048 cons_string = ConsString::cast(string);
11049 PushLeft(cons_string);
11050 continue;
11051 }
11052 // Tell the stack we're done descending.
11053 AdjustMaximumDepth();
11054 } else {
11055 // Descend right.
11056 // Update progress through the string.
11057 offset += length;
11058 // Keep going if we're still in a ConString.
11059 string = cons_string->second();
11060 type = string->map()->instance_type();
11061 if ((type & kStringRepresentationMask) == kConsStringTag) {
11062 cons_string = ConsString::cast(string);
11063 PushRight(cons_string);
11064 continue;
11065 }
11066 // Need this to be updated for the current string.
11067 length = string->length();
11068 // Account for the possibility of an empty right leaf.
11069 // This happens only if we have asked for an offset outside the string.
11070 if (length == 0) {
11071 // Reset so future operations will return null immediately.
11072 Reset(NULL);
11073 return NULL;
11074 }
11075 // Tell the stack we're done descending.
11076 AdjustMaximumDepth();
11077 // Pop stack so next iteration is in correct place.
11078 Pop();
11079 }
11080 DCHECK(length != 0);
11081 // Adjust return values and exit.
11082 consumed_ = offset + length;
11083 *offset_out = consumed - offset;
11084 return string;
11085 }
11086 UNREACHABLE();
11087 return NULL;
11088 }
11089
11090
NextLeaf(bool * blew_stack)11091 String* ConsStringIterator::NextLeaf(bool* blew_stack) {
11092 while (true) {
11093 // Tree traversal complete.
11094 if (depth_ == 0) {
11095 *blew_stack = false;
11096 return NULL;
11097 }
11098 // We've lost track of higher nodes.
11099 if (StackBlown()) {
11100 *blew_stack = true;
11101 return NULL;
11102 }
11103 // Go right.
11104 ConsString* cons_string = frames_[OffsetForDepth(depth_ - 1)];
11105 String* string = cons_string->second();
11106 int32_t type = string->map()->instance_type();
11107 if ((type & kStringRepresentationMask) != kConsStringTag) {
11108 // Pop stack so next iteration is in correct place.
11109 Pop();
11110 int length = string->length();
11111 // Could be a flattened ConsString.
11112 if (length == 0) continue;
11113 consumed_ += length;
11114 return string;
11115 }
11116 cons_string = ConsString::cast(string);
11117 PushRight(cons_string);
11118 // Need to traverse all the way left.
11119 while (true) {
11120 // Continue left.
11121 string = cons_string->first();
11122 type = string->map()->instance_type();
11123 if ((type & kStringRepresentationMask) != kConsStringTag) {
11124 AdjustMaximumDepth();
11125 int length = string->length();
11126 if (length == 0) break; // Skip empty left-hand sides of ConsStrings.
11127 consumed_ += length;
11128 return string;
11129 }
11130 cons_string = ConsString::cast(string);
11131 PushLeft(cons_string);
11132 }
11133 }
11134 UNREACHABLE();
11135 return NULL;
11136 }
11137
11138
ConsStringGet(int index)11139 uint16_t ConsString::ConsStringGet(int index) {
11140 DCHECK(index >= 0 && index < this->length());
11141
11142 // Check for a flattened cons string
11143 if (second()->length() == 0) {
11144 String* left = first();
11145 return left->Get(index);
11146 }
11147
11148 String* string = String::cast(this);
11149
11150 while (true) {
11151 if (StringShape(string).IsCons()) {
11152 ConsString* cons_string = ConsString::cast(string);
11153 String* left = cons_string->first();
11154 if (left->length() > index) {
11155 string = left;
11156 } else {
11157 index -= left->length();
11158 string = cons_string->second();
11159 }
11160 } else {
11161 return string->Get(index);
11162 }
11163 }
11164
11165 UNREACHABLE();
11166 return 0;
11167 }
11168
11169
SlicedStringGet(int index)11170 uint16_t SlicedString::SlicedStringGet(int index) {
11171 return parent()->Get(offset() + index);
11172 }
11173
11174
11175 template <typename sinkchar>
WriteToFlat(String * src,sinkchar * sink,int f,int t)11176 void String::WriteToFlat(String* src,
11177 sinkchar* sink,
11178 int f,
11179 int t) {
11180 String* source = src;
11181 int from = f;
11182 int to = t;
11183 while (true) {
11184 DCHECK(0 <= from && from <= to && to <= source->length());
11185 switch (StringShape(source).full_representation_tag()) {
11186 case kOneByteStringTag | kExternalStringTag: {
11187 CopyChars(sink, ExternalOneByteString::cast(source)->GetChars() + from,
11188 to - from);
11189 return;
11190 }
11191 case kTwoByteStringTag | kExternalStringTag: {
11192 const uc16* data =
11193 ExternalTwoByteString::cast(source)->GetChars();
11194 CopyChars(sink,
11195 data + from,
11196 to - from);
11197 return;
11198 }
11199 case kOneByteStringTag | kSeqStringTag: {
11200 CopyChars(sink,
11201 SeqOneByteString::cast(source)->GetChars() + from,
11202 to - from);
11203 return;
11204 }
11205 case kTwoByteStringTag | kSeqStringTag: {
11206 CopyChars(sink,
11207 SeqTwoByteString::cast(source)->GetChars() + from,
11208 to - from);
11209 return;
11210 }
11211 case kOneByteStringTag | kConsStringTag:
11212 case kTwoByteStringTag | kConsStringTag: {
11213 ConsString* cons_string = ConsString::cast(source);
11214 String* first = cons_string->first();
11215 int boundary = first->length();
11216 if (to - boundary >= boundary - from) {
11217 // Right hand side is longer. Recurse over left.
11218 if (from < boundary) {
11219 WriteToFlat(first, sink, from, boundary);
11220 if (from == 0 && cons_string->second() == first) {
11221 CopyChars(sink + boundary, sink, boundary);
11222 return;
11223 }
11224 sink += boundary - from;
11225 from = 0;
11226 } else {
11227 from -= boundary;
11228 }
11229 to -= boundary;
11230 source = cons_string->second();
11231 } else {
11232 // Left hand side is longer. Recurse over right.
11233 if (to > boundary) {
11234 String* second = cons_string->second();
11235 // When repeatedly appending to a string, we get a cons string that
11236 // is unbalanced to the left, a list, essentially. We inline the
11237 // common case of sequential one-byte right child.
11238 if (to - boundary == 1) {
11239 sink[boundary - from] = static_cast<sinkchar>(second->Get(0));
11240 } else if (second->IsSeqOneByteString()) {
11241 CopyChars(sink + boundary - from,
11242 SeqOneByteString::cast(second)->GetChars(),
11243 to - boundary);
11244 } else {
11245 WriteToFlat(second,
11246 sink + boundary - from,
11247 0,
11248 to - boundary);
11249 }
11250 to = boundary;
11251 }
11252 source = first;
11253 }
11254 break;
11255 }
11256 case kOneByteStringTag | kSlicedStringTag:
11257 case kTwoByteStringTag | kSlicedStringTag: {
11258 SlicedString* slice = SlicedString::cast(source);
11259 unsigned offset = slice->offset();
11260 WriteToFlat(slice->parent(), sink, from + offset, to + offset);
11261 return;
11262 }
11263 }
11264 }
11265 }
11266
11267
11268
11269 template <typename SourceChar>
CalculateLineEndsImpl(Isolate * isolate,List<int> * line_ends,Vector<const SourceChar> src,bool include_ending_line)11270 static void CalculateLineEndsImpl(Isolate* isolate,
11271 List<int>* line_ends,
11272 Vector<const SourceChar> src,
11273 bool include_ending_line) {
11274 const int src_len = src.length();
11275 UnicodeCache* cache = isolate->unicode_cache();
11276 for (int i = 0; i < src_len - 1; i++) {
11277 SourceChar current = src[i];
11278 SourceChar next = src[i + 1];
11279 if (cache->IsLineTerminatorSequence(current, next)) line_ends->Add(i);
11280 }
11281
11282 if (src_len > 0 && cache->IsLineTerminatorSequence(src[src_len - 1], 0)) {
11283 line_ends->Add(src_len - 1);
11284 }
11285 if (include_ending_line) {
11286 // Include one character beyond the end of script. The rewriter uses that
11287 // position for the implicit return statement.
11288 line_ends->Add(src_len);
11289 }
11290 }
11291
11292
CalculateLineEnds(Handle<String> src,bool include_ending_line)11293 Handle<FixedArray> String::CalculateLineEnds(Handle<String> src,
11294 bool include_ending_line) {
11295 src = Flatten(src);
11296 // Rough estimate of line count based on a roughly estimated average
11297 // length of (unpacked) code.
11298 int line_count_estimate = src->length() >> 4;
11299 List<int> line_ends(line_count_estimate);
11300 Isolate* isolate = src->GetIsolate();
11301 { DisallowHeapAllocation no_allocation; // ensure vectors stay valid.
11302 // Dispatch on type of strings.
11303 String::FlatContent content = src->GetFlatContent();
11304 DCHECK(content.IsFlat());
11305 if (content.IsOneByte()) {
11306 CalculateLineEndsImpl(isolate,
11307 &line_ends,
11308 content.ToOneByteVector(),
11309 include_ending_line);
11310 } else {
11311 CalculateLineEndsImpl(isolate,
11312 &line_ends,
11313 content.ToUC16Vector(),
11314 include_ending_line);
11315 }
11316 }
11317 int line_count = line_ends.length();
11318 Handle<FixedArray> array = isolate->factory()->NewFixedArray(line_count);
11319 for (int i = 0; i < line_count; i++) {
11320 array->set(i, Smi::FromInt(line_ends[i]));
11321 }
11322 return array;
11323 }
11324
11325
11326 // Compares the contents of two strings by reading and comparing
11327 // int-sized blocks of characters.
11328 template <typename Char>
CompareRawStringContents(const Char * const a,const Char * const b,int length)11329 static inline bool CompareRawStringContents(const Char* const a,
11330 const Char* const b,
11331 int length) {
11332 return CompareChars(a, b, length) == 0;
11333 }
11334
11335
11336 template<typename Chars1, typename Chars2>
11337 class RawStringComparator : public AllStatic {
11338 public:
compare(const Chars1 * a,const Chars2 * b,int len)11339 static inline bool compare(const Chars1* a, const Chars2* b, int len) {
11340 DCHECK(sizeof(Chars1) != sizeof(Chars2));
11341 for (int i = 0; i < len; i++) {
11342 if (a[i] != b[i]) {
11343 return false;
11344 }
11345 }
11346 return true;
11347 }
11348 };
11349
11350
11351 template<>
11352 class RawStringComparator<uint16_t, uint16_t> {
11353 public:
compare(const uint16_t * a,const uint16_t * b,int len)11354 static inline bool compare(const uint16_t* a, const uint16_t* b, int len) {
11355 return CompareRawStringContents(a, b, len);
11356 }
11357 };
11358
11359
11360 template<>
11361 class RawStringComparator<uint8_t, uint8_t> {
11362 public:
compare(const uint8_t * a,const uint8_t * b,int len)11363 static inline bool compare(const uint8_t* a, const uint8_t* b, int len) {
11364 return CompareRawStringContents(a, b, len);
11365 }
11366 };
11367
11368
11369 class StringComparator {
11370 class State {
11371 public:
State()11372 State() : is_one_byte_(true), length_(0), buffer8_(NULL) {}
11373
Init(String * string)11374 void Init(String* string) {
11375 ConsString* cons_string = String::VisitFlat(this, string);
11376 iter_.Reset(cons_string);
11377 if (cons_string != NULL) {
11378 int offset;
11379 string = iter_.Next(&offset);
11380 String::VisitFlat(this, string, offset);
11381 }
11382 }
11383
VisitOneByteString(const uint8_t * chars,int length)11384 inline void VisitOneByteString(const uint8_t* chars, int length) {
11385 is_one_byte_ = true;
11386 buffer8_ = chars;
11387 length_ = length;
11388 }
11389
VisitTwoByteString(const uint16_t * chars,int length)11390 inline void VisitTwoByteString(const uint16_t* chars, int length) {
11391 is_one_byte_ = false;
11392 buffer16_ = chars;
11393 length_ = length;
11394 }
11395
Advance(int consumed)11396 void Advance(int consumed) {
11397 DCHECK(consumed <= length_);
11398 // Still in buffer.
11399 if (length_ != consumed) {
11400 if (is_one_byte_) {
11401 buffer8_ += consumed;
11402 } else {
11403 buffer16_ += consumed;
11404 }
11405 length_ -= consumed;
11406 return;
11407 }
11408 // Advance state.
11409 int offset;
11410 String* next = iter_.Next(&offset);
11411 DCHECK_EQ(0, offset);
11412 DCHECK(next != NULL);
11413 String::VisitFlat(this, next);
11414 }
11415
11416 ConsStringIterator iter_;
11417 bool is_one_byte_;
11418 int length_;
11419 union {
11420 const uint8_t* buffer8_;
11421 const uint16_t* buffer16_;
11422 };
11423
11424 private:
11425 DISALLOW_COPY_AND_ASSIGN(State);
11426 };
11427
11428 public:
StringComparator()11429 inline StringComparator() {}
11430
11431 template<typename Chars1, typename Chars2>
Equals(State * state_1,State * state_2,int to_check)11432 static inline bool Equals(State* state_1, State* state_2, int to_check) {
11433 const Chars1* a = reinterpret_cast<const Chars1*>(state_1->buffer8_);
11434 const Chars2* b = reinterpret_cast<const Chars2*>(state_2->buffer8_);
11435 return RawStringComparator<Chars1, Chars2>::compare(a, b, to_check);
11436 }
11437
Equals(String * string_1,String * string_2)11438 bool Equals(String* string_1, String* string_2) {
11439 int length = string_1->length();
11440 state_1_.Init(string_1);
11441 state_2_.Init(string_2);
11442 while (true) {
11443 int to_check = Min(state_1_.length_, state_2_.length_);
11444 DCHECK(to_check > 0 && to_check <= length);
11445 bool is_equal;
11446 if (state_1_.is_one_byte_) {
11447 if (state_2_.is_one_byte_) {
11448 is_equal = Equals<uint8_t, uint8_t>(&state_1_, &state_2_, to_check);
11449 } else {
11450 is_equal = Equals<uint8_t, uint16_t>(&state_1_, &state_2_, to_check);
11451 }
11452 } else {
11453 if (state_2_.is_one_byte_) {
11454 is_equal = Equals<uint16_t, uint8_t>(&state_1_, &state_2_, to_check);
11455 } else {
11456 is_equal = Equals<uint16_t, uint16_t>(&state_1_, &state_2_, to_check);
11457 }
11458 }
11459 // Looping done.
11460 if (!is_equal) return false;
11461 length -= to_check;
11462 // Exit condition. Strings are equal.
11463 if (length == 0) return true;
11464 state_1_.Advance(to_check);
11465 state_2_.Advance(to_check);
11466 }
11467 }
11468
11469 private:
11470 State state_1_;
11471 State state_2_;
11472
11473 DISALLOW_COPY_AND_ASSIGN(StringComparator);
11474 };
11475
11476
SlowEquals(String * other)11477 bool String::SlowEquals(String* other) {
11478 DisallowHeapAllocation no_gc;
11479 // Fast check: negative check with lengths.
11480 int len = length();
11481 if (len != other->length()) return false;
11482 if (len == 0) return true;
11483
11484 // Fast check: if hash code is computed for both strings
11485 // a fast negative check can be performed.
11486 if (HasHashCode() && other->HasHashCode()) {
11487 #ifdef ENABLE_SLOW_DCHECKS
11488 if (FLAG_enable_slow_asserts) {
11489 if (Hash() != other->Hash()) {
11490 bool found_difference = false;
11491 for (int i = 0; i < len; i++) {
11492 if (Get(i) != other->Get(i)) {
11493 found_difference = true;
11494 break;
11495 }
11496 }
11497 DCHECK(found_difference);
11498 }
11499 }
11500 #endif
11501 if (Hash() != other->Hash()) return false;
11502 }
11503
11504 // We know the strings are both non-empty. Compare the first chars
11505 // before we try to flatten the strings.
11506 if (this->Get(0) != other->Get(0)) return false;
11507
11508 if (IsSeqOneByteString() && other->IsSeqOneByteString()) {
11509 const uint8_t* str1 = SeqOneByteString::cast(this)->GetChars();
11510 const uint8_t* str2 = SeqOneByteString::cast(other)->GetChars();
11511 return CompareRawStringContents(str1, str2, len);
11512 }
11513
11514 StringComparator comparator;
11515 return comparator.Equals(this, other);
11516 }
11517
11518
SlowEquals(Handle<String> one,Handle<String> two)11519 bool String::SlowEquals(Handle<String> one, Handle<String> two) {
11520 // Fast check: negative check with lengths.
11521 int one_length = one->length();
11522 if (one_length != two->length()) return false;
11523 if (one_length == 0) return true;
11524
11525 // Fast check: if hash code is computed for both strings
11526 // a fast negative check can be performed.
11527 if (one->HasHashCode() && two->HasHashCode()) {
11528 #ifdef ENABLE_SLOW_DCHECKS
11529 if (FLAG_enable_slow_asserts) {
11530 if (one->Hash() != two->Hash()) {
11531 bool found_difference = false;
11532 for (int i = 0; i < one_length; i++) {
11533 if (one->Get(i) != two->Get(i)) {
11534 found_difference = true;
11535 break;
11536 }
11537 }
11538 DCHECK(found_difference);
11539 }
11540 }
11541 #endif
11542 if (one->Hash() != two->Hash()) return false;
11543 }
11544
11545 // We know the strings are both non-empty. Compare the first chars
11546 // before we try to flatten the strings.
11547 if (one->Get(0) != two->Get(0)) return false;
11548
11549 one = String::Flatten(one);
11550 two = String::Flatten(two);
11551
11552 DisallowHeapAllocation no_gc;
11553 String::FlatContent flat1 = one->GetFlatContent();
11554 String::FlatContent flat2 = two->GetFlatContent();
11555
11556 if (flat1.IsOneByte() && flat2.IsOneByte()) {
11557 return CompareRawStringContents(flat1.ToOneByteVector().start(),
11558 flat2.ToOneByteVector().start(),
11559 one_length);
11560 } else {
11561 for (int i = 0; i < one_length; i++) {
11562 if (flat1.Get(i) != flat2.Get(i)) return false;
11563 }
11564 return true;
11565 }
11566 }
11567
11568
11569 // static
Compare(Handle<String> x,Handle<String> y)11570 ComparisonResult String::Compare(Handle<String> x, Handle<String> y) {
11571 // A few fast case tests before we flatten.
11572 if (x.is_identical_to(y)) {
11573 return ComparisonResult::kEqual;
11574 } else if (y->length() == 0) {
11575 return x->length() == 0 ? ComparisonResult::kEqual
11576 : ComparisonResult::kGreaterThan;
11577 } else if (x->length() == 0) {
11578 return ComparisonResult::kLessThan;
11579 }
11580
11581 int const d = x->Get(0) - y->Get(0);
11582 if (d < 0) {
11583 return ComparisonResult::kLessThan;
11584 } else if (d > 0) {
11585 return ComparisonResult::kGreaterThan;
11586 }
11587
11588 // Slow case.
11589 x = String::Flatten(x);
11590 y = String::Flatten(y);
11591
11592 DisallowHeapAllocation no_gc;
11593 ComparisonResult result = ComparisonResult::kEqual;
11594 int prefix_length = x->length();
11595 if (y->length() < prefix_length) {
11596 prefix_length = y->length();
11597 result = ComparisonResult::kGreaterThan;
11598 } else if (y->length() > prefix_length) {
11599 result = ComparisonResult::kLessThan;
11600 }
11601 int r;
11602 String::FlatContent x_content = x->GetFlatContent();
11603 String::FlatContent y_content = y->GetFlatContent();
11604 if (x_content.IsOneByte()) {
11605 Vector<const uint8_t> x_chars = x_content.ToOneByteVector();
11606 if (y_content.IsOneByte()) {
11607 Vector<const uint8_t> y_chars = y_content.ToOneByteVector();
11608 r = CompareChars(x_chars.start(), y_chars.start(), prefix_length);
11609 } else {
11610 Vector<const uc16> y_chars = y_content.ToUC16Vector();
11611 r = CompareChars(x_chars.start(), y_chars.start(), prefix_length);
11612 }
11613 } else {
11614 Vector<const uc16> x_chars = x_content.ToUC16Vector();
11615 if (y_content.IsOneByte()) {
11616 Vector<const uint8_t> y_chars = y_content.ToOneByteVector();
11617 r = CompareChars(x_chars.start(), y_chars.start(), prefix_length);
11618 } else {
11619 Vector<const uc16> y_chars = y_content.ToUC16Vector();
11620 r = CompareChars(x_chars.start(), y_chars.start(), prefix_length);
11621 }
11622 }
11623 if (r < 0) {
11624 result = ComparisonResult::kLessThan;
11625 } else if (r > 0) {
11626 result = ComparisonResult::kGreaterThan;
11627 }
11628 return result;
11629 }
11630
IndexOf(Isolate * isolate,Handle<Object> receiver,Handle<Object> search,Handle<Object> position)11631 Object* String::IndexOf(Isolate* isolate, Handle<Object> receiver,
11632 Handle<Object> search, Handle<Object> position) {
11633 if (receiver->IsNull(isolate) || receiver->IsUndefined(isolate)) {
11634 THROW_NEW_ERROR_RETURN_FAILURE(
11635 isolate, NewTypeError(MessageTemplate::kCalledOnNullOrUndefined,
11636 isolate->factory()->NewStringFromAsciiChecked(
11637 "String.prototype.indexOf")));
11638 }
11639 Handle<String> receiver_string;
11640 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, receiver_string,
11641 Object::ToString(isolate, receiver));
11642
11643 Handle<String> search_string;
11644 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, search_string,
11645 Object::ToString(isolate, search));
11646
11647 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, position,
11648 Object::ToInteger(isolate, position));
11649
11650 double index = std::max(position->Number(), 0.0);
11651 index = std::min(index, static_cast<double>(receiver_string->length()));
11652
11653 return Smi::FromInt(String::IndexOf(isolate, receiver_string, search_string,
11654 static_cast<uint32_t>(index)));
11655 }
11656
11657 namespace {
11658
11659 template <typename T>
SearchString(Isolate * isolate,String::FlatContent receiver_content,Vector<T> pat_vector,int start_index)11660 int SearchString(Isolate* isolate, String::FlatContent receiver_content,
11661 Vector<T> pat_vector, int start_index) {
11662 if (receiver_content.IsOneByte()) {
11663 return SearchString(isolate, receiver_content.ToOneByteVector(), pat_vector,
11664 start_index);
11665 }
11666 return SearchString(isolate, receiver_content.ToUC16Vector(), pat_vector,
11667 start_index);
11668 }
11669
11670 } // namespace
11671
IndexOf(Isolate * isolate,Handle<String> receiver,Handle<String> search,int start_index)11672 int String::IndexOf(Isolate* isolate, Handle<String> receiver,
11673 Handle<String> search, int start_index) {
11674 DCHECK(0 <= start_index);
11675 DCHECK(start_index <= receiver->length());
11676
11677 uint32_t search_length = search->length();
11678 if (search_length == 0) return start_index;
11679
11680 uint32_t receiver_length = receiver->length();
11681 if (start_index + search_length > receiver_length) return -1;
11682
11683 receiver = String::Flatten(receiver);
11684 search = String::Flatten(search);
11685
11686 DisallowHeapAllocation no_gc; // ensure vectors stay valid
11687 // Extract flattened substrings of cons strings before getting encoding.
11688 String::FlatContent receiver_content = receiver->GetFlatContent();
11689 String::FlatContent search_content = search->GetFlatContent();
11690
11691 // dispatch on type of strings
11692 if (search_content.IsOneByte()) {
11693 Vector<const uint8_t> pat_vector = search_content.ToOneByteVector();
11694 return SearchString<const uint8_t>(isolate, receiver_content, pat_vector,
11695 start_index);
11696 }
11697 Vector<const uc16> pat_vector = search_content.ToUC16Vector();
11698 return SearchString<const uc16>(isolate, receiver_content, pat_vector,
11699 start_index);
11700 }
11701
GetSubstitution(Isolate * isolate,Match * match,Handle<String> replacement)11702 MaybeHandle<String> String::GetSubstitution(Isolate* isolate, Match* match,
11703 Handle<String> replacement) {
11704 Factory* factory = isolate->factory();
11705
11706 const int replacement_length = replacement->length();
11707 const int captures_length = match->CaptureCount();
11708
11709 replacement = String::Flatten(replacement);
11710
11711 Handle<String> dollar_string =
11712 factory->LookupSingleCharacterStringFromCode('$');
11713 int next = String::IndexOf(isolate, replacement, dollar_string, 0);
11714 if (next < 0) {
11715 return replacement;
11716 }
11717
11718 IncrementalStringBuilder builder(isolate);
11719
11720 if (next > 0) {
11721 builder.AppendString(factory->NewSubString(replacement, 0, next));
11722 }
11723
11724 while (true) {
11725 int pos = next + 1;
11726 if (pos < replacement_length) {
11727 const uint16_t peek = replacement->Get(pos);
11728 if (peek == '$') { // $$
11729 pos++;
11730 builder.AppendCharacter('$');
11731 } else if (peek == '&') { // $& - match
11732 pos++;
11733 builder.AppendString(match->GetMatch());
11734 } else if (peek == '`') { // $` - prefix
11735 pos++;
11736 builder.AppendString(match->GetPrefix());
11737 } else if (peek == '\'') { // $' - suffix
11738 pos++;
11739 builder.AppendString(match->GetSuffix());
11740 } else if (peek >= '0' && peek <= '9') {
11741 // Valid indices are $1 .. $9, $01 .. $09 and $10 .. $99
11742 int scaled_index = (peek - '0');
11743 int advance = 1;
11744
11745 if (pos + 1 < replacement_length) {
11746 const uint16_t next_peek = replacement->Get(pos + 1);
11747 if (next_peek >= '0' && next_peek <= '9') {
11748 const int new_scaled_index = scaled_index * 10 + (next_peek - '0');
11749 if (new_scaled_index < captures_length) {
11750 scaled_index = new_scaled_index;
11751 advance = 2;
11752 }
11753 }
11754 }
11755
11756 if (scaled_index != 0 && scaled_index < captures_length) {
11757 bool capture_exists;
11758 Handle<String> capture;
11759 ASSIGN_RETURN_ON_EXCEPTION(
11760 isolate, capture,
11761 match->GetCapture(scaled_index, &capture_exists), String);
11762 if (capture_exists) builder.AppendString(capture);
11763 pos += advance;
11764 } else {
11765 builder.AppendCharacter('$');
11766 }
11767 } else {
11768 builder.AppendCharacter('$');
11769 }
11770 } else {
11771 builder.AppendCharacter('$');
11772 }
11773
11774 // Go the the next $ in the replacement.
11775 next = String::IndexOf(isolate, replacement, dollar_string, pos);
11776
11777 // Return if there are no more $ characters in the replacement. If we
11778 // haven't reached the end, we need to append the suffix.
11779 if (next < 0) {
11780 if (pos < replacement_length) {
11781 builder.AppendString(
11782 factory->NewSubString(replacement, pos, replacement_length));
11783 }
11784 return builder.Finish();
11785 }
11786
11787 // Append substring between the previous and the next $ character.
11788 if (next > pos) {
11789 builder.AppendString(factory->NewSubString(replacement, pos, next));
11790 }
11791 }
11792
11793 UNREACHABLE();
11794 return MaybeHandle<String>();
11795 }
11796
11797 namespace { // for String.Prototype.lastIndexOf
11798
11799 template <typename schar, typename pchar>
StringMatchBackwards(Vector<const schar> subject,Vector<const pchar> pattern,int idx)11800 int StringMatchBackwards(Vector<const schar> subject,
11801 Vector<const pchar> pattern, int idx) {
11802 int pattern_length = pattern.length();
11803 DCHECK(pattern_length >= 1);
11804 DCHECK(idx + pattern_length <= subject.length());
11805
11806 if (sizeof(schar) == 1 && sizeof(pchar) > 1) {
11807 for (int i = 0; i < pattern_length; i++) {
11808 uc16 c = pattern[i];
11809 if (c > String::kMaxOneByteCharCode) {
11810 return -1;
11811 }
11812 }
11813 }
11814
11815 pchar pattern_first_char = pattern[0];
11816 for (int i = idx; i >= 0; i--) {
11817 if (subject[i] != pattern_first_char) continue;
11818 int j = 1;
11819 while (j < pattern_length) {
11820 if (pattern[j] != subject[i + j]) {
11821 break;
11822 }
11823 j++;
11824 }
11825 if (j == pattern_length) {
11826 return i;
11827 }
11828 }
11829 return -1;
11830 }
11831
11832 } // namespace
11833
LastIndexOf(Isolate * isolate,Handle<Object> receiver,Handle<Object> search,Handle<Object> position)11834 Object* String::LastIndexOf(Isolate* isolate, Handle<Object> receiver,
11835 Handle<Object> search, Handle<Object> position) {
11836 if (receiver->IsNull(isolate) || receiver->IsUndefined(isolate)) {
11837 THROW_NEW_ERROR_RETURN_FAILURE(
11838 isolate, NewTypeError(MessageTemplate::kCalledOnNullOrUndefined,
11839 isolate->factory()->NewStringFromAsciiChecked(
11840 "String.prototype.lastIndexOf")));
11841 }
11842 Handle<String> receiver_string;
11843 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, receiver_string,
11844 Object::ToString(isolate, receiver));
11845
11846 Handle<String> search_string;
11847 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, search_string,
11848 Object::ToString(isolate, search));
11849
11850 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, position,
11851 Object::ToNumber(position));
11852
11853 uint32_t start_index;
11854
11855 if (position->IsNaN()) {
11856 start_index = receiver_string->length();
11857 } else {
11858 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, position,
11859 Object::ToInteger(isolate, position));
11860
11861 double position_number = std::max(position->Number(), 0.0);
11862 position_number = std::min(position_number,
11863 static_cast<double>(receiver_string->length()));
11864 start_index = static_cast<uint32_t>(position_number);
11865 }
11866
11867 uint32_t pattern_length = search_string->length();
11868 uint32_t receiver_length = receiver_string->length();
11869
11870 if (start_index + pattern_length > receiver_length) {
11871 start_index = receiver_length - pattern_length;
11872 }
11873
11874 if (pattern_length == 0) {
11875 return Smi::FromInt(start_index);
11876 }
11877
11878 receiver_string = String::Flatten(receiver_string);
11879 search_string = String::Flatten(search_string);
11880
11881 int last_index = -1;
11882 DisallowHeapAllocation no_gc; // ensure vectors stay valid
11883
11884 String::FlatContent receiver_content = receiver_string->GetFlatContent();
11885 String::FlatContent search_content = search_string->GetFlatContent();
11886
11887 if (search_content.IsOneByte()) {
11888 Vector<const uint8_t> pat_vector = search_content.ToOneByteVector();
11889 if (receiver_content.IsOneByte()) {
11890 last_index = StringMatchBackwards(receiver_content.ToOneByteVector(),
11891 pat_vector, start_index);
11892 } else {
11893 last_index = StringMatchBackwards(receiver_content.ToUC16Vector(),
11894 pat_vector, start_index);
11895 }
11896 } else {
11897 Vector<const uc16> pat_vector = search_content.ToUC16Vector();
11898 if (receiver_content.IsOneByte()) {
11899 last_index = StringMatchBackwards(receiver_content.ToOneByteVector(),
11900 pat_vector, start_index);
11901 } else {
11902 last_index = StringMatchBackwards(receiver_content.ToUC16Vector(),
11903 pat_vector, start_index);
11904 }
11905 }
11906 return Smi::FromInt(last_index);
11907 }
11908
IsUtf8EqualTo(Vector<const char> str,bool allow_prefix_match)11909 bool String::IsUtf8EqualTo(Vector<const char> str, bool allow_prefix_match) {
11910 int slen = length();
11911 // Can't check exact length equality, but we can check bounds.
11912 int str_len = str.length();
11913 if (!allow_prefix_match &&
11914 (str_len < slen ||
11915 str_len > slen*static_cast<int>(unibrow::Utf8::kMaxEncodedSize))) {
11916 return false;
11917 }
11918 int i;
11919 size_t remaining_in_str = static_cast<size_t>(str_len);
11920 const uint8_t* utf8_data = reinterpret_cast<const uint8_t*>(str.start());
11921 for (i = 0; i < slen && remaining_in_str > 0; i++) {
11922 size_t cursor = 0;
11923 uint32_t r = unibrow::Utf8::ValueOf(utf8_data, remaining_in_str, &cursor);
11924 DCHECK(cursor > 0 && cursor <= remaining_in_str);
11925 if (r > unibrow::Utf16::kMaxNonSurrogateCharCode) {
11926 if (i > slen - 1) return false;
11927 if (Get(i++) != unibrow::Utf16::LeadSurrogate(r)) return false;
11928 if (Get(i) != unibrow::Utf16::TrailSurrogate(r)) return false;
11929 } else {
11930 if (Get(i) != r) return false;
11931 }
11932 utf8_data += cursor;
11933 remaining_in_str -= cursor;
11934 }
11935 return (allow_prefix_match || i == slen) && remaining_in_str == 0;
11936 }
11937
11938
IsOneByteEqualTo(Vector<const uint8_t> str)11939 bool String::IsOneByteEqualTo(Vector<const uint8_t> str) {
11940 int slen = length();
11941 if (str.length() != slen) return false;
11942 DisallowHeapAllocation no_gc;
11943 FlatContent content = GetFlatContent();
11944 if (content.IsOneByte()) {
11945 return CompareChars(content.ToOneByteVector().start(),
11946 str.start(), slen) == 0;
11947 }
11948 for (int i = 0; i < slen; i++) {
11949 if (Get(i) != static_cast<uint16_t>(str[i])) return false;
11950 }
11951 return true;
11952 }
11953
11954
IsTwoByteEqualTo(Vector<const uc16> str)11955 bool String::IsTwoByteEqualTo(Vector<const uc16> str) {
11956 int slen = length();
11957 if (str.length() != slen) return false;
11958 DisallowHeapAllocation no_gc;
11959 FlatContent content = GetFlatContent();
11960 if (content.IsTwoByte()) {
11961 return CompareChars(content.ToUC16Vector().start(), str.start(), slen) == 0;
11962 }
11963 for (int i = 0; i < slen; i++) {
11964 if (Get(i) != str[i]) return false;
11965 }
11966 return true;
11967 }
11968
11969
ComputeAndSetHash()11970 uint32_t String::ComputeAndSetHash() {
11971 // Should only be called if hash code has not yet been computed.
11972 DCHECK(!HasHashCode());
11973
11974 // Store the hash code in the object.
11975 uint32_t field = IteratingStringHasher::Hash(this, GetHeap()->HashSeed());
11976 set_hash_field(field);
11977
11978 // Check the hash code is there.
11979 DCHECK(HasHashCode());
11980 uint32_t result = field >> kHashShift;
11981 DCHECK(result != 0); // Ensure that the hash value of 0 is never computed.
11982 return result;
11983 }
11984
11985
ComputeArrayIndex(uint32_t * index)11986 bool String::ComputeArrayIndex(uint32_t* index) {
11987 int length = this->length();
11988 if (length == 0 || length > kMaxArrayIndexSize) return false;
11989 StringCharacterStream stream(this);
11990 return StringToArrayIndex(&stream, index);
11991 }
11992
11993
SlowAsArrayIndex(uint32_t * index)11994 bool String::SlowAsArrayIndex(uint32_t* index) {
11995 if (length() <= kMaxCachedArrayIndexLength) {
11996 Hash(); // force computation of hash code
11997 uint32_t field = hash_field();
11998 if ((field & kIsNotArrayIndexMask) != 0) return false;
11999 // Isolate the array index form the full hash field.
12000 *index = ArrayIndexValueBits::decode(field);
12001 return true;
12002 } else {
12003 return ComputeArrayIndex(index);
12004 }
12005 }
12006
12007
Truncate(Handle<SeqString> string,int new_length)12008 Handle<String> SeqString::Truncate(Handle<SeqString> string, int new_length) {
12009 int new_size, old_size;
12010 int old_length = string->length();
12011 if (old_length <= new_length) return string;
12012
12013 if (string->IsSeqOneByteString()) {
12014 old_size = SeqOneByteString::SizeFor(old_length);
12015 new_size = SeqOneByteString::SizeFor(new_length);
12016 } else {
12017 DCHECK(string->IsSeqTwoByteString());
12018 old_size = SeqTwoByteString::SizeFor(old_length);
12019 new_size = SeqTwoByteString::SizeFor(new_length);
12020 }
12021
12022 int delta = old_size - new_size;
12023
12024 Address start_of_string = string->address();
12025 DCHECK_OBJECT_ALIGNED(start_of_string);
12026 DCHECK_OBJECT_ALIGNED(start_of_string + new_size);
12027
12028 Heap* heap = string->GetHeap();
12029 // Sizes are pointer size aligned, so that we can use filler objects
12030 // that are a multiple of pointer size.
12031 heap->CreateFillerObjectAt(start_of_string + new_size, delta,
12032 ClearRecordedSlots::kNo);
12033 heap->AdjustLiveBytes(*string, -delta, Heap::CONCURRENT_TO_SWEEPER);
12034
12035 // We are storing the new length using release store after creating a filler
12036 // for the left-over space to avoid races with the sweeper thread.
12037 string->synchronized_set_length(new_length);
12038
12039 if (new_length == 0) return heap->isolate()->factory()->empty_string();
12040 return string;
12041 }
12042
12043
MakeArrayIndexHash(uint32_t value,int length)12044 uint32_t StringHasher::MakeArrayIndexHash(uint32_t value, int length) {
12045 // For array indexes mix the length into the hash as an array index could
12046 // be zero.
12047 DCHECK(length > 0);
12048 DCHECK(length <= String::kMaxArrayIndexSize);
12049 DCHECK(TenToThe(String::kMaxCachedArrayIndexLength) <
12050 (1 << String::kArrayIndexValueBits));
12051
12052 value <<= String::ArrayIndexValueBits::kShift;
12053 value |= length << String::ArrayIndexLengthBits::kShift;
12054
12055 DCHECK((value & String::kIsNotArrayIndexMask) == 0);
12056 DCHECK_EQ(length <= String::kMaxCachedArrayIndexLength,
12057 (value & String::kContainsCachedArrayIndexMask) == 0);
12058 return value;
12059 }
12060
12061
GetHashField()12062 uint32_t StringHasher::GetHashField() {
12063 if (length_ <= String::kMaxHashCalcLength) {
12064 if (is_array_index_) {
12065 return MakeArrayIndexHash(array_index_, length_);
12066 }
12067 return (GetHashCore(raw_running_hash_) << String::kHashShift) |
12068 String::kIsNotArrayIndexMask;
12069 } else {
12070 return (length_ << String::kHashShift) | String::kIsNotArrayIndexMask;
12071 }
12072 }
12073
12074
ComputeUtf8Hash(Vector<const char> chars,uint32_t seed,int * utf16_length_out)12075 uint32_t StringHasher::ComputeUtf8Hash(Vector<const char> chars,
12076 uint32_t seed,
12077 int* utf16_length_out) {
12078 int vector_length = chars.length();
12079 // Handle some edge cases
12080 if (vector_length <= 1) {
12081 DCHECK(vector_length == 0 ||
12082 static_cast<uint8_t>(chars.start()[0]) <=
12083 unibrow::Utf8::kMaxOneByteChar);
12084 *utf16_length_out = vector_length;
12085 return HashSequentialString(chars.start(), vector_length, seed);
12086 }
12087 // Start with a fake length which won't affect computation.
12088 // It will be updated later.
12089 StringHasher hasher(String::kMaxArrayIndexSize, seed);
12090 size_t remaining = static_cast<size_t>(vector_length);
12091 const uint8_t* stream = reinterpret_cast<const uint8_t*>(chars.start());
12092 int utf16_length = 0;
12093 bool is_index = true;
12094 DCHECK(hasher.is_array_index_);
12095 while (remaining > 0) {
12096 size_t consumed = 0;
12097 uint32_t c = unibrow::Utf8::ValueOf(stream, remaining, &consumed);
12098 DCHECK(consumed > 0 && consumed <= remaining);
12099 stream += consumed;
12100 remaining -= consumed;
12101 bool is_two_characters = c > unibrow::Utf16::kMaxNonSurrogateCharCode;
12102 utf16_length += is_two_characters ? 2 : 1;
12103 // No need to keep hashing. But we do need to calculate utf16_length.
12104 if (utf16_length > String::kMaxHashCalcLength) continue;
12105 if (is_two_characters) {
12106 uint16_t c1 = unibrow::Utf16::LeadSurrogate(c);
12107 uint16_t c2 = unibrow::Utf16::TrailSurrogate(c);
12108 hasher.AddCharacter(c1);
12109 hasher.AddCharacter(c2);
12110 if (is_index) is_index = hasher.UpdateIndex(c1);
12111 if (is_index) is_index = hasher.UpdateIndex(c2);
12112 } else {
12113 hasher.AddCharacter(c);
12114 if (is_index) is_index = hasher.UpdateIndex(c);
12115 }
12116 }
12117 *utf16_length_out = static_cast<int>(utf16_length);
12118 // Must set length here so that hash computation is correct.
12119 hasher.length_ = utf16_length;
12120 return hasher.GetHashField();
12121 }
12122
12123
VisitConsString(ConsString * cons_string)12124 void IteratingStringHasher::VisitConsString(ConsString* cons_string) {
12125 // Run small ConsStrings through ConsStringIterator.
12126 if (cons_string->length() < 64) {
12127 ConsStringIterator iter(cons_string);
12128 int offset;
12129 String* string;
12130 while (nullptr != (string = iter.Next(&offset))) {
12131 DCHECK_EQ(0, offset);
12132 String::VisitFlat(this, string, 0);
12133 }
12134 return;
12135 }
12136 // Slow case.
12137 const int max_length = String::kMaxHashCalcLength;
12138 int length = std::min(cons_string->length(), max_length);
12139 if (cons_string->HasOnlyOneByteChars()) {
12140 uint8_t* buffer = new uint8_t[length];
12141 String::WriteToFlat(cons_string, buffer, 0, length);
12142 AddCharacters(buffer, length);
12143 delete[] buffer;
12144 } else {
12145 uint16_t* buffer = new uint16_t[length];
12146 String::WriteToFlat(cons_string, buffer, 0, length);
12147 AddCharacters(buffer, length);
12148 delete[] buffer;
12149 }
12150 }
12151
12152
PrintOn(FILE * file)12153 void String::PrintOn(FILE* file) {
12154 int length = this->length();
12155 for (int i = 0; i < length; i++) {
12156 PrintF(file, "%c", Get(i));
12157 }
12158 }
12159
12160
Hash()12161 int Map::Hash() {
12162 // For performance reasons we only hash the 3 most variable fields of a map:
12163 // constructor, prototype and bit_field2. For predictability reasons we
12164 // use objects' offsets in respective pages for hashing instead of raw
12165 // addresses.
12166
12167 // Shift away the tag.
12168 int hash = ObjectAddressForHashing(GetConstructor()) >> 2;
12169
12170 // XOR-ing the prototype and constructor directly yields too many zero bits
12171 // when the two pointers are close (which is fairly common).
12172 // To avoid this we shift the prototype bits relatively to the constructor.
12173 hash ^= ObjectAddressForHashing(prototype()) << (32 - kPageSizeBits);
12174
12175 return hash ^ (hash >> 16) ^ bit_field2();
12176 }
12177
12178
12179 namespace {
12180
CheckEquivalent(Map * first,Map * second)12181 bool CheckEquivalent(Map* first, Map* second) {
12182 return first->GetConstructor() == second->GetConstructor() &&
12183 first->prototype() == second->prototype() &&
12184 first->instance_type() == second->instance_type() &&
12185 first->bit_field() == second->bit_field() &&
12186 first->is_extensible() == second->is_extensible() &&
12187 first->new_target_is_base() == second->new_target_is_base() &&
12188 first->has_hidden_prototype() == second->has_hidden_prototype();
12189 }
12190
12191 } // namespace
12192
12193
EquivalentToForTransition(Map * other)12194 bool Map::EquivalentToForTransition(Map* other) {
12195 if (!CheckEquivalent(this, other)) return false;
12196 if (instance_type() == JS_FUNCTION_TYPE) {
12197 // JSFunctions require more checks to ensure that sloppy function is
12198 // not equvalent to strict function.
12199 int nof = Min(NumberOfOwnDescriptors(), other->NumberOfOwnDescriptors());
12200 return instance_descriptors()->IsEqualUpTo(other->instance_descriptors(),
12201 nof);
12202 }
12203 return true;
12204 }
12205
12206
EquivalentToForNormalization(Map * other,PropertyNormalizationMode mode)12207 bool Map::EquivalentToForNormalization(Map* other,
12208 PropertyNormalizationMode mode) {
12209 int properties =
12210 mode == CLEAR_INOBJECT_PROPERTIES ? 0 : other->GetInObjectProperties();
12211 return CheckEquivalent(this, other) && bit_field2() == other->bit_field2() &&
12212 GetInObjectProperties() == properties;
12213 }
12214
12215
Inlines(SharedFunctionInfo * candidate)12216 bool JSFunction::Inlines(SharedFunctionInfo* candidate) {
12217 DisallowHeapAllocation no_gc;
12218 if (shared() == candidate) return true;
12219 if (code()->kind() != Code::OPTIMIZED_FUNCTION) return false;
12220 DeoptimizationInputData* const data =
12221 DeoptimizationInputData::cast(code()->deoptimization_data());
12222 if (data->length() == 0) return false;
12223 FixedArray* const literals = data->LiteralArray();
12224 int const inlined_count = data->InlinedFunctionCount()->value();
12225 for (int i = 0; i < inlined_count; ++i) {
12226 if (SharedFunctionInfo::cast(literals->get(i)) == candidate) {
12227 return true;
12228 }
12229 }
12230 return false;
12231 }
12232
MarkForBaseline()12233 void JSFunction::MarkForBaseline() {
12234 Isolate* isolate = GetIsolate();
12235 set_code_no_write_barrier(
12236 isolate->builtins()->builtin(Builtins::kCompileBaseline));
12237 // No write barrier required, since the builtin is part of the root set.
12238 if (FLAG_mark_shared_functions_for_tier_up) {
12239 shared()->set_marked_for_tier_up(true);
12240 }
12241 }
12242
MarkForOptimization()12243 void JSFunction::MarkForOptimization() {
12244 Isolate* isolate = GetIsolate();
12245 DCHECK(!IsOptimized());
12246 DCHECK(shared()->allows_lazy_compilation() ||
12247 !shared()->optimization_disabled());
12248 set_code_no_write_barrier(
12249 isolate->builtins()->builtin(Builtins::kCompileOptimized));
12250 // No write barrier required, since the builtin is part of the root set.
12251 if (FLAG_mark_shared_functions_for_tier_up) {
12252 shared()->set_marked_for_tier_up(true);
12253 }
12254 }
12255
12256
AttemptConcurrentOptimization()12257 void JSFunction::AttemptConcurrentOptimization() {
12258 Isolate* isolate = GetIsolate();
12259 if (!isolate->concurrent_recompilation_enabled() ||
12260 isolate->bootstrapper()->IsActive()) {
12261 MarkForOptimization();
12262 return;
12263 }
12264 DCHECK(!IsInOptimizationQueue());
12265 DCHECK(!IsOptimized());
12266 DCHECK(shared()->allows_lazy_compilation() ||
12267 !shared()->optimization_disabled());
12268 DCHECK(isolate->concurrent_recompilation_enabled());
12269 if (FLAG_trace_concurrent_recompilation) {
12270 PrintF(" ** Marking ");
12271 ShortPrint();
12272 PrintF(" for concurrent recompilation.\n");
12273 }
12274
12275 set_code_no_write_barrier(
12276 isolate->builtins()->builtin(Builtins::kCompileOptimizedConcurrent));
12277 // No write barrier required, since the builtin is part of the root set.
12278 if (FLAG_mark_shared_functions_for_tier_up) {
12279 // TODO(leszeks): The compilation isn't concurrent if we trigger it using
12280 // this bit.
12281 shared()->set_marked_for_tier_up(true);
12282 }
12283 }
12284
12285 // static
FindOrCreateLiterals(Handle<SharedFunctionInfo> shared,Handle<Context> native_context)12286 Handle<LiteralsArray> SharedFunctionInfo::FindOrCreateLiterals(
12287 Handle<SharedFunctionInfo> shared, Handle<Context> native_context) {
12288 Isolate* isolate = shared->GetIsolate();
12289 CodeAndLiterals result =
12290 shared->SearchOptimizedCodeMap(*native_context, BailoutId::None());
12291 if (result.literals != nullptr) {
12292 DCHECK(shared->feedback_metadata()->is_empty() ||
12293 !result.literals->feedback_vector()->is_empty());
12294 return handle(result.literals, isolate);
12295 }
12296
12297 Handle<TypeFeedbackVector> feedback_vector =
12298 TypeFeedbackVector::New(isolate, handle(shared->feedback_metadata()));
12299 Handle<LiteralsArray> literals =
12300 LiteralsArray::New(isolate, feedback_vector, shared->num_literals());
12301 Handle<Code> code;
12302 if (result.code != nullptr) {
12303 code = Handle<Code>(result.code, isolate);
12304 }
12305 AddToOptimizedCodeMap(shared, native_context, code, literals,
12306 BailoutId::None());
12307 return literals;
12308 }
12309
12310 // static
AddToOptimizedCodeMap(Handle<SharedFunctionInfo> shared,Handle<Context> native_context,MaybeHandle<Code> code,Handle<LiteralsArray> literals,BailoutId osr_ast_id)12311 void SharedFunctionInfo::AddToOptimizedCodeMap(
12312 Handle<SharedFunctionInfo> shared, Handle<Context> native_context,
12313 MaybeHandle<Code> code, Handle<LiteralsArray> literals,
12314 BailoutId osr_ast_id) {
12315 Isolate* isolate = shared->GetIsolate();
12316 if (isolate->serializer_enabled()) return;
12317 DCHECK(code.is_null() ||
12318 code.ToHandleChecked()->kind() == Code::OPTIMIZED_FUNCTION);
12319 DCHECK(native_context->IsNativeContext());
12320 STATIC_ASSERT(kEntryLength == 4);
12321 Handle<FixedArray> new_code_map;
12322 int entry;
12323
12324 if (shared->OptimizedCodeMapIsCleared()) {
12325 new_code_map = isolate->factory()->NewFixedArray(kInitialLength, TENURED);
12326 entry = kEntriesStart;
12327 } else {
12328 Handle<FixedArray> old_code_map(shared->optimized_code_map(), isolate);
12329 entry = shared->SearchOptimizedCodeMapEntry(*native_context, osr_ast_id);
12330 if (entry >= kEntriesStart) {
12331 // Just set the code and literals of the entry.
12332 if (!code.is_null()) {
12333 Handle<WeakCell> code_cell =
12334 isolate->factory()->NewWeakCell(code.ToHandleChecked());
12335 old_code_map->set(entry + kCachedCodeOffset, *code_cell);
12336 }
12337 Handle<WeakCell> literals_cell =
12338 isolate->factory()->NewWeakCell(literals);
12339 old_code_map->set(entry + kLiteralsOffset, *literals_cell);
12340 return;
12341 }
12342
12343 // Can we reuse an entry?
12344 DCHECK(entry < kEntriesStart);
12345 int length = old_code_map->length();
12346 for (int i = kEntriesStart; i < length; i += kEntryLength) {
12347 if (WeakCell::cast(old_code_map->get(i + kContextOffset))->cleared()) {
12348 new_code_map = old_code_map;
12349 entry = i;
12350 break;
12351 }
12352 }
12353
12354 if (entry < kEntriesStart) {
12355 // Copy old optimized code map and append one new entry.
12356 new_code_map = isolate->factory()->CopyFixedArrayAndGrow(
12357 old_code_map, kEntryLength, TENURED);
12358 // TODO(mstarzinger): Temporary workaround. The allocation above might
12359 // have flushed the optimized code map and the copy we created is full of
12360 // holes. For now we just give up on adding the entry and pretend it got
12361 // flushed.
12362 if (shared->OptimizedCodeMapIsCleared()) return;
12363 entry = old_code_map->length();
12364 }
12365 }
12366
12367 Handle<WeakCell> code_cell =
12368 code.is_null() ? isolate->factory()->empty_weak_cell()
12369 : isolate->factory()->NewWeakCell(code.ToHandleChecked());
12370 Handle<WeakCell> literals_cell = isolate->factory()->NewWeakCell(literals);
12371 WeakCell* context_cell = native_context->self_weak_cell();
12372
12373 new_code_map->set(entry + kContextOffset, context_cell);
12374 new_code_map->set(entry + kCachedCodeOffset, *code_cell);
12375 new_code_map->set(entry + kLiteralsOffset, *literals_cell);
12376 new_code_map->set(entry + kOsrAstIdOffset, Smi::FromInt(osr_ast_id.ToInt()));
12377
12378 #ifdef DEBUG
12379 for (int i = kEntriesStart; i < new_code_map->length(); i += kEntryLength) {
12380 WeakCell* cell = WeakCell::cast(new_code_map->get(i + kContextOffset));
12381 DCHECK(cell->cleared() || cell->value()->IsNativeContext());
12382 cell = WeakCell::cast(new_code_map->get(i + kCachedCodeOffset));
12383 DCHECK(cell->cleared() ||
12384 (cell->value()->IsCode() &&
12385 Code::cast(cell->value())->kind() == Code::OPTIMIZED_FUNCTION));
12386 cell = WeakCell::cast(new_code_map->get(i + kLiteralsOffset));
12387 DCHECK(cell->cleared() || cell->value()->IsFixedArray());
12388 DCHECK(new_code_map->get(i + kOsrAstIdOffset)->IsSmi());
12389 }
12390 #endif
12391
12392 FixedArray* old_code_map = shared->optimized_code_map();
12393 if (old_code_map != *new_code_map) {
12394 shared->set_optimized_code_map(*new_code_map);
12395 }
12396 }
12397
12398
ClearOptimizedCodeMap()12399 void SharedFunctionInfo::ClearOptimizedCodeMap() {
12400 FixedArray* empty_fixed_array = GetHeap()->empty_fixed_array();
12401 set_optimized_code_map(empty_fixed_array, SKIP_WRITE_BARRIER);
12402 }
12403
12404
EvictFromOptimizedCodeMap(Code * optimized_code,const char * reason)12405 void SharedFunctionInfo::EvictFromOptimizedCodeMap(Code* optimized_code,
12406 const char* reason) {
12407 DisallowHeapAllocation no_gc;
12408 if (OptimizedCodeMapIsCleared()) return;
12409
12410 Heap* heap = GetHeap();
12411 FixedArray* code_map = optimized_code_map();
12412 int dst = kEntriesStart;
12413 int length = code_map->length();
12414 for (int src = kEntriesStart; src < length; src += kEntryLength) {
12415 DCHECK(WeakCell::cast(code_map->get(src))->cleared() ||
12416 WeakCell::cast(code_map->get(src))->value()->IsNativeContext());
12417 if (WeakCell::cast(code_map->get(src + kCachedCodeOffset))->value() ==
12418 optimized_code) {
12419 BailoutId osr(Smi::cast(code_map->get(src + kOsrAstIdOffset))->value());
12420 if (FLAG_trace_opt) {
12421 PrintF("[evicting entry from optimizing code map (%s) for ", reason);
12422 ShortPrint();
12423 if (osr.IsNone()) {
12424 PrintF("]\n");
12425 } else {
12426 PrintF(" (osr ast id %d)]\n", osr.ToInt());
12427 }
12428 }
12429 if (!osr.IsNone()) {
12430 // Evict the src entry by not copying it to the dst entry.
12431 continue;
12432 }
12433 // In case of non-OSR entry just clear the code in order to proceed
12434 // sharing literals.
12435 code_map->set(src + kCachedCodeOffset, heap->empty_weak_cell(),
12436 SKIP_WRITE_BARRIER);
12437 }
12438
12439 // Keep the src entry by copying it to the dst entry.
12440 if (dst != src) {
12441 code_map->set(dst + kContextOffset, code_map->get(src + kContextOffset));
12442 code_map->set(dst + kCachedCodeOffset,
12443 code_map->get(src + kCachedCodeOffset));
12444 code_map->set(dst + kLiteralsOffset,
12445 code_map->get(src + kLiteralsOffset));
12446 code_map->set(dst + kOsrAstIdOffset,
12447 code_map->get(src + kOsrAstIdOffset));
12448 }
12449 dst += kEntryLength;
12450 }
12451 if (dst != length) {
12452 // Always trim even when array is cleared because of heap verifier.
12453 heap->RightTrimFixedArray<Heap::CONCURRENT_TO_SWEEPER>(code_map,
12454 length - dst);
12455 if (code_map->length() == kEntriesStart) {
12456 ClearOptimizedCodeMap();
12457 }
12458 }
12459 }
12460
12461
TrimOptimizedCodeMap(int shrink_by)12462 void SharedFunctionInfo::TrimOptimizedCodeMap(int shrink_by) {
12463 FixedArray* code_map = optimized_code_map();
12464 DCHECK(shrink_by % kEntryLength == 0);
12465 DCHECK(shrink_by <= code_map->length() - kEntriesStart);
12466 // Always trim even when array is cleared because of heap verifier.
12467 GetHeap()->RightTrimFixedArray<Heap::SEQUENTIAL_TO_SWEEPER>(code_map,
12468 shrink_by);
12469 if (code_map->length() == kEntriesStart) {
12470 ClearOptimizedCodeMap();
12471 }
12472 }
12473
12474 // static
EnsureLiterals(Handle<JSFunction> function)12475 void JSFunction::EnsureLiterals(Handle<JSFunction> function) {
12476 Handle<SharedFunctionInfo> shared(function->shared());
12477 Handle<Context> native_context(function->context()->native_context());
12478 if (function->literals() ==
12479 function->GetIsolate()->heap()->empty_literals_array()) {
12480 Handle<LiteralsArray> literals =
12481 SharedFunctionInfo::FindOrCreateLiterals(shared, native_context);
12482 function->set_literals(*literals);
12483 }
12484 }
12485
GetMinInobjectSlack(Map * map,void * data)12486 static void GetMinInobjectSlack(Map* map, void* data) {
12487 int slack = map->unused_property_fields();
12488 if (*reinterpret_cast<int*>(data) > slack) {
12489 *reinterpret_cast<int*>(data) = slack;
12490 }
12491 }
12492
12493
ShrinkInstanceSize(Map * map,void * data)12494 static void ShrinkInstanceSize(Map* map, void* data) {
12495 int slack = *reinterpret_cast<int*>(data);
12496 map->SetInObjectProperties(map->GetInObjectProperties() - slack);
12497 map->set_unused_property_fields(map->unused_property_fields() - slack);
12498 map->set_instance_size(map->instance_size() - slack * kPointerSize);
12499 map->set_construction_counter(Map::kNoSlackTracking);
12500
12501 // Visitor id might depend on the instance size, recalculate it.
12502 map->set_visitor_id(Heap::GetStaticVisitorIdForMap(map));
12503 }
12504
StopSlackTracking(Map * map,void * data)12505 static void StopSlackTracking(Map* map, void* data) {
12506 map->set_construction_counter(Map::kNoSlackTracking);
12507 }
12508
CompleteInobjectSlackTracking()12509 void Map::CompleteInobjectSlackTracking() {
12510 // Has to be an initial map.
12511 DCHECK(GetBackPointer()->IsUndefined(GetIsolate()));
12512
12513 int slack = unused_property_fields();
12514 TransitionArray::TraverseTransitionTree(this, &GetMinInobjectSlack, &slack);
12515 if (slack != 0) {
12516 // Resize the initial map and all maps in its transition tree.
12517 TransitionArray::TraverseTransitionTree(this, &ShrinkInstanceSize, &slack);
12518 } else {
12519 TransitionArray::TraverseTransitionTree(this, &StopSlackTracking, nullptr);
12520 }
12521 }
12522
12523
PrototypeBenefitsFromNormalization(Handle<JSObject> object)12524 static bool PrototypeBenefitsFromNormalization(Handle<JSObject> object) {
12525 DisallowHeapAllocation no_gc;
12526 if (!object->HasFastProperties()) return false;
12527 Map* map = object->map();
12528 if (map->is_prototype_map()) return false;
12529 DescriptorArray* descriptors = map->instance_descriptors();
12530 for (int i = 0; i < map->NumberOfOwnDescriptors(); i++) {
12531 PropertyDetails details = descriptors->GetDetails(i);
12532 if (details.location() == kDescriptor) continue;
12533 if (details.representation().IsHeapObject() ||
12534 details.representation().IsTagged()) {
12535 FieldIndex index = FieldIndex::ForDescriptor(map, i);
12536 if (object->RawFastPropertyAt(index)->IsJSFunction()) return true;
12537 }
12538 }
12539 return false;
12540 }
12541
12542 // static
MakePrototypesFast(Handle<Object> receiver,WhereToStart where_to_start,Isolate * isolate)12543 void JSObject::MakePrototypesFast(Handle<Object> receiver,
12544 WhereToStart where_to_start,
12545 Isolate* isolate) {
12546 if (!receiver->IsJSReceiver()) return;
12547 for (PrototypeIterator iter(isolate, Handle<JSReceiver>::cast(receiver),
12548 where_to_start);
12549 !iter.IsAtEnd(); iter.Advance()) {
12550 Handle<Object> current = PrototypeIterator::GetCurrent(iter);
12551 if (!current->IsJSObject()) return;
12552 Handle<JSObject> current_obj = Handle<JSObject>::cast(current);
12553 Map* current_map = current_obj->map();
12554 if (current_map->is_prototype_map() &&
12555 !current_map->should_be_fast_prototype_map()) {
12556 Handle<Map> map(current_map);
12557 Map::SetShouldBeFastPrototypeMap(map, true, isolate);
12558 JSObject::OptimizeAsPrototype(current_obj, FAST_PROTOTYPE);
12559 }
12560 }
12561 }
12562
12563 // static
OptimizeAsPrototype(Handle<JSObject> object,PrototypeOptimizationMode mode)12564 void JSObject::OptimizeAsPrototype(Handle<JSObject> object,
12565 PrototypeOptimizationMode mode) {
12566 if (object->IsJSGlobalObject()) return;
12567 if (mode == FAST_PROTOTYPE && PrototypeBenefitsFromNormalization(object)) {
12568 // First normalize to ensure all JSFunctions are DATA_CONSTANT.
12569 JSObject::NormalizeProperties(object, KEEP_INOBJECT_PROPERTIES, 0,
12570 "NormalizeAsPrototype");
12571 }
12572 Handle<Map> previous_map(object->map());
12573 if (object->map()->is_prototype_map()) {
12574 if (object->map()->should_be_fast_prototype_map() &&
12575 !object->HasFastProperties()) {
12576 JSObject::MigrateSlowToFast(object, 0, "OptimizeAsPrototype");
12577 }
12578 } else {
12579 if (object->map() == *previous_map) {
12580 Handle<Map> new_map = Map::Copy(handle(object->map()), "CopyAsPrototype");
12581 JSObject::MigrateToMap(object, new_map);
12582 }
12583 object->map()->set_is_prototype_map(true);
12584
12585 // Replace the pointer to the exact constructor with the Object function
12586 // from the same context if undetectable from JS. This is to avoid keeping
12587 // memory alive unnecessarily.
12588 Object* maybe_constructor = object->map()->GetConstructor();
12589 if (maybe_constructor->IsJSFunction()) {
12590 JSFunction* constructor = JSFunction::cast(maybe_constructor);
12591 Isolate* isolate = object->GetIsolate();
12592 if (!constructor->shared()->IsApiFunction() &&
12593 object->class_name() == isolate->heap()->Object_string()) {
12594 Context* context = constructor->context()->native_context();
12595 JSFunction* object_function = context->object_function();
12596 object->map()->SetConstructor(object_function);
12597 }
12598 }
12599 }
12600 }
12601
12602
12603 // static
ReoptimizeIfPrototype(Handle<JSObject> object)12604 void JSObject::ReoptimizeIfPrototype(Handle<JSObject> object) {
12605 if (!object->map()->is_prototype_map()) return;
12606 if (!object->map()->should_be_fast_prototype_map()) return;
12607 OptimizeAsPrototype(object, FAST_PROTOTYPE);
12608 }
12609
12610
12611 // static
LazyRegisterPrototypeUser(Handle<Map> user,Isolate * isolate)12612 void JSObject::LazyRegisterPrototypeUser(Handle<Map> user, Isolate* isolate) {
12613 // Contract: In line with InvalidatePrototypeChains()'s requirements,
12614 // leaf maps don't need to register as users, only prototypes do.
12615 DCHECK(user->is_prototype_map());
12616
12617 Handle<Map> current_user = user;
12618 Handle<PrototypeInfo> current_user_info =
12619 Map::GetOrCreatePrototypeInfo(user, isolate);
12620 for (PrototypeIterator iter(user); !iter.IsAtEnd(); iter.Advance()) {
12621 // Walk up the prototype chain as far as links haven't been registered yet.
12622 if (current_user_info->registry_slot() != PrototypeInfo::UNREGISTERED) {
12623 break;
12624 }
12625 Handle<Object> maybe_proto = PrototypeIterator::GetCurrent(iter);
12626 // Proxies on the prototype chain are not supported. They make it
12627 // impossible to make any assumptions about the prototype chain anyway.
12628 if (maybe_proto->IsJSProxy()) return;
12629 Handle<JSObject> proto = Handle<JSObject>::cast(maybe_proto);
12630 Handle<PrototypeInfo> proto_info =
12631 Map::GetOrCreatePrototypeInfo(proto, isolate);
12632 Handle<Object> maybe_registry(proto_info->prototype_users(), isolate);
12633 int slot = 0;
12634 Handle<WeakFixedArray> new_array =
12635 WeakFixedArray::Add(maybe_registry, current_user, &slot);
12636 current_user_info->set_registry_slot(slot);
12637 if (!maybe_registry.is_identical_to(new_array)) {
12638 proto_info->set_prototype_users(*new_array);
12639 }
12640 if (FLAG_trace_prototype_users) {
12641 PrintF("Registering %p as a user of prototype %p (map=%p).\n",
12642 reinterpret_cast<void*>(*current_user),
12643 reinterpret_cast<void*>(*proto),
12644 reinterpret_cast<void*>(proto->map()));
12645 }
12646
12647 current_user = handle(proto->map(), isolate);
12648 current_user_info = proto_info;
12649 }
12650 }
12651
12652
12653 // Can be called regardless of whether |user| was actually registered with
12654 // |prototype|. Returns true when there was a registration.
12655 // static
UnregisterPrototypeUser(Handle<Map> user,Isolate * isolate)12656 bool JSObject::UnregisterPrototypeUser(Handle<Map> user, Isolate* isolate) {
12657 DCHECK(user->is_prototype_map());
12658 // If it doesn't have a PrototypeInfo, it was never registered.
12659 if (!user->prototype_info()->IsPrototypeInfo()) return false;
12660 // If it had no prototype before, see if it had users that might expect
12661 // registration.
12662 if (!user->prototype()->IsJSObject()) {
12663 Object* users =
12664 PrototypeInfo::cast(user->prototype_info())->prototype_users();
12665 return users->IsWeakFixedArray();
12666 }
12667 Handle<JSObject> prototype(JSObject::cast(user->prototype()), isolate);
12668 Handle<PrototypeInfo> user_info =
12669 Map::GetOrCreatePrototypeInfo(user, isolate);
12670 int slot = user_info->registry_slot();
12671 if (slot == PrototypeInfo::UNREGISTERED) return false;
12672 DCHECK(prototype->map()->is_prototype_map());
12673 Object* maybe_proto_info = prototype->map()->prototype_info();
12674 // User knows its registry slot, prototype info and user registry must exist.
12675 DCHECK(maybe_proto_info->IsPrototypeInfo());
12676 Handle<PrototypeInfo> proto_info(PrototypeInfo::cast(maybe_proto_info),
12677 isolate);
12678 Object* maybe_registry = proto_info->prototype_users();
12679 DCHECK(maybe_registry->IsWeakFixedArray());
12680 DCHECK(WeakFixedArray::cast(maybe_registry)->Get(slot) == *user);
12681 WeakFixedArray::cast(maybe_registry)->Clear(slot);
12682 if (FLAG_trace_prototype_users) {
12683 PrintF("Unregistering %p as a user of prototype %p.\n",
12684 reinterpret_cast<void*>(*user), reinterpret_cast<void*>(*prototype));
12685 }
12686 return true;
12687 }
12688
12689
InvalidatePrototypeChainsInternal(Map * map)12690 static void InvalidatePrototypeChainsInternal(Map* map) {
12691 DCHECK(map->is_prototype_map());
12692 if (FLAG_trace_prototype_users) {
12693 PrintF("Invalidating prototype map %p 's cell\n",
12694 reinterpret_cast<void*>(map));
12695 }
12696 Object* maybe_proto_info = map->prototype_info();
12697 if (!maybe_proto_info->IsPrototypeInfo()) return;
12698 PrototypeInfo* proto_info = PrototypeInfo::cast(maybe_proto_info);
12699 Object* maybe_cell = proto_info->validity_cell();
12700 if (maybe_cell->IsCell()) {
12701 // Just set the value; the cell will be replaced lazily.
12702 Cell* cell = Cell::cast(maybe_cell);
12703 cell->set_value(Smi::FromInt(Map::kPrototypeChainInvalid));
12704 }
12705
12706 WeakFixedArray::Iterator iterator(proto_info->prototype_users());
12707 // For now, only maps register themselves as users.
12708 Map* user;
12709 while ((user = iterator.Next<Map>())) {
12710 // Walk the prototype chain (backwards, towards leaf objects) if necessary.
12711 InvalidatePrototypeChainsInternal(user);
12712 }
12713 }
12714
12715
12716 // static
InvalidatePrototypeChains(Map * map)12717 void JSObject::InvalidatePrototypeChains(Map* map) {
12718 DisallowHeapAllocation no_gc;
12719 InvalidatePrototypeChainsInternal(map);
12720 }
12721
12722
12723 // static
GetOrCreatePrototypeInfo(Handle<JSObject> prototype,Isolate * isolate)12724 Handle<PrototypeInfo> Map::GetOrCreatePrototypeInfo(Handle<JSObject> prototype,
12725 Isolate* isolate) {
12726 Object* maybe_proto_info = prototype->map()->prototype_info();
12727 if (maybe_proto_info->IsPrototypeInfo()) {
12728 return handle(PrototypeInfo::cast(maybe_proto_info), isolate);
12729 }
12730 Handle<PrototypeInfo> proto_info = isolate->factory()->NewPrototypeInfo();
12731 prototype->map()->set_prototype_info(*proto_info);
12732 return proto_info;
12733 }
12734
12735
12736 // static
GetOrCreatePrototypeInfo(Handle<Map> prototype_map,Isolate * isolate)12737 Handle<PrototypeInfo> Map::GetOrCreatePrototypeInfo(Handle<Map> prototype_map,
12738 Isolate* isolate) {
12739 Object* maybe_proto_info = prototype_map->prototype_info();
12740 if (maybe_proto_info->IsPrototypeInfo()) {
12741 return handle(PrototypeInfo::cast(maybe_proto_info), isolate);
12742 }
12743 Handle<PrototypeInfo> proto_info = isolate->factory()->NewPrototypeInfo();
12744 prototype_map->set_prototype_info(*proto_info);
12745 return proto_info;
12746 }
12747
12748 // static
SetShouldBeFastPrototypeMap(Handle<Map> map,bool value,Isolate * isolate)12749 void Map::SetShouldBeFastPrototypeMap(Handle<Map> map, bool value,
12750 Isolate* isolate) {
12751 if (value == false && !map->prototype_info()->IsPrototypeInfo()) {
12752 // "False" is the implicit default value, so there's nothing to do.
12753 return;
12754 }
12755 GetOrCreatePrototypeInfo(map, isolate)->set_should_be_fast_map(value);
12756 }
12757
12758 // static
GetOrCreatePrototypeChainValidityCell(Handle<Map> map,Isolate * isolate)12759 Handle<Cell> Map::GetOrCreatePrototypeChainValidityCell(Handle<Map> map,
12760 Isolate* isolate) {
12761 Handle<Object> maybe_prototype(
12762 map->GetPrototypeChainRootMap(isolate)->prototype(), isolate);
12763 if (!maybe_prototype->IsJSObject()) return Handle<Cell>::null();
12764 Handle<JSObject> prototype = Handle<JSObject>::cast(maybe_prototype);
12765 // Ensure the prototype is registered with its own prototypes so its cell
12766 // will be invalidated when necessary.
12767 JSObject::LazyRegisterPrototypeUser(handle(prototype->map(), isolate),
12768 isolate);
12769 Handle<PrototypeInfo> proto_info =
12770 GetOrCreatePrototypeInfo(prototype, isolate);
12771 Object* maybe_cell = proto_info->validity_cell();
12772 // Return existing cell if it's still valid.
12773 if (maybe_cell->IsCell()) {
12774 Handle<Cell> cell(Cell::cast(maybe_cell), isolate);
12775 if (cell->value() == Smi::FromInt(Map::kPrototypeChainValid)) {
12776 return cell;
12777 }
12778 }
12779 // Otherwise create a new cell.
12780 Handle<Cell> cell = isolate->factory()->NewCell(
12781 handle(Smi::FromInt(Map::kPrototypeChainValid), isolate));
12782 proto_info->set_validity_cell(*cell);
12783 return cell;
12784 }
12785
12786 // static
GetOrCreatePrototypeWeakCell(Handle<JSObject> prototype,Isolate * isolate)12787 Handle<WeakCell> Map::GetOrCreatePrototypeWeakCell(Handle<JSObject> prototype,
12788 Isolate* isolate) {
12789 DCHECK(!prototype.is_null());
12790 Handle<PrototypeInfo> proto_info =
12791 GetOrCreatePrototypeInfo(prototype, isolate);
12792 Object* maybe_cell = proto_info->weak_cell();
12793 // Return existing cell if it's already created.
12794 if (maybe_cell->IsWeakCell()) {
12795 Handle<WeakCell> cell(WeakCell::cast(maybe_cell), isolate);
12796 DCHECK(!cell->cleared());
12797 return cell;
12798 }
12799 // Otherwise create a new cell.
12800 Handle<WeakCell> cell = isolate->factory()->NewWeakCell(prototype);
12801 proto_info->set_weak_cell(*cell);
12802 return cell;
12803 }
12804
12805 // static
SetPrototype(Handle<Map> map,Handle<Object> prototype,PrototypeOptimizationMode proto_mode)12806 void Map::SetPrototype(Handle<Map> map, Handle<Object> prototype,
12807 PrototypeOptimizationMode proto_mode) {
12808 RuntimeCallTimerScope stats_scope(*map, &RuntimeCallStats::Map_SetPrototype);
12809
12810 bool is_hidden = false;
12811 if (prototype->IsJSObject()) {
12812 Handle<JSObject> prototype_jsobj = Handle<JSObject>::cast(prototype);
12813 JSObject::OptimizeAsPrototype(prototype_jsobj, proto_mode);
12814
12815 Object* maybe_constructor = prototype_jsobj->map()->GetConstructor();
12816 if (maybe_constructor->IsJSFunction()) {
12817 JSFunction* constructor = JSFunction::cast(maybe_constructor);
12818 Object* data = constructor->shared()->function_data();
12819 is_hidden = (data->IsFunctionTemplateInfo() &&
12820 FunctionTemplateInfo::cast(data)->hidden_prototype()) ||
12821 prototype->IsJSGlobalObject();
12822 }
12823 }
12824 map->set_has_hidden_prototype(is_hidden);
12825
12826 WriteBarrierMode wb_mode = prototype->IsNull(map->GetIsolate())
12827 ? SKIP_WRITE_BARRIER
12828 : UPDATE_WRITE_BARRIER;
12829 map->set_prototype(*prototype, wb_mode);
12830 }
12831
12832
CacheInitialJSArrayMaps(Handle<Context> native_context,Handle<Map> initial_map)12833 Handle<Object> CacheInitialJSArrayMaps(
12834 Handle<Context> native_context, Handle<Map> initial_map) {
12835 // Replace all of the cached initial array maps in the native context with
12836 // the appropriate transitioned elements kind maps.
12837 Handle<Map> current_map = initial_map;
12838 ElementsKind kind = current_map->elements_kind();
12839 DCHECK_EQ(GetInitialFastElementsKind(), kind);
12840 native_context->set(Context::ArrayMapIndex(kind), *current_map);
12841 for (int i = GetSequenceIndexFromFastElementsKind(kind) + 1;
12842 i < kFastElementsKindCount; ++i) {
12843 Handle<Map> new_map;
12844 ElementsKind next_kind = GetFastElementsKindFromSequenceIndex(i);
12845 if (Map* maybe_elements_transition = current_map->ElementsTransitionMap()) {
12846 new_map = handle(maybe_elements_transition);
12847 } else {
12848 new_map = Map::CopyAsElementsKind(
12849 current_map, next_kind, INSERT_TRANSITION);
12850 }
12851 DCHECK_EQ(next_kind, new_map->elements_kind());
12852 native_context->set(Context::ArrayMapIndex(next_kind), *new_map);
12853 current_map = new_map;
12854 }
12855 return initial_map;
12856 }
12857
12858
SetInstancePrototype(Handle<JSFunction> function,Handle<Object> value)12859 void JSFunction::SetInstancePrototype(Handle<JSFunction> function,
12860 Handle<Object> value) {
12861 Isolate* isolate = function->GetIsolate();
12862
12863 DCHECK(value->IsJSReceiver());
12864
12865 // Now some logic for the maps of the objects that are created by using this
12866 // function as a constructor.
12867 if (function->has_initial_map()) {
12868 // If the function has allocated the initial map replace it with a
12869 // copy containing the new prototype. Also complete any in-object
12870 // slack tracking that is in progress at this point because it is
12871 // still tracking the old copy.
12872 function->CompleteInobjectSlackTrackingIfActive();
12873
12874 Handle<Map> initial_map(function->initial_map(), isolate);
12875
12876 if (!initial_map->GetIsolate()->bootstrapper()->IsActive() &&
12877 initial_map->instance_type() == JS_OBJECT_TYPE) {
12878 // Put the value in the initial map field until an initial map is needed.
12879 // At that point, a new initial map is created and the prototype is put
12880 // into the initial map where it belongs.
12881 function->set_prototype_or_initial_map(*value);
12882 } else {
12883 Handle<Map> new_map = Map::Copy(initial_map, "SetInstancePrototype");
12884 JSFunction::SetInitialMap(function, new_map, value);
12885
12886 // If the function is used as the global Array function, cache the
12887 // updated initial maps (and transitioned versions) in the native context.
12888 Handle<Context> native_context(function->context()->native_context(),
12889 isolate);
12890 Handle<Object> array_function(
12891 native_context->get(Context::ARRAY_FUNCTION_INDEX), isolate);
12892 if (array_function->IsJSFunction() &&
12893 *function == JSFunction::cast(*array_function)) {
12894 CacheInitialJSArrayMaps(native_context, new_map);
12895 }
12896 }
12897
12898 // Deoptimize all code that embeds the previous initial map.
12899 initial_map->dependent_code()->DeoptimizeDependentCodeGroup(
12900 isolate, DependentCode::kInitialMapChangedGroup);
12901 } else {
12902 // Put the value in the initial map field until an initial map is
12903 // needed. At that point, a new initial map is created and the
12904 // prototype is put into the initial map where it belongs.
12905 function->set_prototype_or_initial_map(*value);
12906 if (value->IsJSObject()) {
12907 // Optimize as prototype to detach it from its transition tree.
12908 JSObject::OptimizeAsPrototype(Handle<JSObject>::cast(value),
12909 FAST_PROTOTYPE);
12910 }
12911 }
12912 isolate->heap()->ClearInstanceofCache();
12913 }
12914
12915
SetPrototype(Handle<JSFunction> function,Handle<Object> value)12916 void JSFunction::SetPrototype(Handle<JSFunction> function,
12917 Handle<Object> value) {
12918 DCHECK(function->IsConstructor() ||
12919 IsGeneratorFunction(function->shared()->kind()));
12920 Handle<Object> construct_prototype = value;
12921
12922 // If the value is not a JSReceiver, store the value in the map's
12923 // constructor field so it can be accessed. Also, set the prototype
12924 // used for constructing objects to the original object prototype.
12925 // See ECMA-262 13.2.2.
12926 if (!value->IsJSReceiver()) {
12927 // Copy the map so this does not affect unrelated functions.
12928 // Remove map transitions because they point to maps with a
12929 // different prototype.
12930 Handle<Map> new_map = Map::Copy(handle(function->map()), "SetPrototype");
12931
12932 JSObject::MigrateToMap(function, new_map);
12933 new_map->SetConstructor(*value);
12934 new_map->set_non_instance_prototype(true);
12935 Isolate* isolate = new_map->GetIsolate();
12936
12937 construct_prototype = handle(
12938 IsGeneratorFunction(function->shared()->kind())
12939 ? function->context()
12940 ->native_context()
12941 ->initial_generator_prototype()
12942 : function->context()->native_context()->initial_object_prototype(),
12943 isolate);
12944 } else {
12945 function->map()->set_non_instance_prototype(false);
12946 }
12947
12948 return SetInstancePrototype(function, construct_prototype);
12949 }
12950
12951
RemovePrototype()12952 bool JSFunction::RemovePrototype() {
12953 Context* native_context = context()->native_context();
12954 Map* no_prototype_map =
12955 is_strict(shared()->language_mode())
12956 ? native_context->strict_function_without_prototype_map()
12957 : native_context->sloppy_function_without_prototype_map();
12958
12959 if (map() == no_prototype_map) return true;
12960
12961 #ifdef DEBUG
12962 if (map() != (is_strict(shared()->language_mode())
12963 ? native_context->strict_function_map()
12964 : native_context->sloppy_function_map())) {
12965 return false;
12966 }
12967 #endif
12968
12969 set_map(no_prototype_map);
12970 set_prototype_or_initial_map(no_prototype_map->GetHeap()->the_hole_value());
12971 return true;
12972 }
12973
12974
SetInitialMap(Handle<JSFunction> function,Handle<Map> map,Handle<Object> prototype)12975 void JSFunction::SetInitialMap(Handle<JSFunction> function, Handle<Map> map,
12976 Handle<Object> prototype) {
12977 if (map->prototype() != *prototype) {
12978 Map::SetPrototype(map, prototype, FAST_PROTOTYPE);
12979 }
12980 function->set_prototype_or_initial_map(*map);
12981 map->SetConstructor(*function);
12982 #if TRACE_MAPS
12983 if (FLAG_trace_maps) {
12984 PrintF("[TraceMaps: InitialMap map= %p SFI= %d_%s ]\n",
12985 reinterpret_cast<void*>(*map), function->shared()->unique_id(),
12986 function->shared()->DebugName()->ToCString().get());
12987 }
12988 #endif
12989 }
12990
12991
12992 #ifdef DEBUG
12993 namespace {
12994
CanSubclassHaveInobjectProperties(InstanceType instance_type)12995 bool CanSubclassHaveInobjectProperties(InstanceType instance_type) {
12996 switch (instance_type) {
12997 case JS_API_OBJECT_TYPE:
12998 case JS_ARRAY_BUFFER_TYPE:
12999 case JS_ARRAY_TYPE:
13000 case JS_CONTEXT_EXTENSION_OBJECT_TYPE:
13001 case JS_DATA_VIEW_TYPE:
13002 case JS_DATE_TYPE:
13003 case JS_FUNCTION_TYPE:
13004 case JS_GENERATOR_OBJECT_TYPE:
13005 case JS_MAP_ITERATOR_TYPE:
13006 case JS_MAP_TYPE:
13007 case JS_MESSAGE_OBJECT_TYPE:
13008 case JS_OBJECT_TYPE:
13009 case JS_ERROR_TYPE:
13010 case JS_ARGUMENTS_TYPE:
13011 case JS_PROMISE_TYPE:
13012 case JS_REGEXP_TYPE:
13013 case JS_SET_ITERATOR_TYPE:
13014 case JS_SET_TYPE:
13015 case JS_SPECIAL_API_OBJECT_TYPE:
13016 case JS_TYPED_ARRAY_TYPE:
13017 case JS_VALUE_TYPE:
13018 case JS_WEAK_MAP_TYPE:
13019 case JS_WEAK_SET_TYPE:
13020 return true;
13021
13022 case BYTECODE_ARRAY_TYPE:
13023 case BYTE_ARRAY_TYPE:
13024 case CELL_TYPE:
13025 case CODE_TYPE:
13026 case FILLER_TYPE:
13027 case FIXED_ARRAY_TYPE:
13028 case FIXED_DOUBLE_ARRAY_TYPE:
13029 case FOREIGN_TYPE:
13030 case FREE_SPACE_TYPE:
13031 case HEAP_NUMBER_TYPE:
13032 case JS_BOUND_FUNCTION_TYPE:
13033 case JS_GLOBAL_OBJECT_TYPE:
13034 case JS_GLOBAL_PROXY_TYPE:
13035 case JS_PROXY_TYPE:
13036 case MAP_TYPE:
13037 case MUTABLE_HEAP_NUMBER_TYPE:
13038 case ODDBALL_TYPE:
13039 case PROPERTY_CELL_TYPE:
13040 case SHARED_FUNCTION_INFO_TYPE:
13041 case SIMD128_VALUE_TYPE:
13042 case SYMBOL_TYPE:
13043 case WEAK_CELL_TYPE:
13044
13045 #define TYPED_ARRAY_CASE(Type, type, TYPE, ctype, size) \
13046 case FIXED_##TYPE##_ARRAY_TYPE:
13047 #undef TYPED_ARRAY_CASE
13048
13049 #define MAKE_STRUCT_CASE(NAME, Name, name) case NAME##_TYPE:
13050 STRUCT_LIST(MAKE_STRUCT_CASE)
13051 #undef MAKE_STRUCT_CASE
13052 // We must not end up here for these instance types at all.
13053 UNREACHABLE();
13054 // Fall through.
13055 default:
13056 return false;
13057 }
13058 }
13059
13060 } // namespace
13061 #endif
13062
13063
EnsureHasInitialMap(Handle<JSFunction> function)13064 void JSFunction::EnsureHasInitialMap(Handle<JSFunction> function) {
13065 DCHECK(function->IsConstructor() ||
13066 IsResumableFunction(function->shared()->kind()));
13067 if (function->has_initial_map()) return;
13068 Isolate* isolate = function->GetIsolate();
13069
13070 // The constructor should be compiled for the optimization hints to be
13071 // available.
13072 Compiler::Compile(function, Compiler::CLEAR_EXCEPTION);
13073
13074 // First create a new map with the size and number of in-object properties
13075 // suggested by the function.
13076 InstanceType instance_type;
13077 if (IsResumableFunction(function->shared()->kind())) {
13078 instance_type = JS_GENERATOR_OBJECT_TYPE;
13079 } else {
13080 instance_type = JS_OBJECT_TYPE;
13081 }
13082 int instance_size;
13083 int in_object_properties;
13084 function->CalculateInstanceSize(instance_type, 0, &instance_size,
13085 &in_object_properties);
13086
13087 Handle<Map> map = isolate->factory()->NewMap(instance_type, instance_size);
13088
13089 // Fetch or allocate prototype.
13090 Handle<Object> prototype;
13091 if (function->has_instance_prototype()) {
13092 prototype = handle(function->instance_prototype(), isolate);
13093 } else {
13094 prototype = isolate->factory()->NewFunctionPrototype(function);
13095 }
13096 map->SetInObjectProperties(in_object_properties);
13097 map->set_unused_property_fields(in_object_properties);
13098 DCHECK(map->has_fast_object_elements());
13099
13100 // Finally link initial map and constructor function.
13101 DCHECK(prototype->IsJSReceiver());
13102 JSFunction::SetInitialMap(function, map, prototype);
13103 map->StartInobjectSlackTracking();
13104 }
13105
13106
13107 // static
GetDerivedMap(Isolate * isolate,Handle<JSFunction> constructor,Handle<JSReceiver> new_target)13108 MaybeHandle<Map> JSFunction::GetDerivedMap(Isolate* isolate,
13109 Handle<JSFunction> constructor,
13110 Handle<JSReceiver> new_target) {
13111 EnsureHasInitialMap(constructor);
13112
13113 Handle<Map> constructor_initial_map(constructor->initial_map(), isolate);
13114 if (*new_target == *constructor) return constructor_initial_map;
13115
13116 // Fast case, new.target is a subclass of constructor. The map is cacheable
13117 // (and may already have been cached). new.target.prototype is guaranteed to
13118 // be a JSReceiver.
13119 if (new_target->IsJSFunction()) {
13120 Handle<JSFunction> function = Handle<JSFunction>::cast(new_target);
13121
13122 // Check that |function|'s initial map still in sync with the |constructor|,
13123 // otherwise we must create a new initial map for |function|.
13124 if (function->has_initial_map() &&
13125 function->initial_map()->GetConstructor() == *constructor) {
13126 return handle(function->initial_map(), isolate);
13127 }
13128
13129 // Create a new map with the size and number of in-object properties
13130 // suggested by |function|.
13131
13132 // Link initial map and constructor function if the new.target is actually a
13133 // subclass constructor.
13134 if (IsSubclassConstructor(function->shared()->kind())) {
13135 Handle<Object> prototype(function->instance_prototype(), isolate);
13136 InstanceType instance_type = constructor_initial_map->instance_type();
13137 DCHECK(CanSubclassHaveInobjectProperties(instance_type));
13138 int internal_fields =
13139 JSObject::GetInternalFieldCount(*constructor_initial_map);
13140 int pre_allocated = constructor_initial_map->GetInObjectProperties() -
13141 constructor_initial_map->unused_property_fields();
13142 int instance_size;
13143 int in_object_properties;
13144 function->CalculateInstanceSizeForDerivedClass(
13145 instance_type, internal_fields, &instance_size,
13146 &in_object_properties);
13147
13148 int unused_property_fields = in_object_properties - pre_allocated;
13149 Handle<Map> map =
13150 Map::CopyInitialMap(constructor_initial_map, instance_size,
13151 in_object_properties, unused_property_fields);
13152 map->set_new_target_is_base(false);
13153
13154 JSFunction::SetInitialMap(function, map, prototype);
13155 map->SetConstructor(*constructor);
13156 map->set_construction_counter(Map::kNoSlackTracking);
13157 map->StartInobjectSlackTracking();
13158 return map;
13159 }
13160 }
13161
13162 // Slow path, new.target is either a proxy or can't cache the map.
13163 // new.target.prototype is not guaranteed to be a JSReceiver, and may need to
13164 // fall back to the intrinsicDefaultProto.
13165 Handle<Object> prototype;
13166 if (new_target->IsJSFunction()) {
13167 Handle<JSFunction> function = Handle<JSFunction>::cast(new_target);
13168 // Make sure the new.target.prototype is cached.
13169 EnsureHasInitialMap(function);
13170 prototype = handle(function->prototype(), isolate);
13171 } else {
13172 Handle<String> prototype_string = isolate->factory()->prototype_string();
13173 ASSIGN_RETURN_ON_EXCEPTION(
13174 isolate, prototype,
13175 JSReceiver::GetProperty(new_target, prototype_string), Map);
13176 // The above prototype lookup might change the constructor and its
13177 // prototype, hence we have to reload the initial map.
13178 EnsureHasInitialMap(constructor);
13179 constructor_initial_map = handle(constructor->initial_map(), isolate);
13180 }
13181
13182 // If prototype is not a JSReceiver, fetch the intrinsicDefaultProto from the
13183 // correct realm. Rather than directly fetching the .prototype, we fetch the
13184 // constructor that points to the .prototype. This relies on
13185 // constructor.prototype being FROZEN for those constructors.
13186 if (!prototype->IsJSReceiver()) {
13187 Handle<Context> context;
13188 ASSIGN_RETURN_ON_EXCEPTION(isolate, context,
13189 JSReceiver::GetFunctionRealm(new_target), Map);
13190 DCHECK(context->IsNativeContext());
13191 Handle<Object> maybe_index = JSReceiver::GetDataProperty(
13192 constructor, isolate->factory()->native_context_index_symbol());
13193 int index = maybe_index->IsSmi() ? Smi::cast(*maybe_index)->value()
13194 : Context::OBJECT_FUNCTION_INDEX;
13195 Handle<JSFunction> realm_constructor(JSFunction::cast(context->get(index)));
13196 prototype = handle(realm_constructor->prototype(), isolate);
13197 }
13198
13199 Handle<Map> map = Map::CopyInitialMap(constructor_initial_map);
13200 map->set_new_target_is_base(false);
13201 DCHECK(prototype->IsJSReceiver());
13202 if (map->prototype() != *prototype) {
13203 Map::SetPrototype(map, prototype, FAST_PROTOTYPE);
13204 }
13205 map->SetConstructor(*constructor);
13206 return map;
13207 }
13208
13209
PrintName(FILE * out)13210 void JSFunction::PrintName(FILE* out) {
13211 std::unique_ptr<char[]> name = shared()->DebugName()->ToCString();
13212 PrintF(out, "%s", name.get());
13213 }
13214
13215
GetName(Handle<JSFunction> function)13216 Handle<String> JSFunction::GetName(Handle<JSFunction> function) {
13217 Isolate* isolate = function->GetIsolate();
13218 Handle<Object> name =
13219 JSReceiver::GetDataProperty(function, isolate->factory()->name_string());
13220 if (name->IsString()) return Handle<String>::cast(name);
13221 return handle(function->shared()->DebugName(), isolate);
13222 }
13223
13224
GetDebugName(Handle<JSFunction> function)13225 Handle<String> JSFunction::GetDebugName(Handle<JSFunction> function) {
13226 Isolate* isolate = function->GetIsolate();
13227 Handle<Object> name = JSReceiver::GetDataProperty(
13228 function, isolate->factory()->display_name_string());
13229 if (name->IsString()) return Handle<String>::cast(name);
13230 return JSFunction::GetName(function);
13231 }
13232
SetName(Handle<JSFunction> function,Handle<Name> name,Handle<String> prefix)13233 void JSFunction::SetName(Handle<JSFunction> function, Handle<Name> name,
13234 Handle<String> prefix) {
13235 Isolate* isolate = function->GetIsolate();
13236 Handle<String> function_name = Name::ToFunctionName(name).ToHandleChecked();
13237 if (prefix->length() > 0) {
13238 IncrementalStringBuilder builder(isolate);
13239 builder.AppendString(prefix);
13240 builder.AppendCharacter(' ');
13241 builder.AppendString(function_name);
13242 function_name = builder.Finish().ToHandleChecked();
13243 }
13244 JSObject::DefinePropertyOrElementIgnoreAttributes(
13245 function, isolate->factory()->name_string(), function_name,
13246 static_cast<PropertyAttributes>(DONT_ENUM | READ_ONLY))
13247 .ToHandleChecked();
13248 }
13249
13250 namespace {
13251
13252 char const kNativeCodeSource[] = "function () { [native code] }";
13253
13254
NativeCodeFunctionSourceString(Handle<SharedFunctionInfo> shared_info)13255 Handle<String> NativeCodeFunctionSourceString(
13256 Handle<SharedFunctionInfo> shared_info) {
13257 Isolate* const isolate = shared_info->GetIsolate();
13258 if (shared_info->name()->IsString()) {
13259 IncrementalStringBuilder builder(isolate);
13260 builder.AppendCString("function ");
13261 builder.AppendString(handle(String::cast(shared_info->name()), isolate));
13262 builder.AppendCString("() { [native code] }");
13263 return builder.Finish().ToHandleChecked();
13264 }
13265 return isolate->factory()->NewStringFromAsciiChecked(kNativeCodeSource);
13266 }
13267
13268 } // namespace
13269
13270
13271 // static
ToString(Handle<JSBoundFunction> function)13272 Handle<String> JSBoundFunction::ToString(Handle<JSBoundFunction> function) {
13273 Isolate* const isolate = function->GetIsolate();
13274 return isolate->factory()->NewStringFromAsciiChecked(kNativeCodeSource);
13275 }
13276
13277
13278 // static
ToString(Handle<JSFunction> function)13279 Handle<String> JSFunction::ToString(Handle<JSFunction> function) {
13280 Isolate* const isolate = function->GetIsolate();
13281 Handle<SharedFunctionInfo> shared_info(function->shared(), isolate);
13282
13283 // Check if {function} should hide its source code.
13284 if (!shared_info->script()->IsScript() ||
13285 Script::cast(shared_info->script())->hide_source()) {
13286 return NativeCodeFunctionSourceString(shared_info);
13287 }
13288
13289 // Check if we should print {function} as a class.
13290 Handle<Object> class_start_position = JSReceiver::GetDataProperty(
13291 function, isolate->factory()->class_start_position_symbol());
13292 if (class_start_position->IsSmi()) {
13293 Handle<Object> class_end_position = JSReceiver::GetDataProperty(
13294 function, isolate->factory()->class_end_position_symbol());
13295 Handle<String> script_source(
13296 String::cast(Script::cast(shared_info->script())->source()), isolate);
13297 return isolate->factory()->NewSubString(
13298 script_source, Handle<Smi>::cast(class_start_position)->value(),
13299 Handle<Smi>::cast(class_end_position)->value());
13300 }
13301
13302 // Check if we have source code for the {function}.
13303 if (!shared_info->HasSourceCode()) {
13304 return NativeCodeFunctionSourceString(shared_info);
13305 }
13306
13307 IncrementalStringBuilder builder(isolate);
13308 FunctionKind kind = shared_info->kind();
13309 if (!IsArrowFunction(kind)) {
13310 if (IsConciseMethod(kind)) {
13311 if (IsGeneratorFunction(kind)) {
13312 builder.AppendCharacter('*');
13313 } else if (IsAsyncFunction(kind)) {
13314 builder.AppendCString("async ");
13315 }
13316 } else {
13317 if (IsGeneratorFunction(kind)) {
13318 builder.AppendCString("function* ");
13319 } else if (IsAsyncFunction(kind)) {
13320 builder.AppendCString("async function ");
13321 } else {
13322 builder.AppendCString("function ");
13323 }
13324 }
13325 if (shared_info->name_should_print_as_anonymous()) {
13326 builder.AppendCString("anonymous");
13327 } else if (!shared_info->is_anonymous_expression()) {
13328 builder.AppendString(handle(String::cast(shared_info->name()), isolate));
13329 }
13330 }
13331 builder.AppendString(Handle<String>::cast(shared_info->GetSourceCode()));
13332 return builder.Finish().ToHandleChecked();
13333 }
13334
Initialize(Isolate * isolate,Handle<Oddball> oddball,const char * to_string,Handle<Object> to_number,const char * type_of,byte kind)13335 void Oddball::Initialize(Isolate* isolate, Handle<Oddball> oddball,
13336 const char* to_string, Handle<Object> to_number,
13337 const char* type_of, byte kind) {
13338 Handle<String> internalized_to_string =
13339 isolate->factory()->InternalizeUtf8String(to_string);
13340 Handle<String> internalized_type_of =
13341 isolate->factory()->InternalizeUtf8String(type_of);
13342 oddball->set_to_number_raw(to_number->Number());
13343 oddball->set_to_number(*to_number);
13344 oddball->set_to_string(*internalized_to_string);
13345 oddball->set_type_of(*internalized_type_of);
13346 oddball->set_kind(kind);
13347 }
13348
SetEvalOrigin(Handle<Script> script,Handle<SharedFunctionInfo> outer_info,int eval_position)13349 void Script::SetEvalOrigin(Handle<Script> script,
13350 Handle<SharedFunctionInfo> outer_info,
13351 int eval_position) {
13352 if (eval_position == kNoSourcePosition) {
13353 // If the position is missing, attempt to get the code offset from the
13354 // current activation. Do not translate the code offset into source
13355 // position, but store it as negative value for lazy translation.
13356 StackTraceFrameIterator it(script->GetIsolate());
13357 if (!it.done() && it.is_javascript()) {
13358 FrameSummary summary = FrameSummary::GetFirst(it.javascript_frame());
13359 script->set_eval_from_shared(summary.function()->shared());
13360 script->set_eval_from_position(-summary.code_offset());
13361 return;
13362 }
13363 eval_position = 0;
13364 }
13365 script->set_eval_from_shared(*outer_info);
13366 script->set_eval_from_position(eval_position);
13367 }
13368
GetEvalPosition()13369 int Script::GetEvalPosition() {
13370 DisallowHeapAllocation no_gc;
13371 DCHECK(compilation_type() == Script::COMPILATION_TYPE_EVAL);
13372 int position = eval_from_position();
13373 if (position < 0) {
13374 // Due to laziness, the position may not have been translated from code
13375 // offset yet, which would be encoded as negative integer. In that case,
13376 // translate and set the position.
13377 if (eval_from_shared()->IsUndefined(GetIsolate())) {
13378 position = 0;
13379 } else {
13380 SharedFunctionInfo* shared = SharedFunctionInfo::cast(eval_from_shared());
13381 position = shared->abstract_code()->SourcePosition(-position);
13382 }
13383 DCHECK(position >= 0);
13384 set_eval_from_position(position);
13385 }
13386 return position;
13387 }
13388
InitLineEnds(Handle<Script> script)13389 void Script::InitLineEnds(Handle<Script> script) {
13390 Isolate* isolate = script->GetIsolate();
13391 if (!script->line_ends()->IsUndefined(isolate)) return;
13392 DCHECK_NE(Script::TYPE_WASM, script->type());
13393
13394 Object* src_obj = script->source();
13395 if (!src_obj->IsString()) {
13396 DCHECK(src_obj->IsUndefined(isolate));
13397 script->set_line_ends(isolate->heap()->empty_fixed_array());
13398 } else {
13399 DCHECK(src_obj->IsString());
13400 Handle<String> src(String::cast(src_obj), isolate);
13401 Handle<FixedArray> array = String::CalculateLineEnds(src, true);
13402 script->set_line_ends(*array);
13403 }
13404
13405 DCHECK(script->line_ends()->IsFixedArray());
13406 }
13407
GetPositionInfo(Handle<Script> script,int position,PositionInfo * info,OffsetFlag offset_flag)13408 bool Script::GetPositionInfo(Handle<Script> script, int position,
13409 PositionInfo* info, OffsetFlag offset_flag) {
13410 // For wasm, we do not create an artificial line_ends array, but do the
13411 // translation directly.
13412 if (script->type() == Script::TYPE_WASM) {
13413 Handle<WasmCompiledModule> compiled_module(
13414 WasmCompiledModule::cast(script->wasm_compiled_module()));
13415 DCHECK_LE(0, position);
13416 return wasm::GetPositionInfo(compiled_module,
13417 static_cast<uint32_t>(position), info);
13418 }
13419
13420 InitLineEnds(script);
13421 return script->GetPositionInfo(position, info, offset_flag);
13422 }
13423
13424 namespace {
GetPositionInfoSlow(const Script * script,int position,Script::PositionInfo * info)13425 bool GetPositionInfoSlow(const Script* script, int position,
13426 Script::PositionInfo* info) {
13427 if (!script->source()->IsString()) return false;
13428 if (position < 0) position = 0;
13429
13430 String* source_string = String::cast(script->source());
13431 int line = 0;
13432 int line_start = 0;
13433 int len = source_string->length();
13434 for (int pos = 0; pos <= len; ++pos) {
13435 if (pos == len || source_string->Get(pos) == '\n') {
13436 if (position <= pos) {
13437 info->line = line;
13438 info->column = position - line_start;
13439 info->line_start = line_start;
13440 info->line_end = pos;
13441 return true;
13442 }
13443 line++;
13444 line_start = pos + 1;
13445 }
13446 }
13447 return false;
13448 }
13449 } // namespace
13450
13451 #define SMI_VALUE(x) (Smi::cast(x)->value())
GetPositionInfo(int position,PositionInfo * info,OffsetFlag offset_flag) const13452 bool Script::GetPositionInfo(int position, PositionInfo* info,
13453 OffsetFlag offset_flag) const {
13454 DisallowHeapAllocation no_allocation;
13455
13456 if (line_ends()->IsUndefined(GetIsolate())) {
13457 // Slow mode: we do not have line_ends. We have to iterate through source.
13458 if (!GetPositionInfoSlow(this, position, info)) return false;
13459 } else {
13460 DCHECK(line_ends()->IsFixedArray());
13461 FixedArray* ends = FixedArray::cast(line_ends());
13462
13463 const int ends_len = ends->length();
13464 if (ends_len == 0) return false;
13465
13466 // Return early on invalid positions. Negative positions behave as if 0 was
13467 // passed, and positions beyond the end of the script return as failure.
13468 if (position < 0) {
13469 position = 0;
13470 } else if (position > SMI_VALUE(ends->get(ends_len - 1))) {
13471 return false;
13472 }
13473
13474 // Determine line number by doing a binary search on the line ends array.
13475 if (SMI_VALUE(ends->get(0)) >= position) {
13476 info->line = 0;
13477 info->line_start = 0;
13478 info->column = position;
13479 } else {
13480 int left = 0;
13481 int right = ends_len - 1;
13482
13483 while (right > 0) {
13484 DCHECK_LE(left, right);
13485 const int mid = (left + right) / 2;
13486 if (position > SMI_VALUE(ends->get(mid))) {
13487 left = mid + 1;
13488 } else if (position <= SMI_VALUE(ends->get(mid - 1))) {
13489 right = mid - 1;
13490 } else {
13491 info->line = mid;
13492 break;
13493 }
13494 }
13495 DCHECK(SMI_VALUE(ends->get(info->line)) >= position &&
13496 SMI_VALUE(ends->get(info->line - 1)) < position);
13497 info->line_start = SMI_VALUE(ends->get(info->line - 1)) + 1;
13498 info->column = position - info->line_start;
13499 }
13500
13501 // Line end is position of the linebreak character.
13502 info->line_end = SMI_VALUE(ends->get(info->line));
13503 if (info->line_end > 0) {
13504 DCHECK(source()->IsString());
13505 String* src = String::cast(source());
13506 if (src->length() >= info->line_end &&
13507 src->Get(info->line_end - 1) == '\r') {
13508 info->line_end--;
13509 }
13510 }
13511 }
13512
13513 // Add offsets if requested.
13514 if (offset_flag == WITH_OFFSET) {
13515 if (info->line == 0) {
13516 info->column += column_offset();
13517 }
13518 info->line += line_offset();
13519 }
13520
13521 return true;
13522 }
13523 #undef SMI_VALUE
13524
GetColumnNumber(Handle<Script> script,int code_pos)13525 int Script::GetColumnNumber(Handle<Script> script, int code_pos) {
13526 PositionInfo info;
13527 GetPositionInfo(script, code_pos, &info, WITH_OFFSET);
13528 return info.column;
13529 }
13530
GetColumnNumber(int code_pos) const13531 int Script::GetColumnNumber(int code_pos) const {
13532 PositionInfo info;
13533 GetPositionInfo(code_pos, &info, WITH_OFFSET);
13534 return info.column;
13535 }
13536
GetLineNumber(Handle<Script> script,int code_pos)13537 int Script::GetLineNumber(Handle<Script> script, int code_pos) {
13538 PositionInfo info;
13539 GetPositionInfo(script, code_pos, &info, WITH_OFFSET);
13540 return info.line;
13541 }
13542
GetLineNumber(int code_pos) const13543 int Script::GetLineNumber(int code_pos) const {
13544 PositionInfo info;
13545 GetPositionInfo(code_pos, &info, WITH_OFFSET);
13546 return info.line;
13547 }
13548
GetNameOrSourceURL(Handle<Script> script)13549 Handle<Object> Script::GetNameOrSourceURL(Handle<Script> script) {
13550 Isolate* isolate = script->GetIsolate();
13551
13552 // Keep in sync with ScriptNameOrSourceURL in messages.js.
13553
13554 if (!script->source_url()->IsUndefined(isolate)) {
13555 return handle(script->source_url(), isolate);
13556 }
13557 return handle(script->name(), isolate);
13558 }
13559
13560
GetWrapper(Handle<Script> script)13561 Handle<JSObject> Script::GetWrapper(Handle<Script> script) {
13562 Isolate* isolate = script->GetIsolate();
13563 if (!script->wrapper()->IsUndefined(isolate)) {
13564 DCHECK(script->wrapper()->IsWeakCell());
13565 Handle<WeakCell> cell(WeakCell::cast(script->wrapper()));
13566 if (!cell->cleared()) {
13567 // Return a handle for the existing script wrapper from the cache.
13568 return handle(JSObject::cast(cell->value()));
13569 }
13570 // If we found an empty WeakCell, that means the script wrapper was
13571 // GCed. We are not notified directly of that, so we decrement here
13572 // so that we at least don't count double for any given script.
13573 isolate->counters()->script_wrappers()->Decrement();
13574 }
13575 // Construct a new script wrapper.
13576 isolate->counters()->script_wrappers()->Increment();
13577 Handle<JSFunction> constructor = isolate->script_function();
13578 Handle<JSValue> result =
13579 Handle<JSValue>::cast(isolate->factory()->NewJSObject(constructor));
13580 result->set_value(*script);
13581 Handle<WeakCell> cell = isolate->factory()->NewWeakCell(result);
13582 script->set_wrapper(*cell);
13583 return result;
13584 }
13585
13586
FindSharedFunctionInfo(FunctionLiteral * fun)13587 MaybeHandle<SharedFunctionInfo> Script::FindSharedFunctionInfo(
13588 FunctionLiteral* fun) {
13589 WeakFixedArray::Iterator iterator(shared_function_infos());
13590 SharedFunctionInfo* shared;
13591 while ((shared = iterator.Next<SharedFunctionInfo>())) {
13592 if (fun->function_token_position() == shared->function_token_position() &&
13593 fun->start_position() == shared->start_position() &&
13594 fun->end_position() == shared->end_position()) {
13595 return Handle<SharedFunctionInfo>(shared);
13596 }
13597 }
13598 return MaybeHandle<SharedFunctionInfo>();
13599 }
13600
13601
Iterator(Isolate * isolate)13602 Script::Iterator::Iterator(Isolate* isolate)
13603 : iterator_(isolate->heap()->script_list()) {}
13604
13605
Next()13606 Script* Script::Iterator::Next() { return iterator_.Next<Script>(); }
13607
13608
Iterator(Isolate * isolate)13609 SharedFunctionInfo::Iterator::Iterator(Isolate* isolate)
13610 : script_iterator_(isolate),
13611 sfi_iterator_(isolate->heap()->noscript_shared_function_infos()) {}
13612
13613
NextScript()13614 bool SharedFunctionInfo::Iterator::NextScript() {
13615 Script* script = script_iterator_.Next();
13616 if (script == NULL) return false;
13617 sfi_iterator_.Reset(script->shared_function_infos());
13618 return true;
13619 }
13620
13621
Next()13622 SharedFunctionInfo* SharedFunctionInfo::Iterator::Next() {
13623 do {
13624 SharedFunctionInfo* next = sfi_iterator_.Next<SharedFunctionInfo>();
13625 if (next != NULL) return next;
13626 } while (NextScript());
13627 return NULL;
13628 }
13629
13630
SetScript(Handle<SharedFunctionInfo> shared,Handle<Object> script_object)13631 void SharedFunctionInfo::SetScript(Handle<SharedFunctionInfo> shared,
13632 Handle<Object> script_object) {
13633 if (shared->script() == *script_object) return;
13634 Isolate* isolate = shared->GetIsolate();
13635
13636 // Add shared function info to new script's list. If a collection occurs,
13637 // the shared function info may be temporarily in two lists.
13638 // This is okay because the gc-time processing of these lists can tolerate
13639 // duplicates.
13640 Handle<Object> list;
13641 if (script_object->IsScript()) {
13642 Handle<Script> script = Handle<Script>::cast(script_object);
13643 list = handle(script->shared_function_infos(), isolate);
13644 } else {
13645 list = isolate->factory()->noscript_shared_function_infos();
13646 }
13647
13648 #ifdef DEBUG
13649 if (FLAG_enable_slow_asserts) {
13650 WeakFixedArray::Iterator iterator(*list);
13651 SharedFunctionInfo* next;
13652 while ((next = iterator.Next<SharedFunctionInfo>())) {
13653 DCHECK_NE(next, *shared);
13654 }
13655 }
13656 #endif // DEBUG
13657 list = WeakFixedArray::Add(list, shared);
13658
13659 if (script_object->IsScript()) {
13660 Handle<Script> script = Handle<Script>::cast(script_object);
13661 script->set_shared_function_infos(*list);
13662 } else {
13663 isolate->heap()->SetRootNoScriptSharedFunctionInfos(*list);
13664 }
13665
13666 // Remove shared function info from old script's list.
13667 if (shared->script()->IsScript()) {
13668 Script* old_script = Script::cast(shared->script());
13669 if (old_script->shared_function_infos()->IsWeakFixedArray()) {
13670 WeakFixedArray* list =
13671 WeakFixedArray::cast(old_script->shared_function_infos());
13672 list->Remove(shared);
13673 }
13674 } else {
13675 // Remove shared function info from root array.
13676 Object* list = isolate->heap()->noscript_shared_function_infos();
13677 CHECK(WeakFixedArray::cast(list)->Remove(shared));
13678 }
13679
13680 // Finally set new script.
13681 shared->set_script(*script_object);
13682 }
13683
13684
DebugName()13685 String* SharedFunctionInfo::DebugName() {
13686 Object* n = name();
13687 if (!n->IsString() || String::cast(n)->length() == 0) return inferred_name();
13688 return String::cast(n);
13689 }
13690
13691 // The filter is a pattern that matches function names in this way:
13692 // "*" all; the default
13693 // "-" all but the top-level function
13694 // "-name" all but the function "name"
13695 // "" only the top-level function
13696 // "name" only the function "name"
13697 // "name*" only functions starting with "name"
13698 // "~" none; the tilde is not an identifier
PassesFilter(const char * raw_filter)13699 bool SharedFunctionInfo::PassesFilter(const char* raw_filter) {
13700 if (*raw_filter == '*') return true;
13701 String* name = DebugName();
13702 Vector<const char> filter = CStrVector(raw_filter);
13703 if (filter.length() == 0) return name->length() == 0;
13704 if (filter[0] == '-') {
13705 // Negative filter.
13706 if (filter.length() == 1) {
13707 return (name->length() != 0);
13708 } else if (name->IsUtf8EqualTo(filter.SubVector(1, filter.length()))) {
13709 return false;
13710 }
13711 if (filter[filter.length() - 1] == '*' &&
13712 name->IsUtf8EqualTo(filter.SubVector(1, filter.length() - 1), true)) {
13713 return false;
13714 }
13715 return true;
13716
13717 } else if (name->IsUtf8EqualTo(filter)) {
13718 return true;
13719 }
13720 if (filter[filter.length() - 1] == '*' &&
13721 name->IsUtf8EqualTo(filter.SubVector(0, filter.length() - 1), true)) {
13722 return true;
13723 }
13724 return false;
13725 }
13726
HasSourceCode() const13727 bool SharedFunctionInfo::HasSourceCode() const {
13728 Isolate* isolate = GetIsolate();
13729 return !script()->IsUndefined(isolate) &&
13730 !reinterpret_cast<Script*>(script())->source()->IsUndefined(isolate);
13731 }
13732
13733
GetSourceCode()13734 Handle<Object> SharedFunctionInfo::GetSourceCode() {
13735 if (!HasSourceCode()) return GetIsolate()->factory()->undefined_value();
13736 Handle<String> source(String::cast(Script::cast(script())->source()));
13737 return GetIsolate()->factory()->NewSubString(
13738 source, start_position(), end_position());
13739 }
13740
13741
IsInlineable()13742 bool SharedFunctionInfo::IsInlineable() {
13743 // Check that the function has a script associated with it.
13744 if (!script()->IsScript()) return false;
13745 return !optimization_disabled();
13746 }
13747
13748
SourceSize()13749 int SharedFunctionInfo::SourceSize() {
13750 return end_position() - start_position();
13751 }
13752
CalculateInstanceSizeHelper(InstanceType instance_type,int requested_internal_fields,int requested_in_object_properties,int * instance_size,int * in_object_properties)13753 void JSFunction::CalculateInstanceSizeHelper(InstanceType instance_type,
13754 int requested_internal_fields,
13755 int requested_in_object_properties,
13756 int* instance_size,
13757 int* in_object_properties) {
13758 int header_size = JSObject::GetHeaderSize(instance_type);
13759 DCHECK_LE(requested_internal_fields,
13760 (JSObject::kMaxInstanceSize - header_size) >> kPointerSizeLog2);
13761 *instance_size =
13762 Min(header_size +
13763 ((requested_internal_fields + requested_in_object_properties)
13764 << kPointerSizeLog2),
13765 JSObject::kMaxInstanceSize);
13766 *in_object_properties = ((*instance_size - header_size) >> kPointerSizeLog2) -
13767 requested_internal_fields;
13768 }
13769
13770
CalculateInstanceSize(InstanceType instance_type,int requested_internal_fields,int * instance_size,int * in_object_properties)13771 void JSFunction::CalculateInstanceSize(InstanceType instance_type,
13772 int requested_internal_fields,
13773 int* instance_size,
13774 int* in_object_properties) {
13775 CalculateInstanceSizeHelper(instance_type, requested_internal_fields,
13776 shared()->expected_nof_properties(),
13777 instance_size, in_object_properties);
13778 }
13779
13780
CalculateInstanceSizeForDerivedClass(InstanceType instance_type,int requested_internal_fields,int * instance_size,int * in_object_properties)13781 void JSFunction::CalculateInstanceSizeForDerivedClass(
13782 InstanceType instance_type, int requested_internal_fields,
13783 int* instance_size, int* in_object_properties) {
13784 Isolate* isolate = GetIsolate();
13785 int expected_nof_properties = 0;
13786 for (PrototypeIterator iter(isolate, this, kStartAtReceiver); !iter.IsAtEnd();
13787 iter.Advance()) {
13788 JSReceiver* current = iter.GetCurrent<JSReceiver>();
13789 if (!current->IsJSFunction()) break;
13790 JSFunction* func = JSFunction::cast(current);
13791 SharedFunctionInfo* shared = func->shared();
13792 expected_nof_properties += shared->expected_nof_properties();
13793 if (!IsSubclassConstructor(shared->kind())) {
13794 break;
13795 }
13796 }
13797 CalculateInstanceSizeHelper(instance_type, requested_internal_fields,
13798 expected_nof_properties, instance_size,
13799 in_object_properties);
13800 }
13801
13802
13803 // Output the source code without any allocation in the heap.
operator <<(std::ostream & os,const SourceCodeOf & v)13804 std::ostream& operator<<(std::ostream& os, const SourceCodeOf& v) {
13805 const SharedFunctionInfo* s = v.value;
13806 // For some native functions there is no source.
13807 if (!s->HasSourceCode()) return os << "<No Source>";
13808
13809 // Get the source for the script which this function came from.
13810 // Don't use String::cast because we don't want more assertion errors while
13811 // we are already creating a stack dump.
13812 String* script_source =
13813 reinterpret_cast<String*>(Script::cast(s->script())->source());
13814
13815 if (!script_source->LooksValid()) return os << "<Invalid Source>";
13816
13817 if (!s->is_toplevel()) {
13818 os << "function ";
13819 Object* name = s->name();
13820 if (name->IsString() && String::cast(name)->length() > 0) {
13821 String::cast(name)->PrintUC16(os);
13822 }
13823 }
13824
13825 int len = s->end_position() - s->start_position();
13826 if (len <= v.max_length || v.max_length < 0) {
13827 script_source->PrintUC16(os, s->start_position(), s->end_position());
13828 return os;
13829 } else {
13830 script_source->PrintUC16(os, s->start_position(),
13831 s->start_position() + v.max_length);
13832 return os << "...\n";
13833 }
13834 }
13835
13836
IsCodeEquivalent(Code * code,Code * recompiled)13837 static bool IsCodeEquivalent(Code* code, Code* recompiled) {
13838 if (code->instruction_size() != recompiled->instruction_size()) return false;
13839 ByteArray* code_relocation = code->relocation_info();
13840 ByteArray* recompiled_relocation = recompiled->relocation_info();
13841 int length = code_relocation->length();
13842 if (length != recompiled_relocation->length()) return false;
13843 int compare = memcmp(code_relocation->GetDataStartAddress(),
13844 recompiled_relocation->GetDataStartAddress(),
13845 length);
13846 return compare == 0;
13847 }
13848
13849
EnableDeoptimizationSupport(Code * recompiled)13850 void SharedFunctionInfo::EnableDeoptimizationSupport(Code* recompiled) {
13851 DCHECK(!has_deoptimization_support());
13852 DisallowHeapAllocation no_allocation;
13853 Code* code = this->code();
13854 if (IsCodeEquivalent(code, recompiled)) {
13855 // Copy the deoptimization data from the recompiled code.
13856 code->set_deoptimization_data(recompiled->deoptimization_data());
13857 code->set_has_deoptimization_support(true);
13858 } else {
13859 // TODO(3025757): In case the recompiled isn't equivalent to the
13860 // old code, we have to replace it. We should try to avoid this
13861 // altogether because it flushes valuable type feedback by
13862 // effectively resetting all IC state.
13863 ReplaceCode(recompiled);
13864 }
13865 DCHECK(has_deoptimization_support());
13866 }
13867
13868
DisableOptimization(BailoutReason reason)13869 void SharedFunctionInfo::DisableOptimization(BailoutReason reason) {
13870 // Disable optimization for the shared function info and mark the
13871 // code as non-optimizable. The marker on the shared function info
13872 // is there because we flush non-optimized code thereby loosing the
13873 // non-optimizable information for the code. When the code is
13874 // regenerated and set on the shared function info it is marked as
13875 // non-optimizable if optimization is disabled for the shared
13876 // function info.
13877 DCHECK(reason != kNoReason);
13878 set_optimization_disabled(true);
13879 set_disable_optimization_reason(reason);
13880 // Code should be the lazy compilation stub or else unoptimized.
13881 DCHECK(abstract_code()->kind() == AbstractCode::FUNCTION ||
13882 abstract_code()->kind() == AbstractCode::INTERPRETED_FUNCTION ||
13883 abstract_code()->kind() == AbstractCode::BUILTIN);
13884 PROFILE(GetIsolate(), CodeDisableOptEvent(abstract_code(), this));
13885 if (FLAG_trace_opt) {
13886 PrintF("[disabled optimization for ");
13887 ShortPrint();
13888 PrintF(", reason: %s]\n", GetBailoutReason(reason));
13889 }
13890 }
13891
13892 namespace {
13893
13894 // Sets the expected number of properties based on estimate from parser.
SetExpectedNofPropertiesFromEstimate(Handle<SharedFunctionInfo> shared,FunctionLiteral * literal)13895 void SetExpectedNofPropertiesFromEstimate(Handle<SharedFunctionInfo> shared,
13896 FunctionLiteral* literal) {
13897 int estimate = literal->expected_property_count();
13898
13899 // If no properties are added in the constructor, they are more likely
13900 // to be added later.
13901 if (estimate == 0) estimate = 2;
13902
13903 // TODO(yangguo): check whether those heuristics are still up-to-date.
13904 // We do not shrink objects that go into a snapshot (yet), so we adjust
13905 // the estimate conservatively.
13906 if (shared->GetIsolate()->serializer_enabled()) {
13907 estimate += 2;
13908 } else {
13909 // Inobject slack tracking will reclaim redundant inobject space later,
13910 // so we can afford to adjust the estimate generously.
13911 estimate += 8;
13912 }
13913
13914 shared->set_expected_nof_properties(estimate);
13915 }
13916
13917 } // namespace
13918
InitFromFunctionLiteral(Handle<SharedFunctionInfo> shared_info,FunctionLiteral * lit)13919 void SharedFunctionInfo::InitFromFunctionLiteral(
13920 Handle<SharedFunctionInfo> shared_info, FunctionLiteral* lit) {
13921 // When adding fields here, make sure DeclarationScope::AnalyzePartially is
13922 // updated accordingly.
13923 shared_info->set_length(lit->function_length());
13924 shared_info->set_internal_formal_parameter_count(lit->parameter_count());
13925 shared_info->set_function_token_position(lit->function_token_position());
13926 shared_info->set_start_position(lit->start_position());
13927 shared_info->set_end_position(lit->end_position());
13928 shared_info->set_is_declaration(lit->is_declaration());
13929 shared_info->set_is_named_expression(lit->is_named_expression());
13930 shared_info->set_is_anonymous_expression(lit->is_anonymous_expression());
13931 shared_info->set_inferred_name(*lit->inferred_name());
13932 shared_info->set_allows_lazy_compilation(lit->AllowsLazyCompilation());
13933 shared_info->set_language_mode(lit->language_mode());
13934 shared_info->set_uses_arguments(lit->scope()->arguments() != NULL);
13935 shared_info->set_has_duplicate_parameters(lit->has_duplicate_parameters());
13936 shared_info->set_is_function(lit->is_function());
13937 shared_info->set_never_compiled(true);
13938 shared_info->set_kind(lit->kind());
13939 if (!IsConstructable(lit->kind(), lit->language_mode())) {
13940 shared_info->SetConstructStub(
13941 *shared_info->GetIsolate()->builtins()->ConstructedNonConstructable());
13942 }
13943 shared_info->set_needs_home_object(lit->scope()->NeedsHomeObject());
13944 shared_info->set_asm_function(lit->scope()->asm_function());
13945 shared_info->set_requires_class_field_init(lit->requires_class_field_init());
13946 shared_info->set_is_class_field_initializer(
13947 lit->is_class_field_initializer());
13948 SetExpectedNofPropertiesFromEstimate(shared_info, lit);
13949 }
13950
13951
VerifyBailoutId(BailoutId id)13952 bool SharedFunctionInfo::VerifyBailoutId(BailoutId id) {
13953 DCHECK(!id.IsNone());
13954 Code* unoptimized = code();
13955 DeoptimizationOutputData* data =
13956 DeoptimizationOutputData::cast(unoptimized->deoptimization_data());
13957 unsigned ignore = Deoptimizer::GetOutputInfo(data, id, this);
13958 USE(ignore);
13959 return true; // Return true if there was no DCHECK.
13960 }
13961
SetConstructStub(Code * code)13962 void SharedFunctionInfo::SetConstructStub(Code* code) {
13963 if (code->kind() == Code::BUILTIN) code->set_is_construct_stub(true);
13964 set_construct_stub(code);
13965 }
13966
StartInobjectSlackTracking()13967 void Map::StartInobjectSlackTracking() {
13968 DCHECK(!IsInobjectSlackTrackingInProgress());
13969
13970 // No tracking during the snapshot construction phase.
13971 Isolate* isolate = GetIsolate();
13972 if (isolate->serializer_enabled()) return;
13973
13974 if (unused_property_fields() == 0) return;
13975
13976 set_construction_counter(Map::kSlackTrackingCounterStart);
13977 }
13978
13979
ResetForNewContext(int new_ic_age)13980 void SharedFunctionInfo::ResetForNewContext(int new_ic_age) {
13981 code()->ClearInlineCaches();
13982 set_ic_age(new_ic_age);
13983 if (code()->kind() == Code::FUNCTION) {
13984 code()->set_profiler_ticks(0);
13985 if (optimization_disabled() && opt_count() >= FLAG_max_opt_count) {
13986 // Re-enable optimizations if they were disabled due to opt_count limit.
13987 set_optimization_disabled(false);
13988 }
13989 set_opt_count(0);
13990 set_deopt_count(0);
13991 } else if (IsInterpreted()) {
13992 set_profiler_ticks(0);
13993 if (optimization_disabled() && opt_count() >= FLAG_max_opt_count) {
13994 // Re-enable optimizations if they were disabled due to opt_count limit.
13995 set_optimization_disabled(false);
13996 }
13997 set_opt_count(0);
13998 set_deopt_count(0);
13999 }
14000 }
14001
14002
SearchOptimizedCodeMapEntry(Context * native_context,BailoutId osr_ast_id)14003 int SharedFunctionInfo::SearchOptimizedCodeMapEntry(Context* native_context,
14004 BailoutId osr_ast_id) {
14005 DisallowHeapAllocation no_gc;
14006 DCHECK(native_context->IsNativeContext());
14007 if (!OptimizedCodeMapIsCleared()) {
14008 FixedArray* optimized_code_map = this->optimized_code_map();
14009 int length = optimized_code_map->length();
14010 Smi* osr_ast_id_smi = Smi::FromInt(osr_ast_id.ToInt());
14011 for (int i = kEntriesStart; i < length; i += kEntryLength) {
14012 if (WeakCell::cast(optimized_code_map->get(i + kContextOffset))
14013 ->value() == native_context &&
14014 optimized_code_map->get(i + kOsrAstIdOffset) == osr_ast_id_smi) {
14015 return i;
14016 }
14017 }
14018 }
14019 return -1;
14020 }
14021
ClearCodeFromOptimizedCodeMap()14022 void SharedFunctionInfo::ClearCodeFromOptimizedCodeMap() {
14023 if (!OptimizedCodeMapIsCleared()) {
14024 FixedArray* optimized_code_map = this->optimized_code_map();
14025 int length = optimized_code_map->length();
14026 WeakCell* empty_weak_cell = GetHeap()->empty_weak_cell();
14027 for (int i = kEntriesStart; i < length; i += kEntryLength) {
14028 optimized_code_map->set(i + kCachedCodeOffset, empty_weak_cell,
14029 SKIP_WRITE_BARRIER);
14030 }
14031 }
14032 }
14033
SearchOptimizedCodeMap(Context * native_context,BailoutId osr_ast_id)14034 CodeAndLiterals SharedFunctionInfo::SearchOptimizedCodeMap(
14035 Context* native_context, BailoutId osr_ast_id) {
14036 CodeAndLiterals result = {nullptr, nullptr};
14037 int entry = SearchOptimizedCodeMapEntry(native_context, osr_ast_id);
14038 if (entry != kNotFound) {
14039 FixedArray* code_map = optimized_code_map();
14040 DCHECK_LE(entry + kEntryLength, code_map->length());
14041 WeakCell* cell = WeakCell::cast(code_map->get(entry + kCachedCodeOffset));
14042 WeakCell* literals_cell =
14043 WeakCell::cast(code_map->get(entry + kLiteralsOffset));
14044
14045 result = {cell->cleared() ? nullptr : Code::cast(cell->value()),
14046 literals_cell->cleared() ? nullptr : LiteralsArray::cast(
14047 literals_cell->value())};
14048 }
14049 return result;
14050 }
14051
14052
14053 #define DECLARE_TAG(ignore1, name, ignore2) name,
14054 const char* const VisitorSynchronization::kTags[
14055 VisitorSynchronization::kNumberOfSyncTags] = {
14056 VISITOR_SYNCHRONIZATION_TAGS_LIST(DECLARE_TAG)
14057 };
14058 #undef DECLARE_TAG
14059
14060
14061 #define DECLARE_TAG(ignore1, ignore2, name) name,
14062 const char* const VisitorSynchronization::kTagNames[
14063 VisitorSynchronization::kNumberOfSyncTags] = {
14064 VISITOR_SYNCHRONIZATION_TAGS_LIST(DECLARE_TAG)
14065 };
14066 #undef DECLARE_TAG
14067
14068
VisitCodeTarget(RelocInfo * rinfo)14069 void ObjectVisitor::VisitCodeTarget(RelocInfo* rinfo) {
14070 DCHECK(RelocInfo::IsCodeTarget(rinfo->rmode()));
14071 Object* old_pointer = Code::GetCodeFromTargetAddress(rinfo->target_address());
14072 Object* new_pointer = old_pointer;
14073 VisitPointer(&new_pointer);
14074 DCHECK_EQ(old_pointer, new_pointer);
14075 }
14076
14077
VisitCodeAgeSequence(RelocInfo * rinfo)14078 void ObjectVisitor::VisitCodeAgeSequence(RelocInfo* rinfo) {
14079 DCHECK(RelocInfo::IsCodeAgeSequence(rinfo->rmode()));
14080 Object* old_pointer = rinfo->code_age_stub();
14081 Object* new_pointer = old_pointer;
14082 if (old_pointer != nullptr) {
14083 VisitPointer(&new_pointer);
14084 DCHECK_EQ(old_pointer, new_pointer);
14085 }
14086 }
14087
14088
VisitCodeEntry(Address entry_address)14089 void ObjectVisitor::VisitCodeEntry(Address entry_address) {
14090 Object* old_pointer = Code::GetObjectFromEntryAddress(entry_address);
14091 Object* new_pointer = old_pointer;
14092 VisitPointer(&new_pointer);
14093 DCHECK_EQ(old_pointer, new_pointer);
14094 }
14095
14096
VisitCell(RelocInfo * rinfo)14097 void ObjectVisitor::VisitCell(RelocInfo* rinfo) {
14098 DCHECK(rinfo->rmode() == RelocInfo::CELL);
14099 Object* old_pointer = rinfo->target_cell();
14100 Object* new_pointer = old_pointer;
14101 VisitPointer(&new_pointer);
14102 DCHECK_EQ(old_pointer, new_pointer);
14103 }
14104
14105
VisitDebugTarget(RelocInfo * rinfo)14106 void ObjectVisitor::VisitDebugTarget(RelocInfo* rinfo) {
14107 DCHECK(RelocInfo::IsDebugBreakSlot(rinfo->rmode()) &&
14108 rinfo->IsPatchedDebugBreakSlotSequence());
14109 Object* old_pointer =
14110 Code::GetCodeFromTargetAddress(rinfo->debug_call_address());
14111 Object* new_pointer = old_pointer;
14112 VisitPointer(&new_pointer);
14113 DCHECK_EQ(old_pointer, new_pointer);
14114 }
14115
14116
VisitEmbeddedPointer(RelocInfo * rinfo)14117 void ObjectVisitor::VisitEmbeddedPointer(RelocInfo* rinfo) {
14118 DCHECK(rinfo->rmode() == RelocInfo::EMBEDDED_OBJECT);
14119 Object* old_pointer = rinfo->target_object();
14120 Object* new_pointer = old_pointer;
14121 VisitPointer(&new_pointer);
14122 DCHECK_EQ(old_pointer, new_pointer);
14123 }
14124
14125
VisitExternalReference(RelocInfo * rinfo)14126 void ObjectVisitor::VisitExternalReference(RelocInfo* rinfo) {
14127 Address old_reference = rinfo->target_external_reference();
14128 Address new_reference = old_reference;
14129 VisitExternalReference(&new_reference);
14130 DCHECK_EQ(old_reference, new_reference);
14131 }
14132
14133
InvalidateRelocation()14134 void Code::InvalidateRelocation() {
14135 InvalidateEmbeddedObjects();
14136 set_relocation_info(GetHeap()->empty_byte_array());
14137 }
14138
14139
InvalidateEmbeddedObjects()14140 void Code::InvalidateEmbeddedObjects() {
14141 Object* undefined = GetHeap()->undefined_value();
14142 Cell* undefined_cell = GetHeap()->undefined_cell();
14143 int mode_mask = RelocInfo::ModeMask(RelocInfo::EMBEDDED_OBJECT) |
14144 RelocInfo::ModeMask(RelocInfo::CELL);
14145 for (RelocIterator it(this, mode_mask); !it.done(); it.next()) {
14146 RelocInfo::Mode mode = it.rinfo()->rmode();
14147 if (mode == RelocInfo::EMBEDDED_OBJECT) {
14148 it.rinfo()->set_target_object(undefined, SKIP_WRITE_BARRIER);
14149 } else if (mode == RelocInfo::CELL) {
14150 it.rinfo()->set_target_cell(undefined_cell, SKIP_WRITE_BARRIER);
14151 }
14152 }
14153 }
14154
14155
Relocate(intptr_t delta)14156 void Code::Relocate(intptr_t delta) {
14157 for (RelocIterator it(this, RelocInfo::kApplyMask); !it.done(); it.next()) {
14158 it.rinfo()->apply(delta);
14159 }
14160 Assembler::FlushICache(GetIsolate(), instruction_start(), instruction_size());
14161 }
14162
14163
CopyFrom(const CodeDesc & desc)14164 void Code::CopyFrom(const CodeDesc& desc) {
14165 // copy code
14166 CopyBytes(instruction_start(), desc.buffer,
14167 static_cast<size_t>(desc.instr_size));
14168
14169 // copy unwinding info, if any
14170 if (desc.unwinding_info) {
14171 DCHECK_GT(desc.unwinding_info_size, 0);
14172 set_unwinding_info_size(desc.unwinding_info_size);
14173 CopyBytes(unwinding_info_start(), desc.unwinding_info,
14174 static_cast<size_t>(desc.unwinding_info_size));
14175 }
14176
14177 // copy reloc info
14178 CopyBytes(relocation_start(),
14179 desc.buffer + desc.buffer_size - desc.reloc_size,
14180 static_cast<size_t>(desc.reloc_size));
14181
14182 // unbox handles and relocate
14183 intptr_t delta = instruction_start() - desc.buffer;
14184 int mode_mask = RelocInfo::kCodeTargetMask |
14185 RelocInfo::ModeMask(RelocInfo::EMBEDDED_OBJECT) |
14186 RelocInfo::ModeMask(RelocInfo::CELL) |
14187 RelocInfo::ModeMask(RelocInfo::RUNTIME_ENTRY) |
14188 RelocInfo::kApplyMask;
14189 // Needed to find target_object and runtime_entry on X64
14190 Assembler* origin = desc.origin;
14191 AllowDeferredHandleDereference embedding_raw_address;
14192 for (RelocIterator it(this, mode_mask); !it.done(); it.next()) {
14193 RelocInfo::Mode mode = it.rinfo()->rmode();
14194 if (mode == RelocInfo::EMBEDDED_OBJECT) {
14195 Handle<Object> p = it.rinfo()->target_object_handle(origin);
14196 it.rinfo()->set_target_object(*p, UPDATE_WRITE_BARRIER,
14197 SKIP_ICACHE_FLUSH);
14198 } else if (mode == RelocInfo::CELL) {
14199 Handle<Cell> cell = it.rinfo()->target_cell_handle();
14200 it.rinfo()->set_target_cell(*cell, UPDATE_WRITE_BARRIER,
14201 SKIP_ICACHE_FLUSH);
14202 } else if (RelocInfo::IsCodeTarget(mode)) {
14203 // rewrite code handles in inline cache targets to direct
14204 // pointers to the first instruction in the code object
14205 Handle<Object> p = it.rinfo()->target_object_handle(origin);
14206 Code* code = Code::cast(*p);
14207 it.rinfo()->set_target_address(code->instruction_start(),
14208 UPDATE_WRITE_BARRIER, SKIP_ICACHE_FLUSH);
14209 } else if (RelocInfo::IsRuntimeEntry(mode)) {
14210 Address p = it.rinfo()->target_runtime_entry(origin);
14211 it.rinfo()->set_target_runtime_entry(p, UPDATE_WRITE_BARRIER,
14212 SKIP_ICACHE_FLUSH);
14213 } else if (mode == RelocInfo::CODE_AGE_SEQUENCE) {
14214 Handle<Object> p = it.rinfo()->code_age_stub_handle(origin);
14215 Code* code = Code::cast(*p);
14216 it.rinfo()->set_code_age_stub(code, SKIP_ICACHE_FLUSH);
14217 } else {
14218 it.rinfo()->apply(delta);
14219 }
14220 }
14221 Assembler::FlushICache(GetIsolate(), instruction_start(), instruction_size());
14222 }
14223
14224
GetSafepointEntry(Address pc)14225 SafepointEntry Code::GetSafepointEntry(Address pc) {
14226 SafepointTable table(this);
14227 return table.FindEntry(pc);
14228 }
14229
14230
FindNthObject(int n,Map * match_map)14231 Object* Code::FindNthObject(int n, Map* match_map) {
14232 DCHECK(is_inline_cache_stub());
14233 DisallowHeapAllocation no_allocation;
14234 int mask = RelocInfo::ModeMask(RelocInfo::EMBEDDED_OBJECT);
14235 for (RelocIterator it(this, mask); !it.done(); it.next()) {
14236 RelocInfo* info = it.rinfo();
14237 Object* object = info->target_object();
14238 if (object->IsWeakCell()) object = WeakCell::cast(object)->value();
14239 if (object->IsHeapObject()) {
14240 if (HeapObject::cast(object)->map() == match_map) {
14241 if (--n == 0) return object;
14242 }
14243 }
14244 }
14245 return NULL;
14246 }
14247
14248
FindFirstAllocationSite()14249 AllocationSite* Code::FindFirstAllocationSite() {
14250 Object* result = FindNthObject(1, GetHeap()->allocation_site_map());
14251 return (result != NULL) ? AllocationSite::cast(result) : NULL;
14252 }
14253
14254
FindFirstMap()14255 Map* Code::FindFirstMap() {
14256 Object* result = FindNthObject(1, GetHeap()->meta_map());
14257 return (result != NULL) ? Map::cast(result) : NULL;
14258 }
14259
14260
FindAndReplace(const FindAndReplacePattern & pattern)14261 void Code::FindAndReplace(const FindAndReplacePattern& pattern) {
14262 DCHECK(is_inline_cache_stub() || is_handler());
14263 DisallowHeapAllocation no_allocation;
14264 int mask = RelocInfo::ModeMask(RelocInfo::EMBEDDED_OBJECT);
14265 STATIC_ASSERT(FindAndReplacePattern::kMaxCount < 32);
14266 int current_pattern = 0;
14267 for (RelocIterator it(this, mask); !it.done(); it.next()) {
14268 RelocInfo* info = it.rinfo();
14269 Object* object = info->target_object();
14270 if (object->IsHeapObject()) {
14271 if (object->IsWeakCell()) {
14272 object = HeapObject::cast(WeakCell::cast(object)->value());
14273 }
14274 Map* map = HeapObject::cast(object)->map();
14275 if (map == *pattern.find_[current_pattern]) {
14276 info->set_target_object(*pattern.replace_[current_pattern]);
14277 if (++current_pattern == pattern.count_) return;
14278 }
14279 }
14280 }
14281 UNREACHABLE();
14282 }
14283
14284
ClearInlineCaches()14285 void Code::ClearInlineCaches() {
14286 int mask = RelocInfo::ModeMask(RelocInfo::CODE_TARGET) |
14287 RelocInfo::ModeMask(RelocInfo::CODE_TARGET_WITH_ID);
14288 for (RelocIterator it(this, mask); !it.done(); it.next()) {
14289 RelocInfo* info = it.rinfo();
14290 Code* target(Code::GetCodeFromTargetAddress(info->target_address()));
14291 if (target->is_inline_cache_stub()) {
14292 IC::Clear(this->GetIsolate(), info->pc(), info->host()->constant_pool());
14293 }
14294 }
14295 }
14296
SourcePosition(int offset)14297 int AbstractCode::SourcePosition(int offset) {
14298 int position = 0;
14299 // Subtract one because the current PC is one instruction after the call site.
14300 if (IsCode()) offset--;
14301 for (SourcePositionTableIterator iterator(source_position_table());
14302 !iterator.done() && iterator.code_offset() <= offset;
14303 iterator.Advance()) {
14304 position = iterator.source_position().ScriptOffset();
14305 }
14306 return position;
14307 }
14308
SourceStatementPosition(int offset)14309 int AbstractCode::SourceStatementPosition(int offset) {
14310 // First find the closest position.
14311 int position = SourcePosition(offset);
14312 // Now find the closest statement position before the position.
14313 int statement_position = 0;
14314 for (SourcePositionTableIterator it(source_position_table()); !it.done();
14315 it.Advance()) {
14316 if (it.is_statement()) {
14317 int p = it.source_position().ScriptOffset();
14318 if (statement_position < p && p <= position) {
14319 statement_position = p;
14320 }
14321 }
14322 }
14323 return statement_position;
14324 }
14325
ClearTypeFeedbackInfo()14326 void JSFunction::ClearTypeFeedbackInfo() {
14327 feedback_vector()->ClearSlots(shared());
14328 }
14329
ClearTypeFeedbackInfoAtGCTime()14330 void JSFunction::ClearTypeFeedbackInfoAtGCTime() {
14331 feedback_vector()->ClearSlotsAtGCTime(shared());
14332 }
14333
TranslatePcOffsetToAstId(uint32_t pc_offset)14334 BailoutId Code::TranslatePcOffsetToAstId(uint32_t pc_offset) {
14335 DisallowHeapAllocation no_gc;
14336 DCHECK(kind() == FUNCTION);
14337 BackEdgeTable back_edges(this, &no_gc);
14338 for (uint32_t i = 0; i < back_edges.length(); i++) {
14339 if (back_edges.pc_offset(i) == pc_offset) return back_edges.ast_id(i);
14340 }
14341 return BailoutId::None();
14342 }
14343
14344
TranslateAstIdToPcOffset(BailoutId ast_id)14345 uint32_t Code::TranslateAstIdToPcOffset(BailoutId ast_id) {
14346 DisallowHeapAllocation no_gc;
14347 DCHECK(kind() == FUNCTION);
14348 BackEdgeTable back_edges(this, &no_gc);
14349 for (uint32_t i = 0; i < back_edges.length(); i++) {
14350 if (back_edges.ast_id(i) == ast_id) return back_edges.pc_offset(i);
14351 }
14352 UNREACHABLE(); // We expect to find the back edge.
14353 return 0;
14354 }
14355
LookupRangeInHandlerTable(int code_offset,int * data,HandlerTable::CatchPrediction * prediction)14356 int Code::LookupRangeInHandlerTable(int code_offset, int* data,
14357 HandlerTable::CatchPrediction* prediction) {
14358 DCHECK(!is_optimized_code());
14359 HandlerTable* table = HandlerTable::cast(handler_table());
14360 return table->LookupRange(code_offset, data, prediction);
14361 }
14362
MakeCodeAgeSequenceYoung(byte * sequence,Isolate * isolate)14363 void Code::MakeCodeAgeSequenceYoung(byte* sequence, Isolate* isolate) {
14364 PatchPlatformCodeAge(isolate, sequence, kNoAgeCodeAge, NO_MARKING_PARITY);
14365 }
14366
14367
MarkCodeAsExecuted(byte * sequence,Isolate * isolate)14368 void Code::MarkCodeAsExecuted(byte* sequence, Isolate* isolate) {
14369 PatchPlatformCodeAge(isolate, sequence, kExecutedOnceCodeAge,
14370 NO_MARKING_PARITY);
14371 }
14372
14373
14374 // NextAge defines the Code::Age state transitions during a GC cycle.
NextAge(Code::Age age)14375 static Code::Age NextAge(Code::Age age) {
14376 switch (age) {
14377 case Code::kNotExecutedCodeAge: // Keep, until we've been executed.
14378 case Code::kToBeExecutedOnceCodeAge: // Keep, until we've been executed.
14379 case Code::kLastCodeAge: // Clamp at last Code::Age value.
14380 return age;
14381 case Code::kExecutedOnceCodeAge:
14382 // Pre-age code that has only been executed once.
14383 return static_cast<Code::Age>(Code::kPreAgedCodeAge + 1);
14384 default:
14385 return static_cast<Code::Age>(age + 1); // Default case: Increase age.
14386 }
14387 }
14388
14389
14390 // IsOldAge defines the collection criteria for a Code object.
IsOldAge(Code::Age age)14391 static bool IsOldAge(Code::Age age) {
14392 return age >= Code::kIsOldCodeAge || age == Code::kNotExecutedCodeAge;
14393 }
14394
14395
MakeYoung(Isolate * isolate)14396 void Code::MakeYoung(Isolate* isolate) {
14397 byte* sequence = FindCodeAgeSequence();
14398 if (sequence != NULL) MakeCodeAgeSequenceYoung(sequence, isolate);
14399 }
14400
PreAge(Isolate * isolate)14401 void Code::PreAge(Isolate* isolate) {
14402 byte* sequence = FindCodeAgeSequence();
14403 if (sequence != NULL) {
14404 PatchPlatformCodeAge(isolate, sequence, kPreAgedCodeAge, NO_MARKING_PARITY);
14405 }
14406 }
14407
MarkToBeExecutedOnce(Isolate * isolate)14408 void Code::MarkToBeExecutedOnce(Isolate* isolate) {
14409 byte* sequence = FindCodeAgeSequence();
14410 if (sequence != NULL) {
14411 PatchPlatformCodeAge(isolate, sequence, kToBeExecutedOnceCodeAge,
14412 NO_MARKING_PARITY);
14413 }
14414 }
14415
MakeOlder(MarkingParity current_parity)14416 void Code::MakeOlder(MarkingParity current_parity) {
14417 byte* sequence = FindCodeAgeSequence();
14418 if (sequence != NULL) {
14419 Age age;
14420 MarkingParity code_parity;
14421 Isolate* isolate = GetIsolate();
14422 GetCodeAgeAndParity(isolate, sequence, &age, &code_parity);
14423 Age next_age = NextAge(age);
14424 if (age != next_age && code_parity != current_parity) {
14425 PatchPlatformCodeAge(isolate, sequence, next_age, current_parity);
14426 }
14427 }
14428 }
14429
14430
IsOld()14431 bool Code::IsOld() {
14432 return IsOldAge(GetAge());
14433 }
14434
14435
FindCodeAgeSequence()14436 byte* Code::FindCodeAgeSequence() {
14437 return FLAG_age_code &&
14438 prologue_offset() != Code::kPrologueOffsetNotSet &&
14439 (kind() == OPTIMIZED_FUNCTION ||
14440 (kind() == FUNCTION && !has_debug_break_slots()))
14441 ? instruction_start() + prologue_offset()
14442 : NULL;
14443 }
14444
14445
GetAge()14446 Code::Age Code::GetAge() {
14447 byte* sequence = FindCodeAgeSequence();
14448 if (sequence == NULL) {
14449 return kNoAgeCodeAge;
14450 }
14451 Age age;
14452 MarkingParity parity;
14453 GetCodeAgeAndParity(GetIsolate(), sequence, &age, &parity);
14454 return age;
14455 }
14456
14457
GetCodeAgeAndParity(Code * code,Age * age,MarkingParity * parity)14458 void Code::GetCodeAgeAndParity(Code* code, Age* age,
14459 MarkingParity* parity) {
14460 Isolate* isolate = code->GetIsolate();
14461 Builtins* builtins = isolate->builtins();
14462 Code* stub = NULL;
14463 #define HANDLE_CODE_AGE(AGE) \
14464 stub = *builtins->Make##AGE##CodeYoungAgainEvenMarking(); \
14465 if (code == stub) { \
14466 *age = k##AGE##CodeAge; \
14467 *parity = EVEN_MARKING_PARITY; \
14468 return; \
14469 } \
14470 stub = *builtins->Make##AGE##CodeYoungAgainOddMarking(); \
14471 if (code == stub) { \
14472 *age = k##AGE##CodeAge; \
14473 *parity = ODD_MARKING_PARITY; \
14474 return; \
14475 }
14476 CODE_AGE_LIST(HANDLE_CODE_AGE)
14477 #undef HANDLE_CODE_AGE
14478 stub = *builtins->MarkCodeAsExecutedOnce();
14479 if (code == stub) {
14480 *age = kNotExecutedCodeAge;
14481 *parity = NO_MARKING_PARITY;
14482 return;
14483 }
14484 stub = *builtins->MarkCodeAsExecutedTwice();
14485 if (code == stub) {
14486 *age = kExecutedOnceCodeAge;
14487 *parity = NO_MARKING_PARITY;
14488 return;
14489 }
14490 stub = *builtins->MarkCodeAsToBeExecutedOnce();
14491 if (code == stub) {
14492 *age = kToBeExecutedOnceCodeAge;
14493 *parity = NO_MARKING_PARITY;
14494 return;
14495 }
14496 UNREACHABLE();
14497 }
14498
14499
GetCodeAgeStub(Isolate * isolate,Age age,MarkingParity parity)14500 Code* Code::GetCodeAgeStub(Isolate* isolate, Age age, MarkingParity parity) {
14501 Builtins* builtins = isolate->builtins();
14502 switch (age) {
14503 #define HANDLE_CODE_AGE(AGE) \
14504 case k##AGE##CodeAge: { \
14505 Code* stub = parity == EVEN_MARKING_PARITY \
14506 ? *builtins->Make##AGE##CodeYoungAgainEvenMarking() \
14507 : *builtins->Make##AGE##CodeYoungAgainOddMarking(); \
14508 return stub; \
14509 }
14510 CODE_AGE_LIST(HANDLE_CODE_AGE)
14511 #undef HANDLE_CODE_AGE
14512 case kNotExecutedCodeAge: {
14513 DCHECK(parity == NO_MARKING_PARITY);
14514 return *builtins->MarkCodeAsExecutedOnce();
14515 }
14516 case kExecutedOnceCodeAge: {
14517 DCHECK(parity == NO_MARKING_PARITY);
14518 return *builtins->MarkCodeAsExecutedTwice();
14519 }
14520 case kToBeExecutedOnceCodeAge: {
14521 DCHECK(parity == NO_MARKING_PARITY);
14522 return *builtins->MarkCodeAsToBeExecutedOnce();
14523 }
14524 default:
14525 UNREACHABLE();
14526 break;
14527 }
14528 return NULL;
14529 }
14530
14531
PrintDeoptLocation(FILE * out,Address pc)14532 void Code::PrintDeoptLocation(FILE* out, Address pc) {
14533 Deoptimizer::DeoptInfo info = Deoptimizer::GetDeoptInfo(this, pc);
14534 class SourcePosition pos = info.position;
14535 if (info.deopt_reason != DeoptimizeReason::kNoReason || pos.IsKnown()) {
14536 if (FLAG_hydrogen_track_positions) {
14537 PrintF(out, " ;;; deoptimize at %d_%d: %s\n", pos.InliningId(),
14538 pos.ScriptOffset(), DeoptimizeReasonToString(info.deopt_reason));
14539 } else {
14540 PrintF(out, " ;;; deoptimize at ");
14541 OFStream outstr(out);
14542 pos.Print(outstr, this);
14543 PrintF(out, ", %s\n", DeoptimizeReasonToString(info.deopt_reason));
14544 }
14545 }
14546 }
14547
14548
CanDeoptAt(Address pc)14549 bool Code::CanDeoptAt(Address pc) {
14550 DeoptimizationInputData* deopt_data =
14551 DeoptimizationInputData::cast(deoptimization_data());
14552 Address code_start_address = instruction_start();
14553 for (int i = 0; i < deopt_data->DeoptCount(); i++) {
14554 if (deopt_data->Pc(i)->value() == -1) continue;
14555 Address address = code_start_address + deopt_data->Pc(i)->value();
14556 if (address == pc && deopt_data->AstId(i) != BailoutId::None()) {
14557 return true;
14558 }
14559 }
14560 return false;
14561 }
14562
14563
14564 // Identify kind of code.
Kind2String(Kind kind)14565 const char* Code::Kind2String(Kind kind) {
14566 switch (kind) {
14567 #define CASE(name) case name: return #name;
14568 CODE_KIND_LIST(CASE)
14569 #undef CASE
14570 case NUMBER_OF_KINDS: break;
14571 }
14572 UNREACHABLE();
14573 return NULL;
14574 }
14575
14576 // Identify kind of code.
Kind2String(Kind kind)14577 const char* AbstractCode::Kind2String(Kind kind) {
14578 if (kind < AbstractCode::INTERPRETED_FUNCTION)
14579 return Code::Kind2String((Code::Kind)kind);
14580 if (kind == AbstractCode::INTERPRETED_FUNCTION) return "INTERPRETED_FUNCTION";
14581 UNREACHABLE();
14582 return NULL;
14583 }
14584
WeakCellFor(Handle<Code> code)14585 Handle<WeakCell> Code::WeakCellFor(Handle<Code> code) {
14586 DCHECK(code->kind() == OPTIMIZED_FUNCTION);
14587 WeakCell* raw_cell = code->CachedWeakCell();
14588 if (raw_cell != NULL) return Handle<WeakCell>(raw_cell);
14589 Handle<WeakCell> cell = code->GetIsolate()->factory()->NewWeakCell(code);
14590 DeoptimizationInputData::cast(code->deoptimization_data())
14591 ->SetWeakCellCache(*cell);
14592 return cell;
14593 }
14594
14595
CachedWeakCell()14596 WeakCell* Code::CachedWeakCell() {
14597 DCHECK(kind() == OPTIMIZED_FUNCTION);
14598 Object* weak_cell_cache =
14599 DeoptimizationInputData::cast(deoptimization_data())->WeakCellCache();
14600 if (weak_cell_cache->IsWeakCell()) {
14601 DCHECK(this == WeakCell::cast(weak_cell_cache)->value());
14602 return WeakCell::cast(weak_cell_cache);
14603 }
14604 return NULL;
14605 }
14606
14607 #if defined(OBJECT_PRINT) || defined(ENABLE_DISASSEMBLER)
14608
ICState2String(InlineCacheState state)14609 const char* Code::ICState2String(InlineCacheState state) {
14610 switch (state) {
14611 case UNINITIALIZED:
14612 return "UNINITIALIZED";
14613 case PREMONOMORPHIC:
14614 return "PREMONOMORPHIC";
14615 case MONOMORPHIC:
14616 return "MONOMORPHIC";
14617 case RECOMPUTE_HANDLER:
14618 return "RECOMPUTE_HANDLER";
14619 case POLYMORPHIC:
14620 return "POLYMORPHIC";
14621 case MEGAMORPHIC:
14622 return "MEGAMORPHIC";
14623 case GENERIC:
14624 return "GENERIC";
14625 }
14626 UNREACHABLE();
14627 return NULL;
14628 }
14629
PrintExtraICState(std::ostream & os,Kind kind,ExtraICState extra)14630 void Code::PrintExtraICState(std::ostream& os, // NOLINT
14631 Kind kind, ExtraICState extra) {
14632 os << "extra_ic_state = ";
14633 if ((kind == STORE_IC || kind == KEYED_STORE_IC) &&
14634 is_strict(static_cast<LanguageMode>(extra))) {
14635 os << "STRICT\n";
14636 } else {
14637 os << extra << "\n";
14638 }
14639 }
14640
14641 #endif // defined(OBJECT_PRINT) || defined(ENABLE_DISASSEMBLER)
14642
14643 #ifdef ENABLE_DISASSEMBLER
14644
DeoptimizationInputDataPrint(std::ostream & os)14645 void DeoptimizationInputData::DeoptimizationInputDataPrint(
14646 std::ostream& os) { // NOLINT
14647 disasm::NameConverter converter;
14648 int const inlined_function_count = InlinedFunctionCount()->value();
14649 os << "Inlined functions (count = " << inlined_function_count << ")\n";
14650 for (int id = 0; id < inlined_function_count; ++id) {
14651 Object* info = LiteralArray()->get(id);
14652 os << " " << Brief(SharedFunctionInfo::cast(info)) << "\n";
14653 }
14654 os << "\n";
14655 int deopt_count = DeoptCount();
14656 os << "Deoptimization Input Data (deopt points = " << deopt_count << ")\n";
14657 if (0 != deopt_count) {
14658 os << " index ast id argc pc";
14659 if (FLAG_print_code_verbose) os << " commands";
14660 os << "\n";
14661 }
14662 for (int i = 0; i < deopt_count; i++) {
14663 os << std::setw(6) << i << " " << std::setw(6) << AstId(i).ToInt() << " "
14664 << std::setw(6) << ArgumentsStackHeight(i)->value() << " "
14665 << std::setw(6) << Pc(i)->value();
14666
14667 if (!FLAG_print_code_verbose) {
14668 os << "\n";
14669 continue;
14670 }
14671 // Print details of the frame translation.
14672 int translation_index = TranslationIndex(i)->value();
14673 TranslationIterator iterator(TranslationByteArray(), translation_index);
14674 Translation::Opcode opcode =
14675 static_cast<Translation::Opcode>(iterator.Next());
14676 DCHECK(Translation::BEGIN == opcode);
14677 int frame_count = iterator.Next();
14678 int jsframe_count = iterator.Next();
14679 os << " " << Translation::StringFor(opcode)
14680 << " {frame count=" << frame_count
14681 << ", js frame count=" << jsframe_count << "}\n";
14682
14683 while (iterator.HasNext() &&
14684 Translation::BEGIN !=
14685 (opcode = static_cast<Translation::Opcode>(iterator.Next()))) {
14686 os << std::setw(31) << " " << Translation::StringFor(opcode) << " ";
14687
14688 switch (opcode) {
14689 case Translation::BEGIN:
14690 UNREACHABLE();
14691 break;
14692
14693 case Translation::JS_FRAME: {
14694 int ast_id = iterator.Next();
14695 int shared_info_id = iterator.Next();
14696 unsigned height = iterator.Next();
14697 Object* shared_info = LiteralArray()->get(shared_info_id);
14698 os << "{ast_id=" << ast_id << ", function="
14699 << Brief(SharedFunctionInfo::cast(shared_info)->DebugName())
14700 << ", height=" << height << "}";
14701 break;
14702 }
14703
14704 case Translation::INTERPRETED_FRAME: {
14705 int bytecode_offset = iterator.Next();
14706 int shared_info_id = iterator.Next();
14707 unsigned height = iterator.Next();
14708 Object* shared_info = LiteralArray()->get(shared_info_id);
14709 os << "{bytecode_offset=" << bytecode_offset << ", function="
14710 << Brief(SharedFunctionInfo::cast(shared_info)->DebugName())
14711 << ", height=" << height << "}";
14712 break;
14713 }
14714
14715 case Translation::COMPILED_STUB_FRAME: {
14716 Code::Kind stub_kind = static_cast<Code::Kind>(iterator.Next());
14717 os << "{kind=" << stub_kind << "}";
14718 break;
14719 }
14720
14721 case Translation::ARGUMENTS_ADAPTOR_FRAME:
14722 case Translation::CONSTRUCT_STUB_FRAME: {
14723 int shared_info_id = iterator.Next();
14724 Object* shared_info = LiteralArray()->get(shared_info_id);
14725 unsigned height = iterator.Next();
14726 os << "{function="
14727 << Brief(SharedFunctionInfo::cast(shared_info)->DebugName())
14728 << ", height=" << height << "}";
14729 break;
14730 }
14731
14732 case Translation::TAIL_CALLER_FRAME: {
14733 int shared_info_id = iterator.Next();
14734 Object* shared_info = LiteralArray()->get(shared_info_id);
14735 os << "{function="
14736 << Brief(SharedFunctionInfo::cast(shared_info)->DebugName())
14737 << "}";
14738 break;
14739 }
14740
14741 case Translation::GETTER_STUB_FRAME:
14742 case Translation::SETTER_STUB_FRAME: {
14743 int shared_info_id = iterator.Next();
14744 Object* shared_info = LiteralArray()->get(shared_info_id);
14745 os << "{function=" << Brief(SharedFunctionInfo::cast(shared_info)
14746 ->DebugName()) << "}";
14747 break;
14748 }
14749
14750 case Translation::REGISTER: {
14751 int reg_code = iterator.Next();
14752 os << "{input=" << converter.NameOfCPURegister(reg_code) << "}";
14753 break;
14754 }
14755
14756 case Translation::INT32_REGISTER: {
14757 int reg_code = iterator.Next();
14758 os << "{input=" << converter.NameOfCPURegister(reg_code) << "}";
14759 break;
14760 }
14761
14762 case Translation::UINT32_REGISTER: {
14763 int reg_code = iterator.Next();
14764 os << "{input=" << converter.NameOfCPURegister(reg_code)
14765 << " (unsigned)}";
14766 break;
14767 }
14768
14769 case Translation::BOOL_REGISTER: {
14770 int reg_code = iterator.Next();
14771 os << "{input=" << converter.NameOfCPURegister(reg_code)
14772 << " (bool)}";
14773 break;
14774 }
14775
14776 case Translation::FLOAT_REGISTER: {
14777 int reg_code = iterator.Next();
14778 os << "{input="
14779 << RegisterConfiguration::Crankshaft()->GetFloatRegisterName(
14780 reg_code)
14781 << "}";
14782 break;
14783 }
14784
14785 case Translation::DOUBLE_REGISTER: {
14786 int reg_code = iterator.Next();
14787 os << "{input="
14788 << RegisterConfiguration::Crankshaft()->GetDoubleRegisterName(
14789 reg_code)
14790 << "}";
14791 break;
14792 }
14793
14794 case Translation::STACK_SLOT: {
14795 int input_slot_index = iterator.Next();
14796 os << "{input=" << input_slot_index << "}";
14797 break;
14798 }
14799
14800 case Translation::INT32_STACK_SLOT: {
14801 int input_slot_index = iterator.Next();
14802 os << "{input=" << input_slot_index << "}";
14803 break;
14804 }
14805
14806 case Translation::UINT32_STACK_SLOT: {
14807 int input_slot_index = iterator.Next();
14808 os << "{input=" << input_slot_index << " (unsigned)}";
14809 break;
14810 }
14811
14812 case Translation::BOOL_STACK_SLOT: {
14813 int input_slot_index = iterator.Next();
14814 os << "{input=" << input_slot_index << " (bool)}";
14815 break;
14816 }
14817
14818 case Translation::FLOAT_STACK_SLOT:
14819 case Translation::DOUBLE_STACK_SLOT: {
14820 int input_slot_index = iterator.Next();
14821 os << "{input=" << input_slot_index << "}";
14822 break;
14823 }
14824
14825 case Translation::LITERAL: {
14826 int literal_index = iterator.Next();
14827 Object* literal_value = LiteralArray()->get(literal_index);
14828 os << "{literal_id=" << literal_index << " (" << Brief(literal_value)
14829 << ")}";
14830 break;
14831 }
14832
14833 case Translation::DUPLICATED_OBJECT: {
14834 int object_index = iterator.Next();
14835 os << "{object_index=" << object_index << "}";
14836 break;
14837 }
14838
14839 case Translation::ARGUMENTS_OBJECT:
14840 case Translation::CAPTURED_OBJECT: {
14841 int args_length = iterator.Next();
14842 os << "{length=" << args_length << "}";
14843 break;
14844 }
14845 }
14846 os << "\n";
14847 }
14848 }
14849 }
14850
14851
DeoptimizationOutputDataPrint(std::ostream & os)14852 void DeoptimizationOutputData::DeoptimizationOutputDataPrint(
14853 std::ostream& os) { // NOLINT
14854 os << "Deoptimization Output Data (deopt points = " << this->DeoptPoints()
14855 << ")\n";
14856 if (this->DeoptPoints() == 0) return;
14857
14858 os << "ast id pc state\n";
14859 for (int i = 0; i < this->DeoptPoints(); i++) {
14860 int pc_and_state = this->PcAndState(i)->value();
14861 os << std::setw(6) << this->AstId(i).ToInt() << " " << std::setw(8)
14862 << FullCodeGenerator::PcField::decode(pc_and_state) << " "
14863 << Deoptimizer::BailoutStateToString(
14864 FullCodeGenerator::BailoutStateField::decode(pc_and_state))
14865 << "\n";
14866 }
14867 }
14868
14869
HandlerTableRangePrint(std::ostream & os)14870 void HandlerTable::HandlerTableRangePrint(std::ostream& os) {
14871 os << " from to hdlr\n";
14872 for (int i = 0; i < length(); i += kRangeEntrySize) {
14873 int pc_start = Smi::cast(get(i + kRangeStartIndex))->value();
14874 int pc_end = Smi::cast(get(i + kRangeEndIndex))->value();
14875 int handler_field = Smi::cast(get(i + kRangeHandlerIndex))->value();
14876 int handler_offset = HandlerOffsetField::decode(handler_field);
14877 CatchPrediction prediction = HandlerPredictionField::decode(handler_field);
14878 int data = Smi::cast(get(i + kRangeDataIndex))->value();
14879 os << " (" << std::setw(4) << pc_start << "," << std::setw(4) << pc_end
14880 << ") -> " << std::setw(4) << handler_offset
14881 << " (prediction=" << prediction << ", data=" << data << ")\n";
14882 }
14883 }
14884
14885
HandlerTableReturnPrint(std::ostream & os)14886 void HandlerTable::HandlerTableReturnPrint(std::ostream& os) {
14887 os << " off hdlr (c)\n";
14888 for (int i = 0; i < length(); i += kReturnEntrySize) {
14889 int pc_offset = Smi::cast(get(i + kReturnOffsetIndex))->value();
14890 int handler_field = Smi::cast(get(i + kReturnHandlerIndex))->value();
14891 int handler_offset = HandlerOffsetField::decode(handler_field);
14892 CatchPrediction prediction = HandlerPredictionField::decode(handler_field);
14893 os << " " << std::setw(4) << pc_offset << " -> " << std::setw(4)
14894 << handler_offset << " (prediction=" << prediction << ")\n";
14895 }
14896 }
14897
14898
Disassemble(const char * name,std::ostream & os)14899 void Code::Disassemble(const char* name, std::ostream& os) { // NOLINT
14900 os << "kind = " << Kind2String(kind()) << "\n";
14901 if (IsCodeStubOrIC()) {
14902 const char* n = CodeStub::MajorName(CodeStub::GetMajorKey(this));
14903 os << "major_key = " << (n == NULL ? "null" : n) << "\n";
14904 }
14905 if (is_inline_cache_stub()) {
14906 if (!IC::ICUseVector(kind())) {
14907 InlineCacheState ic_state = IC::StateFromCode(this);
14908 os << "ic_state = " << ICState2String(ic_state) << "\n";
14909 }
14910 PrintExtraICState(os, kind(), extra_ic_state());
14911 if (is_compare_ic_stub()) {
14912 DCHECK(CodeStub::GetMajorKey(this) == CodeStub::CompareIC);
14913 CompareICStub stub(stub_key(), GetIsolate());
14914 os << "compare_state = " << CompareICState::GetStateName(stub.left())
14915 << "*" << CompareICState::GetStateName(stub.right()) << " -> "
14916 << CompareICState::GetStateName(stub.state()) << "\n";
14917 os << "compare_operation = " << Token::Name(stub.op()) << "\n";
14918 }
14919 }
14920 if ((name != nullptr) && (name[0] != '\0')) {
14921 os << "name = " << name << "\n";
14922 } else if (kind() == BUILTIN) {
14923 name = GetIsolate()->builtins()->Lookup(instruction_start());
14924 if (name != nullptr) {
14925 os << "name = " << name << "\n";
14926 }
14927 } else if (kind() == BYTECODE_HANDLER) {
14928 name = GetIsolate()->interpreter()->LookupNameOfBytecodeHandler(this);
14929 if (name != nullptr) {
14930 os << "name = " << name << "\n";
14931 }
14932 }
14933 if (kind() == OPTIMIZED_FUNCTION) {
14934 os << "stack_slots = " << stack_slots() << "\n";
14935 }
14936 os << "compiler = " << (is_turbofanned()
14937 ? "turbofan"
14938 : is_crankshafted() ? "crankshaft"
14939 : kind() == Code::FUNCTION
14940 ? "full-codegen"
14941 : "unknown") << "\n";
14942
14943 os << "Instructions (size = " << instruction_size() << ")\n";
14944 {
14945 Isolate* isolate = GetIsolate();
14946 int size = instruction_size();
14947 int safepoint_offset =
14948 is_crankshafted() ? static_cast<int>(safepoint_table_offset()) : size;
14949 int back_edge_offset = (kind() == Code::FUNCTION)
14950 ? static_cast<int>(back_edge_table_offset())
14951 : size;
14952 int constant_pool_offset = FLAG_enable_embedded_constant_pool
14953 ? this->constant_pool_offset()
14954 : size;
14955
14956 // Stop before reaching any embedded tables
14957 int code_size = Min(safepoint_offset, back_edge_offset);
14958 code_size = Min(code_size, constant_pool_offset);
14959 byte* begin = instruction_start();
14960 byte* end = begin + code_size;
14961 Disassembler::Decode(isolate, &os, begin, end, this);
14962
14963 if (constant_pool_offset < size) {
14964 int constant_pool_size = size - constant_pool_offset;
14965 DCHECK((constant_pool_size & kPointerAlignmentMask) == 0);
14966 os << "\nConstant Pool (size = " << constant_pool_size << ")\n";
14967 Vector<char> buf = Vector<char>::New(50);
14968 intptr_t* ptr = reinterpret_cast<intptr_t*>(begin + constant_pool_offset);
14969 for (int i = 0; i < constant_pool_size; i += kPointerSize, ptr++) {
14970 SNPrintF(buf, "%4d %08" V8PRIxPTR, i, *ptr);
14971 os << static_cast<const void*>(ptr) << " " << buf.start() << "\n";
14972 }
14973 }
14974 }
14975 os << "\n";
14976
14977 SourcePositionTableIterator it(source_position_table());
14978 if (!it.done()) {
14979 os << "Source positions:\n pc offset position\n";
14980 for (; !it.done(); it.Advance()) {
14981 os << std::setw(10) << it.code_offset() << std::setw(10)
14982 << it.source_position().ScriptOffset()
14983 << (it.is_statement() ? " statement" : "") << "\n";
14984 }
14985 os << "\n";
14986 }
14987
14988 if (kind() == FUNCTION) {
14989 DeoptimizationOutputData* data =
14990 DeoptimizationOutputData::cast(this->deoptimization_data());
14991 data->DeoptimizationOutputDataPrint(os);
14992 } else if (kind() == OPTIMIZED_FUNCTION) {
14993 DeoptimizationInputData* data =
14994 DeoptimizationInputData::cast(this->deoptimization_data());
14995 data->DeoptimizationInputDataPrint(os);
14996 }
14997 os << "\n";
14998
14999 if (is_crankshafted()) {
15000 SafepointTable table(this);
15001 os << "Safepoints (size = " << table.size() << ")\n";
15002 for (unsigned i = 0; i < table.length(); i++) {
15003 unsigned pc_offset = table.GetPcOffset(i);
15004 os << static_cast<const void*>(instruction_start() + pc_offset) << " ";
15005 os << std::setw(4) << pc_offset << " ";
15006 table.PrintEntry(i, os);
15007 os << " (sp -> fp) ";
15008 SafepointEntry entry = table.GetEntry(i);
15009 if (entry.deoptimization_index() != Safepoint::kNoDeoptimizationIndex) {
15010 os << std::setw(6) << entry.deoptimization_index();
15011 } else {
15012 os << "<none>";
15013 }
15014 if (entry.argument_count() > 0) {
15015 os << " argc: " << entry.argument_count();
15016 }
15017 os << "\n";
15018 }
15019 os << "\n";
15020 } else if (kind() == FUNCTION) {
15021 unsigned offset = back_edge_table_offset();
15022 // If there is no back edge table, the "table start" will be at or after
15023 // (due to alignment) the end of the instruction stream.
15024 if (static_cast<int>(offset) < instruction_size()) {
15025 DisallowHeapAllocation no_gc;
15026 BackEdgeTable back_edges(this, &no_gc);
15027
15028 os << "Back edges (size = " << back_edges.length() << ")\n";
15029 os << "ast_id pc_offset loop_depth\n";
15030
15031 for (uint32_t i = 0; i < back_edges.length(); i++) {
15032 os << std::setw(6) << back_edges.ast_id(i).ToInt() << " "
15033 << std::setw(9) << back_edges.pc_offset(i) << " " << std::setw(10)
15034 << back_edges.loop_depth(i) << "\n";
15035 }
15036
15037 os << "\n";
15038 }
15039 #ifdef OBJECT_PRINT
15040 if (!type_feedback_info()->IsUndefined(GetIsolate())) {
15041 TypeFeedbackInfo::cast(type_feedback_info())->TypeFeedbackInfoPrint(os);
15042 os << "\n";
15043 }
15044 #endif
15045 }
15046
15047 if (handler_table()->length() > 0) {
15048 os << "Handler Table (size = " << handler_table()->Size() << ")\n";
15049 if (kind() == FUNCTION) {
15050 HandlerTable::cast(handler_table())->HandlerTableRangePrint(os);
15051 } else if (kind() == OPTIMIZED_FUNCTION) {
15052 HandlerTable::cast(handler_table())->HandlerTableReturnPrint(os);
15053 }
15054 os << "\n";
15055 }
15056
15057 os << "RelocInfo (size = " << relocation_size() << ")\n";
15058 for (RelocIterator it(this); !it.done(); it.next()) {
15059 it.rinfo()->Print(GetIsolate(), os);
15060 }
15061 os << "\n";
15062
15063 if (has_unwinding_info()) {
15064 os << "UnwindingInfo (size = " << unwinding_info_size() << ")\n";
15065 EhFrameDisassembler eh_frame_disassembler(unwinding_info_start(),
15066 unwinding_info_end());
15067 eh_frame_disassembler.DisassembleToStream(os);
15068 os << "\n";
15069 }
15070 }
15071 #endif // ENABLE_DISASSEMBLER
15072
15073
Disassemble(std::ostream & os)15074 void BytecodeArray::Disassemble(std::ostream& os) {
15075 os << "Parameter count " << parameter_count() << "\n";
15076 os << "Frame size " << frame_size() << "\n";
15077
15078 const uint8_t* base_address = GetFirstBytecodeAddress();
15079 SourcePositionTableIterator source_positions(source_position_table());
15080
15081 interpreter::BytecodeArrayIterator iterator(handle(this));
15082 while (!iterator.done()) {
15083 if (!source_positions.done() &&
15084 iterator.current_offset() == source_positions.code_offset()) {
15085 os << std::setw(5) << source_positions.source_position().ScriptOffset();
15086 os << (source_positions.is_statement() ? " S> " : " E> ");
15087 source_positions.Advance();
15088 } else {
15089 os << " ";
15090 }
15091 const uint8_t* current_address = base_address + iterator.current_offset();
15092 os << reinterpret_cast<const void*>(current_address) << " @ "
15093 << std::setw(4) << iterator.current_offset() << " : ";
15094 interpreter::BytecodeDecoder::Decode(os, current_address,
15095 parameter_count());
15096 if (interpreter::Bytecodes::IsJump(iterator.current_bytecode())) {
15097 const void* jump_target = base_address + iterator.GetJumpTargetOffset();
15098 os << " (" << jump_target << " @ " << iterator.GetJumpTargetOffset()
15099 << ")";
15100 }
15101 os << std::endl;
15102 iterator.Advance();
15103 }
15104
15105 if (constant_pool()->length() > 0) {
15106 os << "Constant pool (size = " << constant_pool()->length() << ")\n";
15107 constant_pool()->Print();
15108 }
15109
15110 #ifdef ENABLE_DISASSEMBLER
15111 if (handler_table()->length() > 0) {
15112 os << "Handler Table (size = " << handler_table()->Size() << ")\n";
15113 HandlerTable::cast(handler_table())->HandlerTableRangePrint(os);
15114 }
15115 #endif
15116 }
15117
CopyBytecodesTo(BytecodeArray * to)15118 void BytecodeArray::CopyBytecodesTo(BytecodeArray* to) {
15119 BytecodeArray* from = this;
15120 DCHECK_EQ(from->length(), to->length());
15121 CopyBytes(to->GetFirstBytecodeAddress(), from->GetFirstBytecodeAddress(),
15122 from->length());
15123 }
15124
LookupRangeInHandlerTable(int code_offset,int * data,HandlerTable::CatchPrediction * prediction)15125 int BytecodeArray::LookupRangeInHandlerTable(
15126 int code_offset, int* data, HandlerTable::CatchPrediction* prediction) {
15127 HandlerTable* table = HandlerTable::cast(handler_table());
15128 code_offset++; // Point after current bytecode.
15129 return table->LookupRange(code_offset, data, prediction);
15130 }
15131
15132 // static
Initialize(Handle<JSArray> array,int capacity,int length)15133 void JSArray::Initialize(Handle<JSArray> array, int capacity, int length) {
15134 DCHECK(capacity >= 0);
15135 array->GetIsolate()->factory()->NewJSArrayStorage(
15136 array, length, capacity, INITIALIZE_ARRAY_ELEMENTS_WITH_HOLE);
15137 }
15138
SetLength(Handle<JSArray> array,uint32_t new_length)15139 void JSArray::SetLength(Handle<JSArray> array, uint32_t new_length) {
15140 // We should never end in here with a pixel or external array.
15141 DCHECK(array->AllowsSetLength());
15142 if (array->SetLengthWouldNormalize(new_length)) {
15143 JSObject::NormalizeElements(array);
15144 }
15145 array->GetElementsAccessor()->SetLength(array, new_length);
15146 }
15147
15148
15149 // static
AddDependentCode(Handle<Map> map,DependentCode::DependencyGroup group,Handle<Code> code)15150 void Map::AddDependentCode(Handle<Map> map,
15151 DependentCode::DependencyGroup group,
15152 Handle<Code> code) {
15153 Handle<WeakCell> cell = Code::WeakCellFor(code);
15154 Handle<DependentCode> codes = DependentCode::InsertWeakCode(
15155 Handle<DependentCode>(map->dependent_code()), group, cell);
15156 if (*codes != map->dependent_code()) map->set_dependent_code(*codes);
15157 }
15158
15159
InsertCompilationDependencies(Handle<DependentCode> entries,DependencyGroup group,Handle<Foreign> info)15160 Handle<DependentCode> DependentCode::InsertCompilationDependencies(
15161 Handle<DependentCode> entries, DependencyGroup group,
15162 Handle<Foreign> info) {
15163 return Insert(entries, group, info);
15164 }
15165
15166
InsertWeakCode(Handle<DependentCode> entries,DependencyGroup group,Handle<WeakCell> code_cell)15167 Handle<DependentCode> DependentCode::InsertWeakCode(
15168 Handle<DependentCode> entries, DependencyGroup group,
15169 Handle<WeakCell> code_cell) {
15170 return Insert(entries, group, code_cell);
15171 }
15172
15173
Insert(Handle<DependentCode> entries,DependencyGroup group,Handle<Object> object)15174 Handle<DependentCode> DependentCode::Insert(Handle<DependentCode> entries,
15175 DependencyGroup group,
15176 Handle<Object> object) {
15177 if (entries->length() == 0 || entries->group() > group) {
15178 // There is no such group.
15179 return DependentCode::New(group, object, entries);
15180 }
15181 if (entries->group() < group) {
15182 // The group comes later in the list.
15183 Handle<DependentCode> old_next(entries->next_link());
15184 Handle<DependentCode> new_next = Insert(old_next, group, object);
15185 if (!old_next.is_identical_to(new_next)) {
15186 entries->set_next_link(*new_next);
15187 }
15188 return entries;
15189 }
15190 DCHECK_EQ(group, entries->group());
15191 int count = entries->count();
15192 // Check for existing entry to avoid duplicates.
15193 for (int i = 0; i < count; i++) {
15194 if (entries->object_at(i) == *object) return entries;
15195 }
15196 if (entries->length() < kCodesStartIndex + count + 1) {
15197 entries = EnsureSpace(entries);
15198 // Count could have changed, reload it.
15199 count = entries->count();
15200 }
15201 entries->set_object_at(count, *object);
15202 entries->set_count(count + 1);
15203 return entries;
15204 }
15205
15206
New(DependencyGroup group,Handle<Object> object,Handle<DependentCode> next)15207 Handle<DependentCode> DependentCode::New(DependencyGroup group,
15208 Handle<Object> object,
15209 Handle<DependentCode> next) {
15210 Isolate* isolate = next->GetIsolate();
15211 Handle<DependentCode> result = Handle<DependentCode>::cast(
15212 isolate->factory()->NewFixedArray(kCodesStartIndex + 1, TENURED));
15213 result->set_next_link(*next);
15214 result->set_flags(GroupField::encode(group) | CountField::encode(1));
15215 result->set_object_at(0, *object);
15216 return result;
15217 }
15218
15219
EnsureSpace(Handle<DependentCode> entries)15220 Handle<DependentCode> DependentCode::EnsureSpace(
15221 Handle<DependentCode> entries) {
15222 if (entries->Compact()) return entries;
15223 Isolate* isolate = entries->GetIsolate();
15224 int capacity = kCodesStartIndex + DependentCode::Grow(entries->count());
15225 int grow_by = capacity - entries->length();
15226 return Handle<DependentCode>::cast(
15227 isolate->factory()->CopyFixedArrayAndGrow(entries, grow_by, TENURED));
15228 }
15229
15230
Compact()15231 bool DependentCode::Compact() {
15232 int old_count = count();
15233 int new_count = 0;
15234 for (int i = 0; i < old_count; i++) {
15235 Object* obj = object_at(i);
15236 if (!obj->IsWeakCell() || !WeakCell::cast(obj)->cleared()) {
15237 if (i != new_count) {
15238 copy(i, new_count);
15239 }
15240 new_count++;
15241 }
15242 }
15243 set_count(new_count);
15244 for (int i = new_count; i < old_count; i++) {
15245 clear_at(i);
15246 }
15247 return new_count < old_count;
15248 }
15249
15250
UpdateToFinishedCode(DependencyGroup group,Foreign * info,WeakCell * code_cell)15251 void DependentCode::UpdateToFinishedCode(DependencyGroup group, Foreign* info,
15252 WeakCell* code_cell) {
15253 if (this->length() == 0 || this->group() > group) {
15254 // There is no such group.
15255 return;
15256 }
15257 if (this->group() < group) {
15258 // The group comes later in the list.
15259 next_link()->UpdateToFinishedCode(group, info, code_cell);
15260 return;
15261 }
15262 DCHECK_EQ(group, this->group());
15263 DisallowHeapAllocation no_gc;
15264 int count = this->count();
15265 for (int i = 0; i < count; i++) {
15266 if (object_at(i) == info) {
15267 set_object_at(i, code_cell);
15268 break;
15269 }
15270 }
15271 #ifdef DEBUG
15272 for (int i = 0; i < count; i++) {
15273 DCHECK(object_at(i) != info);
15274 }
15275 #endif
15276 }
15277
15278
RemoveCompilationDependencies(DependentCode::DependencyGroup group,Foreign * info)15279 void DependentCode::RemoveCompilationDependencies(
15280 DependentCode::DependencyGroup group, Foreign* info) {
15281 if (this->length() == 0 || this->group() > group) {
15282 // There is no such group.
15283 return;
15284 }
15285 if (this->group() < group) {
15286 // The group comes later in the list.
15287 next_link()->RemoveCompilationDependencies(group, info);
15288 return;
15289 }
15290 DCHECK_EQ(group, this->group());
15291 DisallowHeapAllocation no_allocation;
15292 int old_count = count();
15293 // Find compilation info wrapper.
15294 int info_pos = -1;
15295 for (int i = 0; i < old_count; i++) {
15296 if (object_at(i) == info) {
15297 info_pos = i;
15298 break;
15299 }
15300 }
15301 if (info_pos == -1) return; // Not found.
15302 // Use the last code to fill the gap.
15303 if (info_pos < old_count - 1) {
15304 copy(old_count - 1, info_pos);
15305 }
15306 clear_at(old_count - 1);
15307 set_count(old_count - 1);
15308
15309 #ifdef DEBUG
15310 for (int i = 0; i < old_count - 1; i++) {
15311 DCHECK(object_at(i) != info);
15312 }
15313 #endif
15314 }
15315
15316
Contains(DependencyGroup group,WeakCell * code_cell)15317 bool DependentCode::Contains(DependencyGroup group, WeakCell* code_cell) {
15318 if (this->length() == 0 || this->group() > group) {
15319 // There is no such group.
15320 return false;
15321 }
15322 if (this->group() < group) {
15323 // The group comes later in the list.
15324 return next_link()->Contains(group, code_cell);
15325 }
15326 DCHECK_EQ(group, this->group());
15327 int count = this->count();
15328 for (int i = 0; i < count; i++) {
15329 if (object_at(i) == code_cell) return true;
15330 }
15331 return false;
15332 }
15333
15334
IsEmpty(DependencyGroup group)15335 bool DependentCode::IsEmpty(DependencyGroup group) {
15336 if (this->length() == 0 || this->group() > group) {
15337 // There is no such group.
15338 return true;
15339 }
15340 if (this->group() < group) {
15341 // The group comes later in the list.
15342 return next_link()->IsEmpty(group);
15343 }
15344 DCHECK_EQ(group, this->group());
15345 return count() == 0;
15346 }
15347
15348
MarkCodeForDeoptimization(Isolate * isolate,DependentCode::DependencyGroup group)15349 bool DependentCode::MarkCodeForDeoptimization(
15350 Isolate* isolate,
15351 DependentCode::DependencyGroup group) {
15352 if (this->length() == 0 || this->group() > group) {
15353 // There is no such group.
15354 return false;
15355 }
15356 if (this->group() < group) {
15357 // The group comes later in the list.
15358 return next_link()->MarkCodeForDeoptimization(isolate, group);
15359 }
15360 DCHECK_EQ(group, this->group());
15361 DisallowHeapAllocation no_allocation_scope;
15362 // Mark all the code that needs to be deoptimized.
15363 bool marked = false;
15364 bool invalidate_embedded_objects = group == kWeakCodeGroup;
15365 int count = this->count();
15366 for (int i = 0; i < count; i++) {
15367 Object* obj = object_at(i);
15368 if (obj->IsWeakCell()) {
15369 WeakCell* cell = WeakCell::cast(obj);
15370 if (cell->cleared()) continue;
15371 Code* code = Code::cast(cell->value());
15372 if (!code->marked_for_deoptimization()) {
15373 SetMarkedForDeoptimization(code, group);
15374 if (invalidate_embedded_objects) {
15375 code->InvalidateEmbeddedObjects();
15376 }
15377 marked = true;
15378 }
15379 } else {
15380 DCHECK(obj->IsForeign());
15381 CompilationDependencies* info =
15382 reinterpret_cast<CompilationDependencies*>(
15383 Foreign::cast(obj)->foreign_address());
15384 info->Abort();
15385 }
15386 }
15387 for (int i = 0; i < count; i++) {
15388 clear_at(i);
15389 }
15390 set_count(0);
15391 return marked;
15392 }
15393
15394
DeoptimizeDependentCodeGroup(Isolate * isolate,DependentCode::DependencyGroup group)15395 void DependentCode::DeoptimizeDependentCodeGroup(
15396 Isolate* isolate,
15397 DependentCode::DependencyGroup group) {
15398 DCHECK(AllowCodeDependencyChange::IsAllowed());
15399 DisallowHeapAllocation no_allocation_scope;
15400 bool marked = MarkCodeForDeoptimization(isolate, group);
15401 if (marked) Deoptimizer::DeoptimizeMarkedCode(isolate);
15402 }
15403
15404
SetMarkedForDeoptimization(Code * code,DependencyGroup group)15405 void DependentCode::SetMarkedForDeoptimization(Code* code,
15406 DependencyGroup group) {
15407 code->set_marked_for_deoptimization(true);
15408 if (FLAG_trace_deopt &&
15409 (code->deoptimization_data() != code->GetHeap()->empty_fixed_array())) {
15410 DeoptimizationInputData* deopt_data =
15411 DeoptimizationInputData::cast(code->deoptimization_data());
15412 CodeTracer::Scope scope(code->GetHeap()->isolate()->GetCodeTracer());
15413 PrintF(scope.file(), "[marking dependent code 0x%08" V8PRIxPTR
15414 " (opt #%d) for deoptimization, reason: %s]\n",
15415 reinterpret_cast<intptr_t>(code),
15416 deopt_data->OptimizationId()->value(), DependencyGroupName(group));
15417 }
15418 }
15419
15420
DependencyGroupName(DependencyGroup group)15421 const char* DependentCode::DependencyGroupName(DependencyGroup group) {
15422 switch (group) {
15423 case kWeakCodeGroup:
15424 return "weak-code";
15425 case kTransitionGroup:
15426 return "transition";
15427 case kPrototypeCheckGroup:
15428 return "prototype-check";
15429 case kPropertyCellChangedGroup:
15430 return "property-cell-changed";
15431 case kFieldOwnerGroup:
15432 return "field-owner";
15433 case kInitialMapChangedGroup:
15434 return "initial-map-changed";
15435 case kAllocationSiteTenuringChangedGroup:
15436 return "allocation-site-tenuring-changed";
15437 case kAllocationSiteTransitionChangedGroup:
15438 return "allocation-site-transition-changed";
15439 }
15440 UNREACHABLE();
15441 return "?";
15442 }
15443
15444
TransitionToPrototype(Handle<Map> map,Handle<Object> prototype,PrototypeOptimizationMode mode)15445 Handle<Map> Map::TransitionToPrototype(Handle<Map> map,
15446 Handle<Object> prototype,
15447 PrototypeOptimizationMode mode) {
15448 Handle<Map> new_map = TransitionArray::GetPrototypeTransition(map, prototype);
15449 if (new_map.is_null()) {
15450 new_map = Copy(map, "TransitionToPrototype");
15451 TransitionArray::PutPrototypeTransition(map, prototype, new_map);
15452 Map::SetPrototype(new_map, prototype, mode);
15453 }
15454 return new_map;
15455 }
15456
15457
SetPrototype(Handle<JSReceiver> object,Handle<Object> value,bool from_javascript,ShouldThrow should_throw)15458 Maybe<bool> JSReceiver::SetPrototype(Handle<JSReceiver> object,
15459 Handle<Object> value, bool from_javascript,
15460 ShouldThrow should_throw) {
15461 if (object->IsJSProxy()) {
15462 return JSProxy::SetPrototype(Handle<JSProxy>::cast(object), value,
15463 from_javascript, should_throw);
15464 }
15465 return JSObject::SetPrototype(Handle<JSObject>::cast(object), value,
15466 from_javascript, should_throw);
15467 }
15468
15469
15470 // ES6: 9.5.2 [[SetPrototypeOf]] (V)
15471 // static
SetPrototype(Handle<JSProxy> proxy,Handle<Object> value,bool from_javascript,ShouldThrow should_throw)15472 Maybe<bool> JSProxy::SetPrototype(Handle<JSProxy> proxy, Handle<Object> value,
15473 bool from_javascript,
15474 ShouldThrow should_throw) {
15475 Isolate* isolate = proxy->GetIsolate();
15476 STACK_CHECK(isolate, Nothing<bool>());
15477 Handle<Name> trap_name = isolate->factory()->setPrototypeOf_string();
15478 // 1. Assert: Either Type(V) is Object or Type(V) is Null.
15479 DCHECK(value->IsJSReceiver() || value->IsNull(isolate));
15480 // 2. Let handler be the value of the [[ProxyHandler]] internal slot of O.
15481 Handle<Object> handler(proxy->handler(), isolate);
15482 // 3. If handler is null, throw a TypeError exception.
15483 // 4. Assert: Type(handler) is Object.
15484 if (proxy->IsRevoked()) {
15485 isolate->Throw(*isolate->factory()->NewTypeError(
15486 MessageTemplate::kProxyRevoked, trap_name));
15487 return Nothing<bool>();
15488 }
15489 // 5. Let target be the value of the [[ProxyTarget]] internal slot.
15490 Handle<JSReceiver> target(proxy->target(), isolate);
15491 // 6. Let trap be ? GetMethod(handler, "getPrototypeOf").
15492 Handle<Object> trap;
15493 ASSIGN_RETURN_ON_EXCEPTION_VALUE(
15494 isolate, trap,
15495 Object::GetMethod(Handle<JSReceiver>::cast(handler), trap_name),
15496 Nothing<bool>());
15497 // 7. If trap is undefined, then return target.[[SetPrototypeOf]]().
15498 if (trap->IsUndefined(isolate)) {
15499 return JSReceiver::SetPrototype(target, value, from_javascript,
15500 should_throw);
15501 }
15502 // 8. Let booleanTrapResult be ToBoolean(? Call(trap, handler, «target, V»)).
15503 Handle<Object> argv[] = {target, value};
15504 Handle<Object> trap_result;
15505 ASSIGN_RETURN_ON_EXCEPTION_VALUE(
15506 isolate, trap_result,
15507 Execution::Call(isolate, trap, handler, arraysize(argv), argv),
15508 Nothing<bool>());
15509 bool bool_trap_result = trap_result->BooleanValue();
15510 // 9. If booleanTrapResult is false, return false.
15511 if (!bool_trap_result) {
15512 RETURN_FAILURE(
15513 isolate, should_throw,
15514 NewTypeError(MessageTemplate::kProxyTrapReturnedFalsish, trap_name));
15515 }
15516 // 10. Let extensibleTarget be ? IsExtensible(target).
15517 Maybe<bool> is_extensible = JSReceiver::IsExtensible(target);
15518 if (is_extensible.IsNothing()) return Nothing<bool>();
15519 // 11. If extensibleTarget is true, return true.
15520 if (is_extensible.FromJust()) {
15521 if (bool_trap_result) return Just(true);
15522 RETURN_FAILURE(
15523 isolate, should_throw,
15524 NewTypeError(MessageTemplate::kProxyTrapReturnedFalsish, trap_name));
15525 }
15526 // 12. Let targetProto be ? target.[[GetPrototypeOf]]().
15527 Handle<Object> target_proto;
15528 ASSIGN_RETURN_ON_EXCEPTION_VALUE(isolate, target_proto,
15529 JSReceiver::GetPrototype(isolate, target),
15530 Nothing<bool>());
15531 // 13. If SameValue(V, targetProto) is false, throw a TypeError exception.
15532 if (bool_trap_result && !value->SameValue(*target_proto)) {
15533 isolate->Throw(*isolate->factory()->NewTypeError(
15534 MessageTemplate::kProxySetPrototypeOfNonExtensible));
15535 return Nothing<bool>();
15536 }
15537 // 14. Return true.
15538 return Just(true);
15539 }
15540
15541
SetPrototype(Handle<JSObject> object,Handle<Object> value,bool from_javascript,ShouldThrow should_throw)15542 Maybe<bool> JSObject::SetPrototype(Handle<JSObject> object,
15543 Handle<Object> value, bool from_javascript,
15544 ShouldThrow should_throw) {
15545 Isolate* isolate = object->GetIsolate();
15546
15547 #ifdef DEBUG
15548 int size = object->Size();
15549 #endif
15550
15551 if (from_javascript) {
15552 if (object->IsAccessCheckNeeded() &&
15553 !isolate->MayAccess(handle(isolate->context()), object)) {
15554 isolate->ReportFailedAccessCheck(object);
15555 RETURN_VALUE_IF_SCHEDULED_EXCEPTION(isolate, Nothing<bool>());
15556 RETURN_FAILURE(isolate, should_throw,
15557 NewTypeError(MessageTemplate::kNoAccess));
15558 }
15559 } else {
15560 DCHECK(!object->IsAccessCheckNeeded());
15561 }
15562
15563 Heap* heap = isolate->heap();
15564 // Silently ignore the change if value is not a JSObject or null.
15565 // SpiderMonkey behaves this way.
15566 if (!value->IsJSReceiver() && !value->IsNull(isolate)) return Just(true);
15567
15568 bool dictionary_elements_in_chain =
15569 object->map()->DictionaryElementsInPrototypeChainOnly();
15570
15571 bool all_extensible = object->map()->is_extensible();
15572 Handle<JSObject> real_receiver = object;
15573 if (from_javascript) {
15574 // Find the first object in the chain whose prototype object is not
15575 // hidden.
15576 PrototypeIterator iter(isolate, real_receiver, kStartAtPrototype,
15577 PrototypeIterator::END_AT_NON_HIDDEN);
15578 while (!iter.IsAtEnd()) {
15579 // Casting to JSObject is fine because hidden prototypes are never
15580 // JSProxies.
15581 real_receiver = PrototypeIterator::GetCurrent<JSObject>(iter);
15582 iter.Advance();
15583 all_extensible = all_extensible && real_receiver->map()->is_extensible();
15584 }
15585 }
15586 Handle<Map> map(real_receiver->map());
15587
15588 // Nothing to do if prototype is already set.
15589 if (map->prototype() == *value) return Just(true);
15590
15591 bool immutable_proto = map->is_immutable_proto();
15592 if (immutable_proto) {
15593 RETURN_FAILURE(
15594 isolate, should_throw,
15595 NewTypeError(MessageTemplate::kImmutablePrototypeSet, object));
15596 }
15597
15598 // From 8.6.2 Object Internal Methods
15599 // ...
15600 // In addition, if [[Extensible]] is false the value of the [[Class]] and
15601 // [[Prototype]] internal properties of the object may not be modified.
15602 // ...
15603 // Implementation specific extensions that modify [[Class]], [[Prototype]]
15604 // or [[Extensible]] must not violate the invariants defined in the preceding
15605 // paragraph.
15606 if (!all_extensible) {
15607 RETURN_FAILURE(isolate, should_throw,
15608 NewTypeError(MessageTemplate::kNonExtensibleProto, object));
15609 }
15610
15611 // Before we can set the prototype we need to be sure prototype cycles are
15612 // prevented. It is sufficient to validate that the receiver is not in the
15613 // new prototype chain.
15614 if (value->IsJSReceiver()) {
15615 for (PrototypeIterator iter(isolate, JSReceiver::cast(*value),
15616 kStartAtReceiver);
15617 !iter.IsAtEnd(); iter.Advance()) {
15618 if (iter.GetCurrent<JSReceiver>() == *object) {
15619 // Cycle detected.
15620 RETURN_FAILURE(isolate, should_throw,
15621 NewTypeError(MessageTemplate::kCyclicProto));
15622 }
15623 }
15624 }
15625
15626 // Set the new prototype of the object.
15627
15628 isolate->UpdateArrayProtectorOnSetPrototype(real_receiver);
15629
15630 PrototypeOptimizationMode mode =
15631 from_javascript ? REGULAR_PROTOTYPE : FAST_PROTOTYPE;
15632 Handle<Map> new_map = Map::TransitionToPrototype(map, value, mode);
15633 DCHECK(new_map->prototype() == *value);
15634 JSObject::MigrateToMap(real_receiver, new_map);
15635
15636 if (from_javascript && !dictionary_elements_in_chain &&
15637 new_map->DictionaryElementsInPrototypeChainOnly()) {
15638 // If the prototype chain didn't previously have element callbacks, then
15639 // KeyedStoreICs need to be cleared to ensure any that involve this
15640 // map go generic.
15641 TypeFeedbackVector::ClearAllKeyedStoreICs(isolate);
15642 }
15643
15644 heap->ClearInstanceofCache();
15645 DCHECK(size == object->Size());
15646 return Just(true);
15647 }
15648
15649 // static
SetImmutableProto(Handle<JSObject> object)15650 void JSObject::SetImmutableProto(Handle<JSObject> object) {
15651 DCHECK(!object->IsAccessCheckNeeded()); // Never called from JS
15652 Handle<Map> map(object->map());
15653
15654 // Nothing to do if prototype is already set.
15655 if (map->is_immutable_proto()) return;
15656
15657 Handle<Map> new_map = Map::TransitionToImmutableProto(map);
15658 object->set_map(*new_map);
15659 }
15660
EnsureCanContainElements(Handle<JSObject> object,Arguments * args,uint32_t first_arg,uint32_t arg_count,EnsureElementsMode mode)15661 void JSObject::EnsureCanContainElements(Handle<JSObject> object,
15662 Arguments* args,
15663 uint32_t first_arg,
15664 uint32_t arg_count,
15665 EnsureElementsMode mode) {
15666 // Elements in |Arguments| are ordered backwards (because they're on the
15667 // stack), but the method that's called here iterates over them in forward
15668 // direction.
15669 return EnsureCanContainElements(
15670 object, args->arguments() - first_arg - (arg_count - 1), arg_count, mode);
15671 }
15672
15673
GetElementsAccessor()15674 ElementsAccessor* JSObject::GetElementsAccessor() {
15675 return ElementsAccessor::ForKind(GetElementsKind());
15676 }
15677
15678
ValidateElements(Handle<JSObject> object)15679 void JSObject::ValidateElements(Handle<JSObject> object) {
15680 #ifdef ENABLE_SLOW_DCHECKS
15681 if (FLAG_enable_slow_asserts) {
15682 ElementsAccessor* accessor = object->GetElementsAccessor();
15683 accessor->Validate(object);
15684 }
15685 #endif
15686 }
15687
15688
ShouldConvertToSlowElements(JSObject * object,uint32_t capacity,uint32_t index,uint32_t * new_capacity)15689 static bool ShouldConvertToSlowElements(JSObject* object, uint32_t capacity,
15690 uint32_t index,
15691 uint32_t* new_capacity) {
15692 STATIC_ASSERT(JSObject::kMaxUncheckedOldFastElementsLength <=
15693 JSObject::kMaxUncheckedFastElementsLength);
15694 if (index < capacity) {
15695 *new_capacity = capacity;
15696 return false;
15697 }
15698 if (index - capacity >= JSObject::kMaxGap) return true;
15699 *new_capacity = JSObject::NewElementsCapacity(index + 1);
15700 DCHECK_LT(index, *new_capacity);
15701 if (*new_capacity <= JSObject::kMaxUncheckedOldFastElementsLength ||
15702 (*new_capacity <= JSObject::kMaxUncheckedFastElementsLength &&
15703 object->GetHeap()->InNewSpace(object))) {
15704 return false;
15705 }
15706 // If the fast-case backing storage takes up roughly three times as
15707 // much space (in machine words) as a dictionary backing storage
15708 // would, the object should have slow elements.
15709 int used_elements = object->GetFastElementsUsage();
15710 int dictionary_size = SeededNumberDictionary::ComputeCapacity(used_elements) *
15711 SeededNumberDictionary::kEntrySize;
15712 return 3 * static_cast<uint32_t>(dictionary_size) <= *new_capacity;
15713 }
15714
15715
WouldConvertToSlowElements(uint32_t index)15716 bool JSObject::WouldConvertToSlowElements(uint32_t index) {
15717 if (HasFastElements()) {
15718 Handle<FixedArrayBase> backing_store(FixedArrayBase::cast(elements()));
15719 uint32_t capacity = static_cast<uint32_t>(backing_store->length());
15720 uint32_t new_capacity;
15721 return ShouldConvertToSlowElements(this, capacity, index, &new_capacity);
15722 }
15723 return false;
15724 }
15725
15726
BestFittingFastElementsKind(JSObject * object)15727 static ElementsKind BestFittingFastElementsKind(JSObject* object) {
15728 if (object->HasSloppyArgumentsElements()) {
15729 return FAST_SLOPPY_ARGUMENTS_ELEMENTS;
15730 }
15731 if (object->HasStringWrapperElements()) {
15732 return FAST_STRING_WRAPPER_ELEMENTS;
15733 }
15734 DCHECK(object->HasDictionaryElements());
15735 SeededNumberDictionary* dictionary = object->element_dictionary();
15736 ElementsKind kind = FAST_HOLEY_SMI_ELEMENTS;
15737 for (int i = 0; i < dictionary->Capacity(); i++) {
15738 Object* key = dictionary->KeyAt(i);
15739 if (key->IsNumber()) {
15740 Object* value = dictionary->ValueAt(i);
15741 if (!value->IsNumber()) return FAST_HOLEY_ELEMENTS;
15742 if (!value->IsSmi()) {
15743 if (!FLAG_unbox_double_arrays) return FAST_HOLEY_ELEMENTS;
15744 kind = FAST_HOLEY_DOUBLE_ELEMENTS;
15745 }
15746 }
15747 }
15748 return kind;
15749 }
15750
15751
ShouldConvertToFastElements(JSObject * object,SeededNumberDictionary * dictionary,uint32_t index,uint32_t * new_capacity)15752 static bool ShouldConvertToFastElements(JSObject* object,
15753 SeededNumberDictionary* dictionary,
15754 uint32_t index,
15755 uint32_t* new_capacity) {
15756 // If properties with non-standard attributes or accessors were added, we
15757 // cannot go back to fast elements.
15758 if (dictionary->requires_slow_elements()) return false;
15759
15760 // Adding a property with this index will require slow elements.
15761 if (index >= static_cast<uint32_t>(Smi::kMaxValue)) return false;
15762
15763 if (object->IsJSArray()) {
15764 Object* length = JSArray::cast(object)->length();
15765 if (!length->IsSmi()) return false;
15766 *new_capacity = static_cast<uint32_t>(Smi::cast(length)->value());
15767 } else {
15768 *new_capacity = dictionary->max_number_key() + 1;
15769 }
15770 *new_capacity = Max(index + 1, *new_capacity);
15771
15772 uint32_t dictionary_size = static_cast<uint32_t>(dictionary->Capacity()) *
15773 SeededNumberDictionary::kEntrySize;
15774
15775 // Turn fast if the dictionary only saves 50% space.
15776 return 2 * dictionary_size >= *new_capacity;
15777 }
15778
15779
15780 // static
AddDataElement(Handle<JSObject> object,uint32_t index,Handle<Object> value,PropertyAttributes attributes)15781 MaybeHandle<Object> JSObject::AddDataElement(Handle<JSObject> object,
15782 uint32_t index,
15783 Handle<Object> value,
15784 PropertyAttributes attributes) {
15785 MAYBE_RETURN_NULL(
15786 AddDataElement(object, index, value, attributes, THROW_ON_ERROR));
15787 return value;
15788 }
15789
15790
15791 // static
AddDataElement(Handle<JSObject> object,uint32_t index,Handle<Object> value,PropertyAttributes attributes,ShouldThrow should_throw)15792 Maybe<bool> JSObject::AddDataElement(Handle<JSObject> object, uint32_t index,
15793 Handle<Object> value,
15794 PropertyAttributes attributes,
15795 ShouldThrow should_throw) {
15796 DCHECK(object->map()->is_extensible());
15797
15798 Isolate* isolate = object->GetIsolate();
15799
15800 uint32_t old_length = 0;
15801 uint32_t new_capacity = 0;
15802
15803 if (object->IsJSArray()) {
15804 CHECK(JSArray::cast(*object)->length()->ToArrayLength(&old_length));
15805 }
15806
15807 ElementsKind kind = object->GetElementsKind();
15808 FixedArrayBase* elements = object->elements();
15809 ElementsKind dictionary_kind = DICTIONARY_ELEMENTS;
15810 if (IsSloppyArgumentsElements(kind)) {
15811 elements = FixedArrayBase::cast(FixedArray::cast(elements)->get(1));
15812 dictionary_kind = SLOW_SLOPPY_ARGUMENTS_ELEMENTS;
15813 } else if (IsStringWrapperElementsKind(kind)) {
15814 dictionary_kind = SLOW_STRING_WRAPPER_ELEMENTS;
15815 }
15816
15817 if (attributes != NONE) {
15818 kind = dictionary_kind;
15819 } else if (elements->IsSeededNumberDictionary()) {
15820 kind = ShouldConvertToFastElements(*object,
15821 SeededNumberDictionary::cast(elements),
15822 index, &new_capacity)
15823 ? BestFittingFastElementsKind(*object)
15824 : dictionary_kind; // Overwrite in case of arguments.
15825 } else if (ShouldConvertToSlowElements(
15826 *object, static_cast<uint32_t>(elements->length()), index,
15827 &new_capacity)) {
15828 kind = dictionary_kind;
15829 }
15830
15831 ElementsKind to = value->OptimalElementsKind();
15832 if (IsHoleyElementsKind(kind) || !object->IsJSArray() || index > old_length) {
15833 to = GetHoleyElementsKind(to);
15834 kind = GetHoleyElementsKind(kind);
15835 }
15836 to = GetMoreGeneralElementsKind(kind, to);
15837 ElementsAccessor* accessor = ElementsAccessor::ForKind(to);
15838 accessor->Add(object, index, value, attributes, new_capacity);
15839
15840 uint32_t new_length = old_length;
15841 Handle<Object> new_length_handle;
15842 if (object->IsJSArray() && index >= old_length) {
15843 new_length = index + 1;
15844 new_length_handle = isolate->factory()->NewNumberFromUint(new_length);
15845 JSArray::cast(*object)->set_length(*new_length_handle);
15846 }
15847
15848 return Just(true);
15849 }
15850
15851
SetLengthWouldNormalize(uint32_t new_length)15852 bool JSArray::SetLengthWouldNormalize(uint32_t new_length) {
15853 if (!HasFastElements()) return false;
15854 uint32_t capacity = static_cast<uint32_t>(elements()->length());
15855 uint32_t new_capacity;
15856 return JSArray::SetLengthWouldNormalize(GetHeap(), new_length) &&
15857 ShouldConvertToSlowElements(this, capacity, new_length - 1,
15858 &new_capacity);
15859 }
15860
15861
15862 const double AllocationSite::kPretenureRatio = 0.85;
15863
15864
ResetPretenureDecision()15865 void AllocationSite::ResetPretenureDecision() {
15866 set_pretenure_decision(kUndecided);
15867 set_memento_found_count(0);
15868 set_memento_create_count(0);
15869 }
15870
15871
GetPretenureMode()15872 PretenureFlag AllocationSite::GetPretenureMode() {
15873 PretenureDecision mode = pretenure_decision();
15874 // Zombie objects "decide" to be untenured.
15875 return mode == kTenure ? TENURED : NOT_TENURED;
15876 }
15877
15878
IsNestedSite()15879 bool AllocationSite::IsNestedSite() {
15880 DCHECK(FLAG_trace_track_allocation_sites);
15881 Object* current = GetHeap()->allocation_sites_list();
15882 while (current->IsAllocationSite()) {
15883 AllocationSite* current_site = AllocationSite::cast(current);
15884 if (current_site->nested_site() == this) {
15885 return true;
15886 }
15887 current = current_site->weak_next();
15888 }
15889 return false;
15890 }
15891
15892 template <AllocationSiteUpdateMode update_or_check>
DigestTransitionFeedback(Handle<AllocationSite> site,ElementsKind to_kind)15893 bool AllocationSite::DigestTransitionFeedback(Handle<AllocationSite> site,
15894 ElementsKind to_kind) {
15895 Isolate* isolate = site->GetIsolate();
15896 bool result = false;
15897
15898 if (site->SitePointsToLiteral() && site->transition_info()->IsJSArray()) {
15899 Handle<JSArray> transition_info =
15900 handle(JSArray::cast(site->transition_info()));
15901 ElementsKind kind = transition_info->GetElementsKind();
15902 // if kind is holey ensure that to_kind is as well.
15903 if (IsHoleyElementsKind(kind)) {
15904 to_kind = GetHoleyElementsKind(to_kind);
15905 }
15906 if (IsMoreGeneralElementsKindTransition(kind, to_kind)) {
15907 // If the array is huge, it's not likely to be defined in a local
15908 // function, so we shouldn't make new instances of it very often.
15909 uint32_t length = 0;
15910 CHECK(transition_info->length()->ToArrayLength(&length));
15911 if (length <= kMaximumArrayBytesToPretransition) {
15912 if (update_or_check == AllocationSiteUpdateMode::kCheckOnly) {
15913 return true;
15914 }
15915 if (FLAG_trace_track_allocation_sites) {
15916 bool is_nested = site->IsNestedSite();
15917 PrintF(
15918 "AllocationSite: JSArray %p boilerplate %s updated %s->%s\n",
15919 reinterpret_cast<void*>(*site),
15920 is_nested ? "(nested)" : "",
15921 ElementsKindToString(kind),
15922 ElementsKindToString(to_kind));
15923 }
15924 JSObject::TransitionElementsKind(transition_info, to_kind);
15925 site->dependent_code()->DeoptimizeDependentCodeGroup(
15926 isolate, DependentCode::kAllocationSiteTransitionChangedGroup);
15927 result = true;
15928 }
15929 }
15930 } else {
15931 ElementsKind kind = site->GetElementsKind();
15932 // if kind is holey ensure that to_kind is as well.
15933 if (IsHoleyElementsKind(kind)) {
15934 to_kind = GetHoleyElementsKind(to_kind);
15935 }
15936 if (IsMoreGeneralElementsKindTransition(kind, to_kind)) {
15937 if (update_or_check == AllocationSiteUpdateMode::kCheckOnly) return true;
15938 if (FLAG_trace_track_allocation_sites) {
15939 PrintF("AllocationSite: JSArray %p site updated %s->%s\n",
15940 reinterpret_cast<void*>(*site),
15941 ElementsKindToString(kind),
15942 ElementsKindToString(to_kind));
15943 }
15944 site->SetElementsKind(to_kind);
15945 site->dependent_code()->DeoptimizeDependentCodeGroup(
15946 isolate, DependentCode::kAllocationSiteTransitionChangedGroup);
15947 result = true;
15948 }
15949 }
15950 return result;
15951 }
15952
GetMode(ElementsKind from,ElementsKind to)15953 AllocationSiteMode AllocationSite::GetMode(ElementsKind from, ElementsKind to) {
15954 if (IsFastSmiElementsKind(from) &&
15955 IsMoreGeneralElementsKindTransition(from, to)) {
15956 return TRACK_ALLOCATION_SITE;
15957 }
15958
15959 return DONT_TRACK_ALLOCATION_SITE;
15960 }
15961
PretenureDecisionName(PretenureDecision decision)15962 const char* AllocationSite::PretenureDecisionName(PretenureDecision decision) {
15963 switch (decision) {
15964 case kUndecided: return "undecided";
15965 case kDontTenure: return "don't tenure";
15966 case kMaybeTenure: return "maybe tenure";
15967 case kTenure: return "tenure";
15968 case kZombie: return "zombie";
15969 default: UNREACHABLE();
15970 }
15971 return NULL;
15972 }
15973
15974 template <AllocationSiteUpdateMode update_or_check>
UpdateAllocationSite(Handle<JSObject> object,ElementsKind to_kind)15975 bool JSObject::UpdateAllocationSite(Handle<JSObject> object,
15976 ElementsKind to_kind) {
15977 if (!object->IsJSArray()) return false;
15978
15979 Heap* heap = object->GetHeap();
15980 if (!heap->InNewSpace(*object)) return false;
15981
15982 Handle<AllocationSite> site;
15983 {
15984 DisallowHeapAllocation no_allocation;
15985
15986 AllocationMemento* memento =
15987 heap->FindAllocationMemento<Heap::kForRuntime>(*object);
15988 if (memento == NULL) return false;
15989
15990 // Walk through to the Allocation Site
15991 site = handle(memento->GetAllocationSite());
15992 }
15993 return AllocationSite::DigestTransitionFeedback<update_or_check>(site,
15994 to_kind);
15995 }
15996
15997 template bool
15998 JSObject::UpdateAllocationSite<AllocationSiteUpdateMode::kCheckOnly>(
15999 Handle<JSObject> object, ElementsKind to_kind);
16000
16001 template bool JSObject::UpdateAllocationSite<AllocationSiteUpdateMode::kUpdate>(
16002 Handle<JSObject> object, ElementsKind to_kind);
16003
TransitionElementsKind(Handle<JSObject> object,ElementsKind to_kind)16004 void JSObject::TransitionElementsKind(Handle<JSObject> object,
16005 ElementsKind to_kind) {
16006 ElementsKind from_kind = object->GetElementsKind();
16007
16008 if (IsFastHoleyElementsKind(from_kind)) {
16009 to_kind = GetHoleyElementsKind(to_kind);
16010 }
16011
16012 if (from_kind == to_kind) return;
16013
16014 // This method should never be called for any other case.
16015 DCHECK(IsFastElementsKind(from_kind));
16016 DCHECK(IsFastElementsKind(to_kind));
16017 DCHECK_NE(TERMINAL_FAST_ELEMENTS_KIND, from_kind);
16018
16019 UpdateAllocationSite(object, to_kind);
16020 if (object->elements() == object->GetHeap()->empty_fixed_array() ||
16021 IsFastDoubleElementsKind(from_kind) ==
16022 IsFastDoubleElementsKind(to_kind)) {
16023 // No change is needed to the elements() buffer, the transition
16024 // only requires a map change.
16025 Handle<Map> new_map = GetElementsTransitionMap(object, to_kind);
16026 MigrateToMap(object, new_map);
16027 if (FLAG_trace_elements_transitions) {
16028 Handle<FixedArrayBase> elms(object->elements());
16029 PrintElementsTransition(stdout, object, from_kind, elms, to_kind, elms);
16030 }
16031 } else {
16032 DCHECK((IsFastSmiElementsKind(from_kind) &&
16033 IsFastDoubleElementsKind(to_kind)) ||
16034 (IsFastDoubleElementsKind(from_kind) &&
16035 IsFastObjectElementsKind(to_kind)));
16036 uint32_t c = static_cast<uint32_t>(object->elements()->length());
16037 ElementsAccessor::ForKind(to_kind)->GrowCapacityAndConvert(object, c);
16038 }
16039 }
16040
16041
16042 // static
IsValidElementsTransition(ElementsKind from_kind,ElementsKind to_kind)16043 bool Map::IsValidElementsTransition(ElementsKind from_kind,
16044 ElementsKind to_kind) {
16045 // Transitions can't go backwards.
16046 if (!IsMoreGeneralElementsKindTransition(from_kind, to_kind)) {
16047 return false;
16048 }
16049
16050 // Transitions from HOLEY -> PACKED are not allowed.
16051 return !IsFastHoleyElementsKind(from_kind) ||
16052 IsFastHoleyElementsKind(to_kind);
16053 }
16054
16055
HasReadOnlyLength(Handle<JSArray> array)16056 bool JSArray::HasReadOnlyLength(Handle<JSArray> array) {
16057 Map* map = array->map();
16058 // Fast path: "length" is the first fast property of arrays. Since it's not
16059 // configurable, it's guaranteed to be the first in the descriptor array.
16060 if (!map->is_dictionary_map()) {
16061 DCHECK(map->instance_descriptors()->GetKey(0) ==
16062 array->GetHeap()->length_string());
16063 return map->instance_descriptors()->GetDetails(0).IsReadOnly();
16064 }
16065
16066 Isolate* isolate = array->GetIsolate();
16067 LookupIterator it(array, isolate->factory()->length_string(), array,
16068 LookupIterator::OWN_SKIP_INTERCEPTOR);
16069 CHECK_EQ(LookupIterator::ACCESSOR, it.state());
16070 return it.IsReadOnly();
16071 }
16072
16073
WouldChangeReadOnlyLength(Handle<JSArray> array,uint32_t index)16074 bool JSArray::WouldChangeReadOnlyLength(Handle<JSArray> array,
16075 uint32_t index) {
16076 uint32_t length = 0;
16077 CHECK(array->length()->ToArrayLength(&length));
16078 if (length <= index) return HasReadOnlyLength(array);
16079 return false;
16080 }
16081
16082
16083 template <typename BackingStore>
FastHoleyElementsUsage(JSObject * object,BackingStore * store)16084 static int FastHoleyElementsUsage(JSObject* object, BackingStore* store) {
16085 Isolate* isolate = store->GetIsolate();
16086 int limit = object->IsJSArray()
16087 ? Smi::cast(JSArray::cast(object)->length())->value()
16088 : store->length();
16089 int used = 0;
16090 for (int i = 0; i < limit; ++i) {
16091 if (!store->is_the_hole(isolate, i)) ++used;
16092 }
16093 return used;
16094 }
16095
16096
GetFastElementsUsage()16097 int JSObject::GetFastElementsUsage() {
16098 FixedArrayBase* store = elements();
16099 switch (GetElementsKind()) {
16100 case FAST_SMI_ELEMENTS:
16101 case FAST_DOUBLE_ELEMENTS:
16102 case FAST_ELEMENTS:
16103 return IsJSArray() ? Smi::cast(JSArray::cast(this)->length())->value()
16104 : store->length();
16105 case FAST_SLOPPY_ARGUMENTS_ELEMENTS:
16106 store = FixedArray::cast(FixedArray::cast(store)->get(1));
16107 // Fall through.
16108 case FAST_HOLEY_SMI_ELEMENTS:
16109 case FAST_HOLEY_ELEMENTS:
16110 case FAST_STRING_WRAPPER_ELEMENTS:
16111 return FastHoleyElementsUsage(this, FixedArray::cast(store));
16112 case FAST_HOLEY_DOUBLE_ELEMENTS:
16113 if (elements()->length() == 0) return 0;
16114 return FastHoleyElementsUsage(this, FixedDoubleArray::cast(store));
16115
16116 case SLOW_SLOPPY_ARGUMENTS_ELEMENTS:
16117 case SLOW_STRING_WRAPPER_ELEMENTS:
16118 case DICTIONARY_ELEMENTS:
16119 case NO_ELEMENTS:
16120 #define TYPED_ARRAY_CASE(Type, type, TYPE, ctype, size) \
16121 case TYPE##_ELEMENTS: \
16122
16123 TYPED_ARRAYS(TYPED_ARRAY_CASE)
16124 #undef TYPED_ARRAY_CASE
16125 UNREACHABLE();
16126 }
16127 return 0;
16128 }
16129
16130
16131 // Certain compilers request function template instantiation when they
16132 // see the definition of the other template functions in the
16133 // class. This requires us to have the template functions put
16134 // together, so even though this function belongs in objects-debug.cc,
16135 // we keep it here instead to satisfy certain compilers.
16136 #ifdef OBJECT_PRINT
16137 template <typename Derived, typename Shape, typename Key>
Print(std::ostream & os)16138 void Dictionary<Derived, Shape, Key>::Print(std::ostream& os) { // NOLINT
16139 Isolate* isolate = this->GetIsolate();
16140 int capacity = this->Capacity();
16141 for (int i = 0; i < capacity; i++) {
16142 Object* k = this->KeyAt(i);
16143 if (this->IsKey(isolate, k)) {
16144 os << "\n ";
16145 if (k->IsString()) {
16146 String::cast(k)->StringPrint(os);
16147 } else {
16148 os << Brief(k);
16149 }
16150 os << ": " << Brief(this->ValueAt(i)) << " " << this->DetailsAt(i);
16151 }
16152 }
16153 }
16154 template <typename Derived, typename Shape, typename Key>
Print()16155 void Dictionary<Derived, Shape, Key>::Print() {
16156 OFStream os(stdout);
16157 Print(os);
16158 }
16159 #endif
16160
16161
16162 template<typename Derived, typename Shape, typename Key>
CopyValuesTo(FixedArray * elements)16163 void Dictionary<Derived, Shape, Key>::CopyValuesTo(FixedArray* elements) {
16164 Isolate* isolate = this->GetIsolate();
16165 int pos = 0;
16166 int capacity = this->Capacity();
16167 DisallowHeapAllocation no_gc;
16168 WriteBarrierMode mode = elements->GetWriteBarrierMode(no_gc);
16169 for (int i = 0; i < capacity; i++) {
16170 Object* k = this->KeyAt(i);
16171 if (this->IsKey(isolate, k)) {
16172 elements->set(pos++, this->ValueAt(i), mode);
16173 }
16174 }
16175 DCHECK(pos == elements->length());
16176 }
16177
16178
GetPropertyWithInterceptor(LookupIterator * it,bool * done)16179 MaybeHandle<Object> JSObject::GetPropertyWithInterceptor(LookupIterator* it,
16180 bool* done) {
16181 DCHECK_EQ(LookupIterator::INTERCEPTOR, it->state());
16182 return GetPropertyWithInterceptorInternal(it, it->GetInterceptor(), done);
16183 }
16184
HasRealNamedProperty(Handle<JSObject> object,Handle<Name> name)16185 Maybe<bool> JSObject::HasRealNamedProperty(Handle<JSObject> object,
16186 Handle<Name> name) {
16187 LookupIterator it = LookupIterator::PropertyOrElement(
16188 name->GetIsolate(), object, name, LookupIterator::OWN_SKIP_INTERCEPTOR);
16189 return HasProperty(&it);
16190 }
16191
16192
HasRealElementProperty(Handle<JSObject> object,uint32_t index)16193 Maybe<bool> JSObject::HasRealElementProperty(Handle<JSObject> object,
16194 uint32_t index) {
16195 Isolate* isolate = object->GetIsolate();
16196 LookupIterator it(isolate, object, index, object,
16197 LookupIterator::OWN_SKIP_INTERCEPTOR);
16198 return HasProperty(&it);
16199 }
16200
16201
HasRealNamedCallbackProperty(Handle<JSObject> object,Handle<Name> name)16202 Maybe<bool> JSObject::HasRealNamedCallbackProperty(Handle<JSObject> object,
16203 Handle<Name> name) {
16204 LookupIterator it = LookupIterator::PropertyOrElement(
16205 name->GetIsolate(), object, name, LookupIterator::OWN_SKIP_INTERCEPTOR);
16206 Maybe<PropertyAttributes> maybe_result = GetPropertyAttributes(&it);
16207 return maybe_result.IsJust() ? Just(it.state() == LookupIterator::ACCESSOR)
16208 : Nothing<bool>();
16209 }
16210
GetMaxLengthForNewSpaceAllocation(ElementsKind kind)16211 int FixedArrayBase::GetMaxLengthForNewSpaceAllocation(ElementsKind kind) {
16212 return ((kMaxRegularHeapObjectSize - FixedArrayBase::kHeaderSize) >>
16213 ElementsKindToShiftSize(kind));
16214 }
16215
SwapPairs(FixedArray * numbers,int i,int j)16216 void FixedArray::SwapPairs(FixedArray* numbers, int i, int j) {
16217 Object* temp = get(i);
16218 set(i, get(j));
16219 set(j, temp);
16220 if (this != numbers) {
16221 temp = numbers->get(i);
16222 numbers->set(i, Smi::cast(numbers->get(j)));
16223 numbers->set(j, Smi::cast(temp));
16224 }
16225 }
16226
16227
InsertionSortPairs(FixedArray * content,FixedArray * numbers,int len)16228 static void InsertionSortPairs(FixedArray* content,
16229 FixedArray* numbers,
16230 int len) {
16231 for (int i = 1; i < len; i++) {
16232 int j = i;
16233 while (j > 0 &&
16234 (NumberToUint32(numbers->get(j - 1)) >
16235 NumberToUint32(numbers->get(j)))) {
16236 content->SwapPairs(numbers, j - 1, j);
16237 j--;
16238 }
16239 }
16240 }
16241
16242
HeapSortPairs(FixedArray * content,FixedArray * numbers,int len)16243 void HeapSortPairs(FixedArray* content, FixedArray* numbers, int len) {
16244 // In-place heap sort.
16245 DCHECK(content->length() == numbers->length());
16246
16247 // Bottom-up max-heap construction.
16248 for (int i = 1; i < len; ++i) {
16249 int child_index = i;
16250 while (child_index > 0) {
16251 int parent_index = ((child_index + 1) >> 1) - 1;
16252 uint32_t parent_value = NumberToUint32(numbers->get(parent_index));
16253 uint32_t child_value = NumberToUint32(numbers->get(child_index));
16254 if (parent_value < child_value) {
16255 content->SwapPairs(numbers, parent_index, child_index);
16256 } else {
16257 break;
16258 }
16259 child_index = parent_index;
16260 }
16261 }
16262
16263 // Extract elements and create sorted array.
16264 for (int i = len - 1; i > 0; --i) {
16265 // Put max element at the back of the array.
16266 content->SwapPairs(numbers, 0, i);
16267 // Sift down the new top element.
16268 int parent_index = 0;
16269 while (true) {
16270 int child_index = ((parent_index + 1) << 1) - 1;
16271 if (child_index >= i) break;
16272 uint32_t child1_value = NumberToUint32(numbers->get(child_index));
16273 uint32_t child2_value = NumberToUint32(numbers->get(child_index + 1));
16274 uint32_t parent_value = NumberToUint32(numbers->get(parent_index));
16275 if (child_index + 1 >= i || child1_value > child2_value) {
16276 if (parent_value > child1_value) break;
16277 content->SwapPairs(numbers, parent_index, child_index);
16278 parent_index = child_index;
16279 } else {
16280 if (parent_value > child2_value) break;
16281 content->SwapPairs(numbers, parent_index, child_index + 1);
16282 parent_index = child_index + 1;
16283 }
16284 }
16285 }
16286 }
16287
16288
16289 // Sort this array and the numbers as pairs wrt. the (distinct) numbers.
SortPairs(FixedArray * numbers,uint32_t len)16290 void FixedArray::SortPairs(FixedArray* numbers, uint32_t len) {
16291 DCHECK(this->length() == numbers->length());
16292 // For small arrays, simply use insertion sort.
16293 if (len <= 10) {
16294 InsertionSortPairs(this, numbers, len);
16295 return;
16296 }
16297 // Check the range of indices.
16298 uint32_t min_index = NumberToUint32(numbers->get(0));
16299 uint32_t max_index = min_index;
16300 uint32_t i;
16301 for (i = 1; i < len; i++) {
16302 if (NumberToUint32(numbers->get(i)) < min_index) {
16303 min_index = NumberToUint32(numbers->get(i));
16304 } else if (NumberToUint32(numbers->get(i)) > max_index) {
16305 max_index = NumberToUint32(numbers->get(i));
16306 }
16307 }
16308 if (max_index - min_index + 1 == len) {
16309 // Indices form a contiguous range, unless there are duplicates.
16310 // Do an in-place linear time sort assuming distinct numbers, but
16311 // avoid hanging in case they are not.
16312 for (i = 0; i < len; i++) {
16313 uint32_t p;
16314 uint32_t j = 0;
16315 // While the current element at i is not at its correct position p,
16316 // swap the elements at these two positions.
16317 while ((p = NumberToUint32(numbers->get(i)) - min_index) != i &&
16318 j++ < len) {
16319 SwapPairs(numbers, i, p);
16320 }
16321 }
16322 } else {
16323 HeapSortPairs(this, numbers, len);
16324 return;
16325 }
16326 }
16327
WasConstructedFromApiFunction()16328 bool JSObject::WasConstructedFromApiFunction() {
16329 auto instance_type = map()->instance_type();
16330 bool is_api_object = instance_type == JS_API_OBJECT_TYPE ||
16331 instance_type == JS_SPECIAL_API_OBJECT_TYPE;
16332 #ifdef ENABLE_SLOW_DCHECKS
16333 if (FLAG_enable_slow_asserts) {
16334 Object* maybe_constructor = map()->GetConstructor();
16335 if (!maybe_constructor->IsJSFunction()) return false;
16336 JSFunction* constructor = JSFunction::cast(maybe_constructor);
16337 if (constructor->shared()->IsApiFunction()) {
16338 DCHECK(is_api_object);
16339 } else {
16340 DCHECK(!is_api_object);
16341 }
16342 }
16343 #endif
16344 return is_api_object;
16345 }
16346
ObjectProtoToString(Isolate * isolate,Handle<Object> object)16347 MaybeHandle<String> Object::ObjectProtoToString(Isolate* isolate,
16348 Handle<Object> object) {
16349 if (*object == isolate->heap()->undefined_value()) {
16350 return isolate->factory()->undefined_to_string();
16351 }
16352 if (*object == isolate->heap()->null_value()) {
16353 return isolate->factory()->null_to_string();
16354 }
16355
16356 Handle<JSReceiver> receiver =
16357 Object::ToObject(isolate, object).ToHandleChecked();
16358
16359 // For proxies, we must check IsArray() before get(toStringTag) to comply
16360 // with the specification
16361 Maybe<bool> is_array = Nothing<bool>();
16362 InstanceType instance_type = receiver->map()->instance_type();
16363 if (instance_type == JS_PROXY_TYPE) {
16364 is_array = Object::IsArray(receiver);
16365 MAYBE_RETURN(is_array, MaybeHandle<String>());
16366 }
16367
16368 Handle<String> tag;
16369 Handle<Object> to_string_tag;
16370 ASSIGN_RETURN_ON_EXCEPTION(
16371 isolate, to_string_tag,
16372 JSReceiver::GetProperty(receiver,
16373 isolate->factory()->to_string_tag_symbol()),
16374 String);
16375 if (to_string_tag->IsString()) {
16376 tag = Handle<String>::cast(to_string_tag);
16377 } else {
16378 switch (instance_type) {
16379 case JS_API_OBJECT_TYPE:
16380 case JS_SPECIAL_API_OBJECT_TYPE:
16381 tag = handle(receiver->class_name(), isolate);
16382 break;
16383 case JS_ARGUMENTS_TYPE:
16384 return isolate->factory()->arguments_to_string();
16385 case JS_ARRAY_TYPE:
16386 return isolate->factory()->array_to_string();
16387 case JS_BOUND_FUNCTION_TYPE:
16388 case JS_FUNCTION_TYPE:
16389 return isolate->factory()->function_to_string();
16390 case JS_ERROR_TYPE:
16391 return isolate->factory()->error_to_string();
16392 case JS_DATE_TYPE:
16393 return isolate->factory()->date_to_string();
16394 case JS_REGEXP_TYPE:
16395 return isolate->factory()->regexp_to_string();
16396 case JS_PROXY_TYPE: {
16397 if (is_array.FromJust()) {
16398 return isolate->factory()->array_to_string();
16399 }
16400 if (receiver->IsCallable()) {
16401 return isolate->factory()->function_to_string();
16402 }
16403 return isolate->factory()->object_to_string();
16404 }
16405 case JS_VALUE_TYPE: {
16406 Object* value = JSValue::cast(*receiver)->value();
16407 if (value->IsString()) {
16408 return isolate->factory()->string_to_string();
16409 }
16410 if (value->IsNumber()) {
16411 return isolate->factory()->number_to_string();
16412 }
16413 if (value->IsBoolean()) {
16414 return isolate->factory()->boolean_to_string();
16415 }
16416 if (value->IsSymbol()) {
16417 return isolate->factory()->object_to_string();
16418 }
16419 UNREACHABLE();
16420 tag = handle(receiver->class_name(), isolate);
16421 break;
16422 }
16423 default:
16424 return isolate->factory()->object_to_string();
16425 }
16426 }
16427
16428 IncrementalStringBuilder builder(isolate);
16429 builder.AppendCString("[object ");
16430 builder.AppendString(tag);
16431 builder.AppendCharacter(']');
16432 return builder.Finish();
16433 }
16434
PrivateSymbolToName() const16435 const char* Symbol::PrivateSymbolToName() const {
16436 Heap* heap = GetIsolate()->heap();
16437 #define SYMBOL_CHECK_AND_PRINT(name) \
16438 if (this == heap->name()) return #name;
16439 PRIVATE_SYMBOL_LIST(SYMBOL_CHECK_AND_PRINT)
16440 #undef SYMBOL_CHECK_AND_PRINT
16441 return "UNKNOWN";
16442 }
16443
16444
SymbolShortPrint(std::ostream & os)16445 void Symbol::SymbolShortPrint(std::ostream& os) {
16446 os << "<Symbol:";
16447 if (!name()->IsUndefined(GetIsolate())) {
16448 os << " ";
16449 HeapStringAllocator allocator;
16450 StringStream accumulator(&allocator);
16451 String::cast(name())->StringShortPrint(&accumulator, false);
16452 os << accumulator.ToCString().get();
16453 } else {
16454 os << " (" << PrivateSymbolToName() << ")";
16455 }
16456 os << ">";
16457 }
16458
16459
16460 // StringSharedKeys are used as keys in the eval cache.
16461 class StringSharedKey : public HashTableKey {
16462 public:
StringSharedKey(Handle<String> source,Handle<SharedFunctionInfo> shared,LanguageMode language_mode,int scope_position)16463 StringSharedKey(Handle<String> source, Handle<SharedFunctionInfo> shared,
16464 LanguageMode language_mode, int scope_position)
16465 : source_(source),
16466 shared_(shared),
16467 language_mode_(language_mode),
16468 scope_position_(scope_position) {}
16469
IsMatch(Object * other)16470 bool IsMatch(Object* other) override {
16471 DisallowHeapAllocation no_allocation;
16472 if (!other->IsFixedArray()) {
16473 if (!other->IsNumber()) return false;
16474 uint32_t other_hash = static_cast<uint32_t>(other->Number());
16475 return Hash() == other_hash;
16476 }
16477 FixedArray* other_array = FixedArray::cast(other);
16478 SharedFunctionInfo* shared = SharedFunctionInfo::cast(other_array->get(0));
16479 if (shared != *shared_) return false;
16480 int language_unchecked = Smi::cast(other_array->get(2))->value();
16481 DCHECK(is_valid_language_mode(language_unchecked));
16482 LanguageMode language_mode = static_cast<LanguageMode>(language_unchecked);
16483 if (language_mode != language_mode_) return false;
16484 int scope_position = Smi::cast(other_array->get(3))->value();
16485 if (scope_position != scope_position_) return false;
16486 String* source = String::cast(other_array->get(1));
16487 return source->Equals(*source_);
16488 }
16489
StringSharedHashHelper(String * source,SharedFunctionInfo * shared,LanguageMode language_mode,int scope_position)16490 static uint32_t StringSharedHashHelper(String* source,
16491 SharedFunctionInfo* shared,
16492 LanguageMode language_mode,
16493 int scope_position) {
16494 uint32_t hash = source->Hash();
16495 if (shared->HasSourceCode()) {
16496 // Instead of using the SharedFunctionInfo pointer in the hash
16497 // code computation, we use a combination of the hash of the
16498 // script source code and the start position of the calling scope.
16499 // We do this to ensure that the cache entries can survive garbage
16500 // collection.
16501 Script* script(Script::cast(shared->script()));
16502 hash ^= String::cast(script->source())->Hash();
16503 STATIC_ASSERT(LANGUAGE_END == 2);
16504 if (is_strict(language_mode)) hash ^= 0x8000;
16505 hash += scope_position;
16506 }
16507 return hash;
16508 }
16509
Hash()16510 uint32_t Hash() override {
16511 return StringSharedHashHelper(*source_, *shared_, language_mode_,
16512 scope_position_);
16513 }
16514
HashForObject(Object * obj)16515 uint32_t HashForObject(Object* obj) override {
16516 DisallowHeapAllocation no_allocation;
16517 if (obj->IsNumber()) {
16518 return static_cast<uint32_t>(obj->Number());
16519 }
16520 FixedArray* other_array = FixedArray::cast(obj);
16521 SharedFunctionInfo* shared = SharedFunctionInfo::cast(other_array->get(0));
16522 String* source = String::cast(other_array->get(1));
16523 int language_unchecked = Smi::cast(other_array->get(2))->value();
16524 DCHECK(is_valid_language_mode(language_unchecked));
16525 LanguageMode language_mode = static_cast<LanguageMode>(language_unchecked);
16526 int scope_position = Smi::cast(other_array->get(3))->value();
16527 return StringSharedHashHelper(source, shared, language_mode,
16528 scope_position);
16529 }
16530
16531
AsHandle(Isolate * isolate)16532 Handle<Object> AsHandle(Isolate* isolate) override {
16533 Handle<FixedArray> array = isolate->factory()->NewFixedArray(4);
16534 array->set(0, *shared_);
16535 array->set(1, *source_);
16536 array->set(2, Smi::FromInt(language_mode_));
16537 array->set(3, Smi::FromInt(scope_position_));
16538 return array;
16539 }
16540
16541 private:
16542 Handle<String> source_;
16543 Handle<SharedFunctionInfo> shared_;
16544 LanguageMode language_mode_;
16545 int scope_position_;
16546 };
16547
16548
16549 namespace {
16550
RegExpFlagsFromString(Handle<String> flags,bool * success)16551 JSRegExp::Flags RegExpFlagsFromString(Handle<String> flags, bool* success) {
16552 JSRegExp::Flags value = JSRegExp::kNone;
16553 int length = flags->length();
16554 // A longer flags string cannot be valid.
16555 if (length > 5) return JSRegExp::Flags(0);
16556 for (int i = 0; i < length; i++) {
16557 JSRegExp::Flag flag = JSRegExp::kNone;
16558 switch (flags->Get(i)) {
16559 case 'g':
16560 flag = JSRegExp::kGlobal;
16561 break;
16562 case 'i':
16563 flag = JSRegExp::kIgnoreCase;
16564 break;
16565 case 'm':
16566 flag = JSRegExp::kMultiline;
16567 break;
16568 case 'u':
16569 flag = JSRegExp::kUnicode;
16570 break;
16571 case 'y':
16572 flag = JSRegExp::kSticky;
16573 break;
16574 default:
16575 return JSRegExp::Flags(0);
16576 }
16577 // Duplicate flag.
16578 if (value & flag) return JSRegExp::Flags(0);
16579 value |= flag;
16580 }
16581 *success = true;
16582 return value;
16583 }
16584
16585 } // namespace
16586
16587
16588 // static
New(Handle<String> pattern,Flags flags)16589 MaybeHandle<JSRegExp> JSRegExp::New(Handle<String> pattern, Flags flags) {
16590 Isolate* isolate = pattern->GetIsolate();
16591 Handle<JSFunction> constructor = isolate->regexp_function();
16592 Handle<JSRegExp> regexp =
16593 Handle<JSRegExp>::cast(isolate->factory()->NewJSObject(constructor));
16594
16595 return JSRegExp::Initialize(regexp, pattern, flags);
16596 }
16597
16598
16599 // static
Copy(Handle<JSRegExp> regexp)16600 Handle<JSRegExp> JSRegExp::Copy(Handle<JSRegExp> regexp) {
16601 Isolate* const isolate = regexp->GetIsolate();
16602 return Handle<JSRegExp>::cast(isolate->factory()->CopyJSObject(regexp));
16603 }
16604
16605
16606 template <typename Char>
CountRequiredEscapes(Handle<String> source)16607 inline int CountRequiredEscapes(Handle<String> source) {
16608 DisallowHeapAllocation no_gc;
16609 int escapes = 0;
16610 Vector<const Char> src = source->GetCharVector<Char>();
16611 for (int i = 0; i < src.length(); i++) {
16612 if (src[i] == '\\') {
16613 // Escape. Skip next character;
16614 i++;
16615 } else if (src[i] == '/') {
16616 // Not escaped forward-slash needs escape.
16617 escapes++;
16618 }
16619 }
16620 return escapes;
16621 }
16622
16623
16624 template <typename Char, typename StringType>
WriteEscapedRegExpSource(Handle<String> source,Handle<StringType> result)16625 inline Handle<StringType> WriteEscapedRegExpSource(Handle<String> source,
16626 Handle<StringType> result) {
16627 DisallowHeapAllocation no_gc;
16628 Vector<const Char> src = source->GetCharVector<Char>();
16629 Vector<Char> dst(result->GetChars(), result->length());
16630 int s = 0;
16631 int d = 0;
16632 while (s < src.length()) {
16633 if (src[s] == '\\') {
16634 // Escape. Copy this and next character.
16635 dst[d++] = src[s++];
16636 if (s == src.length()) break;
16637 } else if (src[s] == '/') {
16638 // Not escaped forward-slash needs escape.
16639 dst[d++] = '\\';
16640 }
16641 dst[d++] = src[s++];
16642 }
16643 DCHECK_EQ(result->length(), d);
16644 return result;
16645 }
16646
16647
EscapeRegExpSource(Isolate * isolate,Handle<String> source)16648 MaybeHandle<String> EscapeRegExpSource(Isolate* isolate,
16649 Handle<String> source) {
16650 String::Flatten(source);
16651 if (source->length() == 0) return isolate->factory()->query_colon_string();
16652 bool one_byte = source->IsOneByteRepresentationUnderneath();
16653 int escapes = one_byte ? CountRequiredEscapes<uint8_t>(source)
16654 : CountRequiredEscapes<uc16>(source);
16655 if (escapes == 0) return source;
16656 int length = source->length() + escapes;
16657 if (one_byte) {
16658 Handle<SeqOneByteString> result;
16659 ASSIGN_RETURN_ON_EXCEPTION(isolate, result,
16660 isolate->factory()->NewRawOneByteString(length),
16661 String);
16662 return WriteEscapedRegExpSource<uint8_t>(source, result);
16663 } else {
16664 Handle<SeqTwoByteString> result;
16665 ASSIGN_RETURN_ON_EXCEPTION(isolate, result,
16666 isolate->factory()->NewRawTwoByteString(length),
16667 String);
16668 return WriteEscapedRegExpSource<uc16>(source, result);
16669 }
16670 }
16671
16672
16673 // static
Initialize(Handle<JSRegExp> regexp,Handle<String> source,Handle<String> flags_string)16674 MaybeHandle<JSRegExp> JSRegExp::Initialize(Handle<JSRegExp> regexp,
16675 Handle<String> source,
16676 Handle<String> flags_string) {
16677 Isolate* isolate = source->GetIsolate();
16678 bool success = false;
16679 Flags flags = RegExpFlagsFromString(flags_string, &success);
16680 if (!success) {
16681 THROW_NEW_ERROR(
16682 isolate,
16683 NewSyntaxError(MessageTemplate::kInvalidRegExpFlags, flags_string),
16684 JSRegExp);
16685 }
16686 return Initialize(regexp, source, flags);
16687 }
16688
16689
16690 // static
Initialize(Handle<JSRegExp> regexp,Handle<String> source,Flags flags)16691 MaybeHandle<JSRegExp> JSRegExp::Initialize(Handle<JSRegExp> regexp,
16692 Handle<String> source, Flags flags) {
16693 Isolate* isolate = regexp->GetIsolate();
16694 Factory* factory = isolate->factory();
16695 // If source is the empty string we set it to "(?:)" instead as
16696 // suggested by ECMA-262, 5th, section 15.10.4.1.
16697 if (source->length() == 0) source = factory->query_colon_string();
16698
16699 Handle<String> escaped_source;
16700 ASSIGN_RETURN_ON_EXCEPTION(isolate, escaped_source,
16701 EscapeRegExpSource(isolate, source), JSRegExp);
16702
16703 RETURN_ON_EXCEPTION(isolate, RegExpImpl::Compile(regexp, source, flags),
16704 JSRegExp);
16705
16706 regexp->set_source(*escaped_source);
16707 regexp->set_flags(Smi::FromInt(flags));
16708
16709 Map* map = regexp->map();
16710 Object* constructor = map->GetConstructor();
16711 if (constructor->IsJSFunction() &&
16712 JSFunction::cast(constructor)->initial_map() == map) {
16713 // If we still have the original map, set in-object properties directly.
16714 regexp->InObjectPropertyAtPut(JSRegExp::kLastIndexFieldIndex, Smi::kZero,
16715 SKIP_WRITE_BARRIER);
16716 } else {
16717 // Map has changed, so use generic, but slower, method.
16718 RETURN_ON_EXCEPTION(isolate, JSReceiver::SetProperty(
16719 regexp, factory->lastIndex_string(),
16720 Handle<Smi>(Smi::kZero, isolate), STRICT),
16721 JSRegExp);
16722 }
16723
16724 return regexp;
16725 }
16726
16727
16728 // RegExpKey carries the source and flags of a regular expression as key.
16729 class RegExpKey : public HashTableKey {
16730 public:
RegExpKey(Handle<String> string,JSRegExp::Flags flags)16731 RegExpKey(Handle<String> string, JSRegExp::Flags flags)
16732 : string_(string), flags_(Smi::FromInt(flags)) {}
16733
16734 // Rather than storing the key in the hash table, a pointer to the
16735 // stored value is stored where the key should be. IsMatch then
16736 // compares the search key to the found object, rather than comparing
16737 // a key to a key.
IsMatch(Object * obj)16738 bool IsMatch(Object* obj) override {
16739 FixedArray* val = FixedArray::cast(obj);
16740 return string_->Equals(String::cast(val->get(JSRegExp::kSourceIndex)))
16741 && (flags_ == val->get(JSRegExp::kFlagsIndex));
16742 }
16743
Hash()16744 uint32_t Hash() override { return RegExpHash(*string_, flags_); }
16745
AsHandle(Isolate * isolate)16746 Handle<Object> AsHandle(Isolate* isolate) override {
16747 // Plain hash maps, which is where regexp keys are used, don't
16748 // use this function.
16749 UNREACHABLE();
16750 return MaybeHandle<Object>().ToHandleChecked();
16751 }
16752
HashForObject(Object * obj)16753 uint32_t HashForObject(Object* obj) override {
16754 FixedArray* val = FixedArray::cast(obj);
16755 return RegExpHash(String::cast(val->get(JSRegExp::kSourceIndex)),
16756 Smi::cast(val->get(JSRegExp::kFlagsIndex)));
16757 }
16758
RegExpHash(String * string,Smi * flags)16759 static uint32_t RegExpHash(String* string, Smi* flags) {
16760 return string->Hash() + flags->value();
16761 }
16762
16763 Handle<String> string_;
16764 Smi* flags_;
16765 };
16766
16767
AsHandle(Isolate * isolate)16768 Handle<Object> OneByteStringKey::AsHandle(Isolate* isolate) {
16769 if (hash_field_ == 0) Hash();
16770 return isolate->factory()->NewOneByteInternalizedString(string_, hash_field_);
16771 }
16772
16773
AsHandle(Isolate * isolate)16774 Handle<Object> TwoByteStringKey::AsHandle(Isolate* isolate) {
16775 if (hash_field_ == 0) Hash();
16776 return isolate->factory()->NewTwoByteInternalizedString(string_, hash_field_);
16777 }
16778
16779
AsHandle(Isolate * isolate)16780 Handle<Object> SeqOneByteSubStringKey::AsHandle(Isolate* isolate) {
16781 if (hash_field_ == 0) Hash();
16782 return isolate->factory()->NewOneByteInternalizedSubString(
16783 string_, from_, length_, hash_field_);
16784 }
16785
16786
IsMatch(Object * string)16787 bool SeqOneByteSubStringKey::IsMatch(Object* string) {
16788 Vector<const uint8_t> chars(string_->GetChars() + from_, length_);
16789 return String::cast(string)->IsOneByteEqualTo(chars);
16790 }
16791
16792
16793 // InternalizedStringKey carries a string/internalized-string object as key.
16794 class InternalizedStringKey : public HashTableKey {
16795 public:
InternalizedStringKey(Handle<String> string)16796 explicit InternalizedStringKey(Handle<String> string)
16797 : string_(String::Flatten(string)) {}
16798
IsMatch(Object * string)16799 bool IsMatch(Object* string) override {
16800 return String::cast(string)->Equals(*string_);
16801 }
16802
Hash()16803 uint32_t Hash() override { return string_->Hash(); }
16804
HashForObject(Object * other)16805 uint32_t HashForObject(Object* other) override {
16806 return String::cast(other)->Hash();
16807 }
16808
AsHandle(Isolate * isolate)16809 Handle<Object> AsHandle(Isolate* isolate) override {
16810 // Internalize the string if possible.
16811 MaybeHandle<Map> maybe_map =
16812 isolate->factory()->InternalizedStringMapForString(string_);
16813 Handle<Map> map;
16814 if (maybe_map.ToHandle(&map)) {
16815 string_->set_map_no_write_barrier(*map);
16816 DCHECK(string_->IsInternalizedString());
16817 return string_;
16818 }
16819 // Otherwise allocate a new internalized string.
16820 return isolate->factory()->NewInternalizedStringImpl(
16821 string_, string_->length(), string_->hash_field());
16822 }
16823
StringHash(Object * obj)16824 static uint32_t StringHash(Object* obj) {
16825 return String::cast(obj)->Hash();
16826 }
16827
16828 Handle<String> string_;
16829 };
16830
16831
16832 template<typename Derived, typename Shape, typename Key>
IteratePrefix(ObjectVisitor * v)16833 void HashTable<Derived, Shape, Key>::IteratePrefix(ObjectVisitor* v) {
16834 BodyDescriptorBase::IteratePointers(this, 0, kElementsStartOffset, v);
16835 }
16836
16837
16838 template<typename Derived, typename Shape, typename Key>
IterateElements(ObjectVisitor * v)16839 void HashTable<Derived, Shape, Key>::IterateElements(ObjectVisitor* v) {
16840 BodyDescriptorBase::IteratePointers(this, kElementsStartOffset,
16841 kHeaderSize + length() * kPointerSize, v);
16842 }
16843
16844
16845 template<typename Derived, typename Shape, typename Key>
New(Isolate * isolate,int at_least_space_for,MinimumCapacity capacity_option,PretenureFlag pretenure)16846 Handle<Derived> HashTable<Derived, Shape, Key>::New(
16847 Isolate* isolate,
16848 int at_least_space_for,
16849 MinimumCapacity capacity_option,
16850 PretenureFlag pretenure) {
16851 DCHECK(0 <= at_least_space_for);
16852 DCHECK_IMPLIES(capacity_option == USE_CUSTOM_MINIMUM_CAPACITY,
16853 base::bits::IsPowerOfTwo32(at_least_space_for));
16854
16855 int capacity = (capacity_option == USE_CUSTOM_MINIMUM_CAPACITY)
16856 ? at_least_space_for
16857 : ComputeCapacity(at_least_space_for);
16858 if (capacity > HashTable::kMaxCapacity) {
16859 v8::internal::Heap::FatalProcessOutOfMemory("invalid table size", true);
16860 }
16861
16862 Factory* factory = isolate->factory();
16863 int length = EntryToIndex(capacity);
16864 Handle<FixedArray> array = factory->NewFixedArray(length, pretenure);
16865 array->set_map_no_write_barrier(Shape::GetMap(isolate));
16866 Handle<Derived> table = Handle<Derived>::cast(array);
16867
16868 table->SetNumberOfElements(0);
16869 table->SetNumberOfDeletedElements(0);
16870 table->SetCapacity(capacity);
16871 return table;
16872 }
16873
16874
16875 // Find entry for key otherwise return kNotFound.
16876 template <typename Derived, typename Shape>
FindEntry(Handle<Name> key)16877 int NameDictionaryBase<Derived, Shape>::FindEntry(Handle<Name> key) {
16878 if (!key->IsUniqueName()) {
16879 return DerivedDictionary::FindEntry(key);
16880 }
16881
16882 // Optimized for unique names. Knowledge of the key type allows:
16883 // 1. Move the check if the key is unique out of the loop.
16884 // 2. Avoid comparing hash codes in unique-to-unique comparison.
16885 // 3. Detect a case when a dictionary key is not unique but the key is.
16886 // In case of positive result the dictionary key may be replaced by the
16887 // internalized string with minimal performance penalty. It gives a chance
16888 // to perform further lookups in code stubs (and significant performance
16889 // boost a certain style of code).
16890
16891 // EnsureCapacity will guarantee the hash table is never full.
16892 uint32_t capacity = this->Capacity();
16893 uint32_t entry = Derived::FirstProbe(key->Hash(), capacity);
16894 uint32_t count = 1;
16895 Isolate* isolate = this->GetIsolate();
16896 while (true) {
16897 Object* element = this->KeyAt(entry);
16898 if (element->IsUndefined(isolate)) break; // Empty entry.
16899 if (*key == element) return entry;
16900 DCHECK(element->IsTheHole(isolate) || element->IsUniqueName());
16901 entry = Derived::NextProbe(entry, count++, capacity);
16902 }
16903 return Derived::kNotFound;
16904 }
16905
16906
16907 template<typename Derived, typename Shape, typename Key>
Rehash(Handle<Derived> new_table,Key key)16908 void HashTable<Derived, Shape, Key>::Rehash(
16909 Handle<Derived> new_table,
16910 Key key) {
16911 DCHECK(NumberOfElements() < new_table->Capacity());
16912
16913 DisallowHeapAllocation no_gc;
16914 WriteBarrierMode mode = new_table->GetWriteBarrierMode(no_gc);
16915
16916 // Copy prefix to new array.
16917 for (int i = kPrefixStartIndex;
16918 i < kPrefixStartIndex + Shape::kPrefixSize;
16919 i++) {
16920 new_table->set(i, get(i), mode);
16921 }
16922
16923 // Rehash the elements.
16924 int capacity = this->Capacity();
16925 Heap* heap = new_table->GetHeap();
16926 Object* the_hole = heap->the_hole_value();
16927 Object* undefined = heap->undefined_value();
16928 for (int i = 0; i < capacity; i++) {
16929 uint32_t from_index = EntryToIndex(i);
16930 Object* k = this->get(from_index);
16931 if (k != the_hole && k != undefined) {
16932 uint32_t hash = this->HashForObject(key, k);
16933 uint32_t insertion_index =
16934 EntryToIndex(new_table->FindInsertionEntry(hash));
16935 for (int j = 0; j < Shape::kEntrySize; j++) {
16936 new_table->set(insertion_index + j, get(from_index + j), mode);
16937 }
16938 }
16939 }
16940 new_table->SetNumberOfElements(NumberOfElements());
16941 new_table->SetNumberOfDeletedElements(0);
16942 }
16943
16944
16945 template<typename Derived, typename Shape, typename Key>
EntryForProbe(Key key,Object * k,int probe,uint32_t expected)16946 uint32_t HashTable<Derived, Shape, Key>::EntryForProbe(
16947 Key key,
16948 Object* k,
16949 int probe,
16950 uint32_t expected) {
16951 uint32_t hash = this->HashForObject(key, k);
16952 uint32_t capacity = this->Capacity();
16953 uint32_t entry = FirstProbe(hash, capacity);
16954 for (int i = 1; i < probe; i++) {
16955 if (entry == expected) return expected;
16956 entry = NextProbe(entry, i, capacity);
16957 }
16958 return entry;
16959 }
16960
16961
16962 template<typename Derived, typename Shape, typename Key>
Swap(uint32_t entry1,uint32_t entry2,WriteBarrierMode mode)16963 void HashTable<Derived, Shape, Key>::Swap(uint32_t entry1,
16964 uint32_t entry2,
16965 WriteBarrierMode mode) {
16966 int index1 = EntryToIndex(entry1);
16967 int index2 = EntryToIndex(entry2);
16968 Object* temp[Shape::kEntrySize];
16969 for (int j = 0; j < Shape::kEntrySize; j++) {
16970 temp[j] = get(index1 + j);
16971 }
16972 for (int j = 0; j < Shape::kEntrySize; j++) {
16973 set(index1 + j, get(index2 + j), mode);
16974 }
16975 for (int j = 0; j < Shape::kEntrySize; j++) {
16976 set(index2 + j, temp[j], mode);
16977 }
16978 }
16979
16980
16981 template<typename Derived, typename Shape, typename Key>
Rehash(Key key)16982 void HashTable<Derived, Shape, Key>::Rehash(Key key) {
16983 DisallowHeapAllocation no_gc;
16984 WriteBarrierMode mode = GetWriteBarrierMode(no_gc);
16985 Isolate* isolate = GetIsolate();
16986 uint32_t capacity = Capacity();
16987 bool done = false;
16988 for (int probe = 1; !done; probe++) {
16989 // All elements at entries given by one of the first _probe_ probes
16990 // are placed correctly. Other elements might need to be moved.
16991 done = true;
16992 for (uint32_t current = 0; current < capacity; current++) {
16993 Object* current_key = KeyAt(current);
16994 if (IsKey(isolate, current_key)) {
16995 uint32_t target = EntryForProbe(key, current_key, probe, current);
16996 if (current == target) continue;
16997 Object* target_key = KeyAt(target);
16998 if (!IsKey(target_key) ||
16999 EntryForProbe(key, target_key, probe, target) != target) {
17000 // Put the current element into the correct position.
17001 Swap(current, target, mode);
17002 // The other element will be processed on the next iteration.
17003 current--;
17004 } else {
17005 // The place for the current element is occupied. Leave the element
17006 // for the next probe.
17007 done = false;
17008 }
17009 }
17010 }
17011 }
17012 // Wipe deleted entries.
17013 Object* the_hole = isolate->heap()->the_hole_value();
17014 Object* undefined = isolate->heap()->undefined_value();
17015 for (uint32_t current = 0; current < capacity; current++) {
17016 if (KeyAt(current) == the_hole) {
17017 set(EntryToIndex(current) + Derived::kEntryKeyIndex, undefined);
17018 }
17019 }
17020 SetNumberOfDeletedElements(0);
17021 }
17022
17023
17024 template<typename Derived, typename Shape, typename Key>
EnsureCapacity(Handle<Derived> table,int n,Key key,PretenureFlag pretenure)17025 Handle<Derived> HashTable<Derived, Shape, Key>::EnsureCapacity(
17026 Handle<Derived> table,
17027 int n,
17028 Key key,
17029 PretenureFlag pretenure) {
17030 Isolate* isolate = table->GetIsolate();
17031 int capacity = table->Capacity();
17032 int nof = table->NumberOfElements() + n;
17033
17034 if (table->HasSufficientCapacityToAdd(n)) return table;
17035
17036 const int kMinCapacityForPretenure = 256;
17037 bool should_pretenure = pretenure == TENURED ||
17038 ((capacity > kMinCapacityForPretenure) &&
17039 !isolate->heap()->InNewSpace(*table));
17040 Handle<Derived> new_table = HashTable::New(
17041 isolate,
17042 nof * 2,
17043 USE_DEFAULT_MINIMUM_CAPACITY,
17044 should_pretenure ? TENURED : NOT_TENURED);
17045
17046 table->Rehash(new_table, key);
17047 return new_table;
17048 }
17049
17050 template <typename Derived, typename Shape, typename Key>
HasSufficientCapacityToAdd(int number_of_additional_elements)17051 bool HashTable<Derived, Shape, Key>::HasSufficientCapacityToAdd(
17052 int number_of_additional_elements) {
17053 int capacity = Capacity();
17054 int nof = NumberOfElements() + number_of_additional_elements;
17055 int nod = NumberOfDeletedElements();
17056 // Return true if:
17057 // 50% is still free after adding number_of_additional_elements elements and
17058 // at most 50% of the free elements are deleted elements.
17059 if ((nof < capacity) && ((nod <= (capacity - nof) >> 1))) {
17060 int needed_free = nof >> 1;
17061 if (nof + needed_free <= capacity) return true;
17062 }
17063 return false;
17064 }
17065
17066
17067 template<typename Derived, typename Shape, typename Key>
Shrink(Handle<Derived> table,Key key)17068 Handle<Derived> HashTable<Derived, Shape, Key>::Shrink(Handle<Derived> table,
17069 Key key) {
17070 int capacity = table->Capacity();
17071 int nof = table->NumberOfElements();
17072
17073 // Shrink to fit the number of elements if only a quarter of the
17074 // capacity is filled with elements.
17075 if (nof > (capacity >> 2)) return table;
17076 // Allocate a new dictionary with room for at least the current
17077 // number of elements. The allocation method will make sure that
17078 // there is extra room in the dictionary for additions. Don't go
17079 // lower than room for 16 elements.
17080 int at_least_room_for = nof;
17081 if (at_least_room_for < 16) return table;
17082
17083 Isolate* isolate = table->GetIsolate();
17084 const int kMinCapacityForPretenure = 256;
17085 bool pretenure =
17086 (at_least_room_for > kMinCapacityForPretenure) &&
17087 !isolate->heap()->InNewSpace(*table);
17088 Handle<Derived> new_table = HashTable::New(
17089 isolate,
17090 at_least_room_for,
17091 USE_DEFAULT_MINIMUM_CAPACITY,
17092 pretenure ? TENURED : NOT_TENURED);
17093
17094 table->Rehash(new_table, key);
17095 return new_table;
17096 }
17097
17098
17099 template<typename Derived, typename Shape, typename Key>
FindInsertionEntry(uint32_t hash)17100 uint32_t HashTable<Derived, Shape, Key>::FindInsertionEntry(uint32_t hash) {
17101 uint32_t capacity = Capacity();
17102 uint32_t entry = FirstProbe(hash, capacity);
17103 uint32_t count = 1;
17104 // EnsureCapacity will guarantee the hash table is never full.
17105 Isolate* isolate = GetIsolate();
17106 while (true) {
17107 Object* element = KeyAt(entry);
17108 if (!IsKey(isolate, element)) break;
17109 entry = NextProbe(entry, count++, capacity);
17110 }
17111 return entry;
17112 }
17113
17114
17115 // Force instantiation of template instances class.
17116 // Please note this list is compiler dependent.
17117
17118 template class HashTable<StringTable, StringTableShape, HashTableKey*>;
17119
17120 template class HashTable<CompilationCacheTable,
17121 CompilationCacheShape,
17122 HashTableKey*>;
17123
17124 template class HashTable<ObjectHashTable,
17125 ObjectHashTableShape,
17126 Handle<Object> >;
17127
17128 template class HashTable<WeakHashTable, WeakHashTableShape<2>, Handle<Object> >;
17129
17130 template class Dictionary<NameDictionary, NameDictionaryShape, Handle<Name> >;
17131
17132 template class Dictionary<GlobalDictionary, GlobalDictionaryShape,
17133 Handle<Name> >;
17134
17135 template class Dictionary<SeededNumberDictionary,
17136 SeededNumberDictionaryShape,
17137 uint32_t>;
17138
17139 template class Dictionary<UnseededNumberDictionary,
17140 UnseededNumberDictionaryShape,
17141 uint32_t>;
17142
17143 template Handle<SeededNumberDictionary>
17144 Dictionary<SeededNumberDictionary, SeededNumberDictionaryShape, uint32_t>::New(
17145 Isolate*, int at_least_space_for, PretenureFlag pretenure,
17146 MinimumCapacity capacity_option);
17147
17148 template Handle<UnseededNumberDictionary>
17149 Dictionary<UnseededNumberDictionary, UnseededNumberDictionaryShape,
17150 uint32_t>::New(Isolate*, int at_least_space_for,
17151 PretenureFlag pretenure,
17152 MinimumCapacity capacity_option);
17153
17154 template Handle<NameDictionary>
17155 Dictionary<NameDictionary, NameDictionaryShape, Handle<Name>>::New(
17156 Isolate*, int n, PretenureFlag pretenure, MinimumCapacity capacity_option);
17157
17158 template Handle<GlobalDictionary>
17159 Dictionary<GlobalDictionary, GlobalDictionaryShape, Handle<Name>>::New(
17160 Isolate*, int n, PretenureFlag pretenure, MinimumCapacity capacity_option);
17161
17162 template Handle<SeededNumberDictionary>
17163 Dictionary<SeededNumberDictionary, SeededNumberDictionaryShape, uint32_t>::
17164 AtPut(Handle<SeededNumberDictionary>, uint32_t, Handle<Object>);
17165
17166 template Handle<UnseededNumberDictionary>
17167 Dictionary<UnseededNumberDictionary, UnseededNumberDictionaryShape, uint32_t>::
17168 AtPut(Handle<UnseededNumberDictionary>, uint32_t, Handle<Object>);
17169
17170 template Object*
17171 Dictionary<SeededNumberDictionary, SeededNumberDictionaryShape, uint32_t>::
17172 SlowReverseLookup(Object* value);
17173
17174 template Object*
17175 Dictionary<NameDictionary, NameDictionaryShape, Handle<Name> >::
17176 SlowReverseLookup(Object* value);
17177
17178 template Handle<Object>
17179 Dictionary<NameDictionary, NameDictionaryShape, Handle<Name> >::DeleteProperty(
17180 Handle<NameDictionary>, int);
17181
17182 template Handle<Object>
17183 Dictionary<SeededNumberDictionary, SeededNumberDictionaryShape,
17184 uint32_t>::DeleteProperty(Handle<SeededNumberDictionary>, int);
17185
17186 template Handle<Object>
17187 Dictionary<UnseededNumberDictionary, UnseededNumberDictionaryShape,
17188 uint32_t>::DeleteProperty(Handle<UnseededNumberDictionary>, int);
17189
17190 template Handle<NameDictionary>
17191 HashTable<NameDictionary, NameDictionaryShape, Handle<Name> >::
17192 New(Isolate*, int, MinimumCapacity, PretenureFlag);
17193
17194 template Handle<ObjectHashSet> HashTable<ObjectHashSet, ObjectHashSetShape,
17195 Handle<Object>>::New(Isolate*, int n,
17196 MinimumCapacity,
17197 PretenureFlag);
17198
17199 template Handle<NameDictionary>
17200 HashTable<NameDictionary, NameDictionaryShape, Handle<Name> >::
17201 Shrink(Handle<NameDictionary>, Handle<Name>);
17202
17203 template Handle<SeededNumberDictionary>
17204 HashTable<SeededNumberDictionary, SeededNumberDictionaryShape, uint32_t>::
17205 Shrink(Handle<SeededNumberDictionary>, uint32_t);
17206
17207 template Handle<UnseededNumberDictionary>
17208 HashTable<UnseededNumberDictionary, UnseededNumberDictionaryShape,
17209 uint32_t>::Shrink(Handle<UnseededNumberDictionary>, uint32_t);
17210
17211 template Handle<NameDictionary>
17212 Dictionary<NameDictionary, NameDictionaryShape, Handle<Name>>::Add(
17213 Handle<NameDictionary>, Handle<Name>, Handle<Object>, PropertyDetails,
17214 int*);
17215
17216 template Handle<GlobalDictionary>
17217 Dictionary<GlobalDictionary, GlobalDictionaryShape, Handle<Name>>::Add(
17218 Handle<GlobalDictionary>, Handle<Name>, Handle<Object>, PropertyDetails,
17219 int*);
17220
17221 template Handle<FixedArray> Dictionary<
17222 NameDictionary, NameDictionaryShape,
17223 Handle<Name> >::BuildIterationIndicesArray(Handle<NameDictionary>);
17224
17225 template Handle<FixedArray> Dictionary<
17226 NameDictionary, NameDictionaryShape,
17227 Handle<Name> >::GenerateNewEnumerationIndices(Handle<NameDictionary>);
17228
17229 template Handle<SeededNumberDictionary>
17230 Dictionary<SeededNumberDictionary, SeededNumberDictionaryShape, uint32_t>::Add(
17231 Handle<SeededNumberDictionary>, uint32_t, Handle<Object>, PropertyDetails,
17232 int*);
17233
17234 template Handle<UnseededNumberDictionary>
17235 Dictionary<UnseededNumberDictionary, UnseededNumberDictionaryShape,
17236 uint32_t>::Add(Handle<UnseededNumberDictionary>, uint32_t,
17237 Handle<Object>, PropertyDetails, int*);
17238
17239 template Handle<SeededNumberDictionary>
17240 Dictionary<SeededNumberDictionary, SeededNumberDictionaryShape, uint32_t>::
17241 EnsureCapacity(Handle<SeededNumberDictionary>, int, uint32_t);
17242
17243 template Handle<UnseededNumberDictionary>
17244 Dictionary<UnseededNumberDictionary, UnseededNumberDictionaryShape, uint32_t>::
17245 EnsureCapacity(Handle<UnseededNumberDictionary>, int, uint32_t);
17246
17247 template void Dictionary<NameDictionary, NameDictionaryShape,
17248 Handle<Name> >::SetRequiresCopyOnCapacityChange();
17249
17250 template Handle<NameDictionary>
17251 Dictionary<NameDictionary, NameDictionaryShape, Handle<Name> >::
17252 EnsureCapacity(Handle<NameDictionary>, int, Handle<Name>);
17253
17254 template int HashTable<SeededNumberDictionary, SeededNumberDictionaryShape,
17255 uint32_t>::FindEntry(uint32_t);
17256
17257 template int NameDictionaryBase<NameDictionary, NameDictionaryShape>::FindEntry(
17258 Handle<Name>);
17259
17260 template int Dictionary<GlobalDictionary, GlobalDictionaryShape, Handle<Name>>::
17261 NumberOfElementsFilterAttributes(PropertyFilter filter);
17262
17263 template int Dictionary<NameDictionary, NameDictionaryShape, Handle<Name>>::
17264 NumberOfElementsFilterAttributes(PropertyFilter filter);
17265
17266 template void
17267 Dictionary<GlobalDictionary, GlobalDictionaryShape, Handle<Name>>::
17268 CopyEnumKeysTo(Handle<Dictionary<GlobalDictionary, GlobalDictionaryShape,
17269 Handle<Name>>>
17270 dictionary,
17271 Handle<FixedArray> storage, KeyCollectionMode mode,
17272 KeyAccumulator* accumulator);
17273
17274 template void
17275 Dictionary<NameDictionary, NameDictionaryShape, Handle<Name>>::CopyEnumKeysTo(
17276 Handle<Dictionary<NameDictionary, NameDictionaryShape, Handle<Name>>>
17277 dictionary,
17278 Handle<FixedArray> storage, KeyCollectionMode mode,
17279 KeyAccumulator* accumulator);
17280
17281 template void
17282 Dictionary<GlobalDictionary, GlobalDictionaryShape, Handle<Name>>::
17283 CollectKeysTo(Handle<Dictionary<GlobalDictionary, GlobalDictionaryShape,
17284 Handle<Name>>>
17285 dictionary,
17286 KeyAccumulator* keys);
17287
17288 template void
17289 Dictionary<NameDictionary, NameDictionaryShape, Handle<Name>>::CollectKeysTo(
17290 Handle<Dictionary<NameDictionary, NameDictionaryShape, Handle<Name>>>
17291 dictionary,
17292 KeyAccumulator* keys);
17293
PrepareSlowElementsForSort(Handle<JSObject> object,uint32_t limit)17294 Handle<Object> JSObject::PrepareSlowElementsForSort(
17295 Handle<JSObject> object, uint32_t limit) {
17296 DCHECK(object->HasDictionaryElements());
17297 Isolate* isolate = object->GetIsolate();
17298 // Must stay in dictionary mode, either because of requires_slow_elements,
17299 // or because we are not going to sort (and therefore compact) all of the
17300 // elements.
17301 Handle<SeededNumberDictionary> dict(object->element_dictionary(), isolate);
17302 Handle<SeededNumberDictionary> new_dict =
17303 SeededNumberDictionary::New(isolate, dict->NumberOfElements());
17304
17305 uint32_t pos = 0;
17306 uint32_t undefs = 0;
17307 int capacity = dict->Capacity();
17308 Handle<Smi> bailout(Smi::FromInt(-1), isolate);
17309 // Entry to the new dictionary does not cause it to grow, as we have
17310 // allocated one that is large enough for all entries.
17311 DisallowHeapAllocation no_gc;
17312 for (int i = 0; i < capacity; i++) {
17313 Object* k = dict->KeyAt(i);
17314 if (!dict->IsKey(isolate, k)) continue;
17315
17316 DCHECK(k->IsNumber());
17317 DCHECK(!k->IsSmi() || Smi::cast(k)->value() >= 0);
17318 DCHECK(!k->IsHeapNumber() || HeapNumber::cast(k)->value() >= 0);
17319 DCHECK(!k->IsHeapNumber() || HeapNumber::cast(k)->value() <= kMaxUInt32);
17320
17321 HandleScope scope(isolate);
17322 Handle<Object> value(dict->ValueAt(i), isolate);
17323 PropertyDetails details = dict->DetailsAt(i);
17324 if (details.type() == ACCESSOR_CONSTANT || details.IsReadOnly()) {
17325 // Bail out and do the sorting of undefineds and array holes in JS.
17326 // Also bail out if the element is not supposed to be moved.
17327 return bailout;
17328 }
17329
17330 uint32_t key = NumberToUint32(k);
17331 if (key < limit) {
17332 if (value->IsUndefined(isolate)) {
17333 undefs++;
17334 } else if (pos > static_cast<uint32_t>(Smi::kMaxValue)) {
17335 // Adding an entry with the key beyond smi-range requires
17336 // allocation. Bailout.
17337 return bailout;
17338 } else {
17339 Handle<Object> result = SeededNumberDictionary::AddNumberEntry(
17340 new_dict, pos, value, details, object->map()->is_prototype_map());
17341 DCHECK(result.is_identical_to(new_dict));
17342 USE(result);
17343 pos++;
17344 }
17345 } else if (key > static_cast<uint32_t>(Smi::kMaxValue)) {
17346 // Adding an entry with the key beyond smi-range requires
17347 // allocation. Bailout.
17348 return bailout;
17349 } else {
17350 Handle<Object> result = SeededNumberDictionary::AddNumberEntry(
17351 new_dict, key, value, details, object->map()->is_prototype_map());
17352 DCHECK(result.is_identical_to(new_dict));
17353 USE(result);
17354 }
17355 }
17356
17357 uint32_t result = pos;
17358 PropertyDetails no_details = PropertyDetails::Empty();
17359 while (undefs > 0) {
17360 if (pos > static_cast<uint32_t>(Smi::kMaxValue)) {
17361 // Adding an entry with the key beyond smi-range requires
17362 // allocation. Bailout.
17363 return bailout;
17364 }
17365 HandleScope scope(isolate);
17366 Handle<Object> result = SeededNumberDictionary::AddNumberEntry(
17367 new_dict, pos, isolate->factory()->undefined_value(), no_details,
17368 object->map()->is_prototype_map());
17369 DCHECK(result.is_identical_to(new_dict));
17370 USE(result);
17371 pos++;
17372 undefs--;
17373 }
17374
17375 object->set_elements(*new_dict);
17376
17377 AllowHeapAllocation allocate_return_value;
17378 return isolate->factory()->NewNumberFromUint(result);
17379 }
17380
17381
17382 // Collects all defined (non-hole) and non-undefined (array) elements at
17383 // the start of the elements array.
17384 // If the object is in dictionary mode, it is converted to fast elements
17385 // mode.
PrepareElementsForSort(Handle<JSObject> object,uint32_t limit)17386 Handle<Object> JSObject::PrepareElementsForSort(Handle<JSObject> object,
17387 uint32_t limit) {
17388 Isolate* isolate = object->GetIsolate();
17389 if (object->HasSloppyArgumentsElements()) {
17390 return handle(Smi::FromInt(-1), isolate);
17391 }
17392
17393 if (object->HasStringWrapperElements()) {
17394 int len = String::cast(Handle<JSValue>::cast(object)->value())->length();
17395 return handle(Smi::FromInt(len), isolate);
17396 }
17397
17398 if (object->HasDictionaryElements()) {
17399 // Convert to fast elements containing only the existing properties.
17400 // Ordering is irrelevant, since we are going to sort anyway.
17401 Handle<SeededNumberDictionary> dict(object->element_dictionary());
17402 if (object->IsJSArray() || dict->requires_slow_elements() ||
17403 dict->max_number_key() >= limit) {
17404 return JSObject::PrepareSlowElementsForSort(object, limit);
17405 }
17406 // Convert to fast elements.
17407
17408 Handle<Map> new_map =
17409 JSObject::GetElementsTransitionMap(object, FAST_HOLEY_ELEMENTS);
17410
17411 PretenureFlag tenure = isolate->heap()->InNewSpace(*object) ?
17412 NOT_TENURED: TENURED;
17413 Handle<FixedArray> fast_elements =
17414 isolate->factory()->NewFixedArray(dict->NumberOfElements(), tenure);
17415 dict->CopyValuesTo(*fast_elements);
17416 JSObject::ValidateElements(object);
17417
17418 JSObject::SetMapAndElements(object, new_map, fast_elements);
17419 } else if (object->HasFixedTypedArrayElements()) {
17420 // Typed arrays cannot have holes or undefined elements.
17421 return handle(Smi::FromInt(
17422 FixedArrayBase::cast(object->elements())->length()), isolate);
17423 } else if (!object->HasFastDoubleElements()) {
17424 EnsureWritableFastElements(object);
17425 }
17426 DCHECK(object->HasFastSmiOrObjectElements() ||
17427 object->HasFastDoubleElements());
17428
17429 // Collect holes at the end, undefined before that and the rest at the
17430 // start, and return the number of non-hole, non-undefined values.
17431
17432 Handle<FixedArrayBase> elements_base(object->elements());
17433 uint32_t elements_length = static_cast<uint32_t>(elements_base->length());
17434 if (limit > elements_length) {
17435 limit = elements_length;
17436 }
17437 if (limit == 0) {
17438 return handle(Smi::kZero, isolate);
17439 }
17440
17441 uint32_t result = 0;
17442 if (elements_base->map() == isolate->heap()->fixed_double_array_map()) {
17443 FixedDoubleArray* elements = FixedDoubleArray::cast(*elements_base);
17444 // Split elements into defined and the_hole, in that order.
17445 unsigned int holes = limit;
17446 // Assume most arrays contain no holes and undefined values, so minimize the
17447 // number of stores of non-undefined, non-the-hole values.
17448 for (unsigned int i = 0; i < holes; i++) {
17449 if (elements->is_the_hole(i)) {
17450 holes--;
17451 } else {
17452 continue;
17453 }
17454 // Position i needs to be filled.
17455 while (holes > i) {
17456 if (elements->is_the_hole(holes)) {
17457 holes--;
17458 } else {
17459 elements->set(i, elements->get_scalar(holes));
17460 break;
17461 }
17462 }
17463 }
17464 result = holes;
17465 while (holes < limit) {
17466 elements->set_the_hole(holes);
17467 holes++;
17468 }
17469 } else {
17470 FixedArray* elements = FixedArray::cast(*elements_base);
17471 DisallowHeapAllocation no_gc;
17472
17473 // Split elements into defined, undefined and the_hole, in that order. Only
17474 // count locations for undefined and the hole, and fill them afterwards.
17475 WriteBarrierMode write_barrier = elements->GetWriteBarrierMode(no_gc);
17476 unsigned int undefs = limit;
17477 unsigned int holes = limit;
17478 // Assume most arrays contain no holes and undefined values, so minimize the
17479 // number of stores of non-undefined, non-the-hole values.
17480 for (unsigned int i = 0; i < undefs; i++) {
17481 Object* current = elements->get(i);
17482 if (current->IsTheHole(isolate)) {
17483 holes--;
17484 undefs--;
17485 } else if (current->IsUndefined(isolate)) {
17486 undefs--;
17487 } else {
17488 continue;
17489 }
17490 // Position i needs to be filled.
17491 while (undefs > i) {
17492 current = elements->get(undefs);
17493 if (current->IsTheHole(isolate)) {
17494 holes--;
17495 undefs--;
17496 } else if (current->IsUndefined(isolate)) {
17497 undefs--;
17498 } else {
17499 elements->set(i, current, write_barrier);
17500 break;
17501 }
17502 }
17503 }
17504 result = undefs;
17505 while (undefs < holes) {
17506 elements->set_undefined(undefs);
17507 undefs++;
17508 }
17509 while (holes < limit) {
17510 elements->set_the_hole(holes);
17511 holes++;
17512 }
17513 }
17514
17515 return isolate->factory()->NewNumberFromUint(result);
17516 }
17517
17518
type()17519 ExternalArrayType JSTypedArray::type() {
17520 switch (elements()->map()->instance_type()) {
17521 #define INSTANCE_TYPE_TO_ARRAY_TYPE(Type, type, TYPE, ctype, size) \
17522 case FIXED_##TYPE##_ARRAY_TYPE: \
17523 return kExternal##Type##Array;
17524
17525 TYPED_ARRAYS(INSTANCE_TYPE_TO_ARRAY_TYPE)
17526 #undef INSTANCE_TYPE_TO_ARRAY_TYPE
17527
17528 default:
17529 UNREACHABLE();
17530 return static_cast<ExternalArrayType>(-1);
17531 }
17532 }
17533
17534
element_size()17535 size_t JSTypedArray::element_size() {
17536 switch (elements()->map()->instance_type()) {
17537 #define INSTANCE_TYPE_TO_ELEMENT_SIZE(Type, type, TYPE, ctype, size) \
17538 case FIXED_##TYPE##_ARRAY_TYPE: \
17539 return size;
17540
17541 TYPED_ARRAYS(INSTANCE_TYPE_TO_ELEMENT_SIZE)
17542 #undef INSTANCE_TYPE_TO_ELEMENT_SIZE
17543
17544 default:
17545 UNREACHABLE();
17546 return 0;
17547 }
17548 }
17549
17550
InvalidatePropertyCell(Handle<JSGlobalObject> global,Handle<Name> name)17551 void JSGlobalObject::InvalidatePropertyCell(Handle<JSGlobalObject> global,
17552 Handle<Name> name) {
17553 DCHECK(!global->HasFastProperties());
17554 auto dictionary = handle(global->global_dictionary());
17555 int entry = dictionary->FindEntry(name);
17556 if (entry == GlobalDictionary::kNotFound) return;
17557 PropertyCell::InvalidateEntry(dictionary, entry);
17558 }
17559
EnsureEmptyPropertyCell(Handle<JSGlobalObject> global,Handle<Name> name,PropertyCellType cell_type,int * entry_out)17560 Handle<PropertyCell> JSGlobalObject::EnsureEmptyPropertyCell(
17561 Handle<JSGlobalObject> global, Handle<Name> name,
17562 PropertyCellType cell_type, int* entry_out) {
17563 Isolate* isolate = global->GetIsolate();
17564 DCHECK(!global->HasFastProperties());
17565 Handle<GlobalDictionary> dictionary(global->global_dictionary(), isolate);
17566 int entry = dictionary->FindEntry(name);
17567 Handle<PropertyCell> cell;
17568 if (entry != GlobalDictionary::kNotFound) {
17569 if (entry_out) *entry_out = entry;
17570 // This call should be idempotent.
17571 DCHECK(dictionary->ValueAt(entry)->IsPropertyCell());
17572 cell = handle(PropertyCell::cast(dictionary->ValueAt(entry)));
17573 PropertyCellType original_cell_type = cell->property_details().cell_type();
17574 DCHECK(original_cell_type == PropertyCellType::kInvalidated ||
17575 original_cell_type == PropertyCellType::kUninitialized);
17576 DCHECK(cell->value()->IsTheHole(isolate));
17577 if (original_cell_type == PropertyCellType::kInvalidated) {
17578 cell = PropertyCell::InvalidateEntry(dictionary, entry);
17579 }
17580 PropertyDetails details(NONE, DATA, 0, cell_type);
17581 cell->set_property_details(details);
17582 return cell;
17583 }
17584 cell = isolate->factory()->NewPropertyCell();
17585 PropertyDetails details(NONE, DATA, 0, cell_type);
17586 dictionary =
17587 GlobalDictionary::Add(dictionary, name, cell, details, entry_out);
17588 // {*entry_out} is initialized inside GlobalDictionary::Add().
17589 global->set_properties(*dictionary);
17590 return cell;
17591 }
17592
17593
17594 // This class is used for looking up two character strings in the string table.
17595 // If we don't have a hit we don't want to waste much time so we unroll the
17596 // string hash calculation loop here for speed. Doesn't work if the two
17597 // characters form a decimal integer, since such strings have a different hash
17598 // algorithm.
17599 class TwoCharHashTableKey : public HashTableKey {
17600 public:
TwoCharHashTableKey(uint16_t c1,uint16_t c2,uint32_t seed)17601 TwoCharHashTableKey(uint16_t c1, uint16_t c2, uint32_t seed)
17602 : c1_(c1), c2_(c2) {
17603 // Char 1.
17604 uint32_t hash = seed;
17605 hash += c1;
17606 hash += hash << 10;
17607 hash ^= hash >> 6;
17608 // Char 2.
17609 hash += c2;
17610 hash += hash << 10;
17611 hash ^= hash >> 6;
17612 // GetHash.
17613 hash += hash << 3;
17614 hash ^= hash >> 11;
17615 hash += hash << 15;
17616 if ((hash & String::kHashBitMask) == 0) hash = StringHasher::kZeroHash;
17617 hash_ = hash;
17618 #ifdef DEBUG
17619 // If this assert fails then we failed to reproduce the two-character
17620 // version of the string hashing algorithm above. One reason could be
17621 // that we were passed two digits as characters, since the hash
17622 // algorithm is different in that case.
17623 uint16_t chars[2] = {c1, c2};
17624 uint32_t check_hash = StringHasher::HashSequentialString(chars, 2, seed);
17625 hash = (hash << String::kHashShift) | String::kIsNotArrayIndexMask;
17626 DCHECK_EQ(static_cast<int32_t>(hash), static_cast<int32_t>(check_hash));
17627 #endif
17628 }
17629
IsMatch(Object * o)17630 bool IsMatch(Object* o) override {
17631 if (!o->IsString()) return false;
17632 String* other = String::cast(o);
17633 if (other->length() != 2) return false;
17634 if (other->Get(0) != c1_) return false;
17635 return other->Get(1) == c2_;
17636 }
17637
Hash()17638 uint32_t Hash() override { return hash_; }
HashForObject(Object * key)17639 uint32_t HashForObject(Object* key) override {
17640 if (!key->IsString()) return 0;
17641 return String::cast(key)->Hash();
17642 }
17643
AsHandle(Isolate * isolate)17644 Handle<Object> AsHandle(Isolate* isolate) override {
17645 // The TwoCharHashTableKey is only used for looking in the string
17646 // table, not for adding to it.
17647 UNREACHABLE();
17648 return MaybeHandle<Object>().ToHandleChecked();
17649 }
17650
17651 private:
17652 uint16_t c1_;
17653 uint16_t c2_;
17654 uint32_t hash_;
17655 };
17656
17657
InternalizeStringIfExists(Isolate * isolate,Handle<String> string)17658 MaybeHandle<String> StringTable::InternalizeStringIfExists(
17659 Isolate* isolate,
17660 Handle<String> string) {
17661 if (string->IsInternalizedString()) {
17662 return string;
17663 }
17664 return LookupStringIfExists(isolate, string);
17665 }
17666
17667
LookupStringIfExists(Isolate * isolate,Handle<String> string)17668 MaybeHandle<String> StringTable::LookupStringIfExists(
17669 Isolate* isolate,
17670 Handle<String> string) {
17671 Handle<StringTable> string_table = isolate->factory()->string_table();
17672 InternalizedStringKey key(string);
17673 int entry = string_table->FindEntry(&key);
17674 if (entry == kNotFound) {
17675 return MaybeHandle<String>();
17676 } else {
17677 Handle<String> result(String::cast(string_table->KeyAt(entry)), isolate);
17678 DCHECK(StringShape(*result).IsInternalized());
17679 return result;
17680 }
17681 }
17682
17683
LookupTwoCharsStringIfExists(Isolate * isolate,uint16_t c1,uint16_t c2)17684 MaybeHandle<String> StringTable::LookupTwoCharsStringIfExists(
17685 Isolate* isolate,
17686 uint16_t c1,
17687 uint16_t c2) {
17688 Handle<StringTable> string_table = isolate->factory()->string_table();
17689 TwoCharHashTableKey key(c1, c2, isolate->heap()->HashSeed());
17690 int entry = string_table->FindEntry(&key);
17691 if (entry == kNotFound) {
17692 return MaybeHandle<String>();
17693 } else {
17694 Handle<String> result(String::cast(string_table->KeyAt(entry)), isolate);
17695 DCHECK(StringShape(*result).IsInternalized());
17696 return result;
17697 }
17698 }
17699
17700
EnsureCapacityForDeserialization(Isolate * isolate,int expected)17701 void StringTable::EnsureCapacityForDeserialization(Isolate* isolate,
17702 int expected) {
17703 Handle<StringTable> table = isolate->factory()->string_table();
17704 // We need a key instance for the virtual hash function.
17705 InternalizedStringKey dummy_key(isolate->factory()->empty_string());
17706 table = StringTable::EnsureCapacity(table, expected, &dummy_key);
17707 isolate->heap()->SetRootStringTable(*table);
17708 }
17709
17710
LookupString(Isolate * isolate,Handle<String> string)17711 Handle<String> StringTable::LookupString(Isolate* isolate,
17712 Handle<String> string) {
17713 if (string->IsConsString() && string->IsFlat()) {
17714 string = String::Flatten(string);
17715 if (string->IsInternalizedString()) return string;
17716 }
17717
17718 InternalizedStringKey key(string);
17719 Handle<String> result = LookupKey(isolate, &key);
17720
17721 if (string->IsConsString()) {
17722 Handle<ConsString> cons = Handle<ConsString>::cast(string);
17723 cons->set_first(*result);
17724 cons->set_second(isolate->heap()->empty_string());
17725 } else if (string->IsSlicedString()) {
17726 STATIC_ASSERT(ConsString::kSize == SlicedString::kSize);
17727 DisallowHeapAllocation no_gc;
17728 bool one_byte = result->IsOneByteRepresentation();
17729 Handle<Map> map = one_byte ? isolate->factory()->cons_one_byte_string_map()
17730 : isolate->factory()->cons_string_map();
17731 string->set_map(*map);
17732 Handle<ConsString> cons = Handle<ConsString>::cast(string);
17733 cons->set_first(*result);
17734 cons->set_second(isolate->heap()->empty_string());
17735 }
17736 return result;
17737 }
17738
17739
LookupKey(Isolate * isolate,HashTableKey * key)17740 Handle<String> StringTable::LookupKey(Isolate* isolate, HashTableKey* key) {
17741 Handle<StringTable> table = isolate->factory()->string_table();
17742 int entry = table->FindEntry(key);
17743
17744 // String already in table.
17745 if (entry != kNotFound) {
17746 return handle(String::cast(table->KeyAt(entry)), isolate);
17747 }
17748
17749 // Adding new string. Grow table if needed.
17750 table = StringTable::EnsureCapacity(table, 1, key);
17751
17752 // Create string object.
17753 Handle<Object> string = key->AsHandle(isolate);
17754 // There must be no attempts to internalize strings that could throw
17755 // InvalidStringLength error.
17756 CHECK(!string.is_null());
17757
17758 // Add the new string and return it along with the string table.
17759 entry = table->FindInsertionEntry(key->Hash());
17760 table->set(EntryToIndex(entry), *string);
17761 table->ElementAdded();
17762
17763 isolate->heap()->SetRootStringTable(*table);
17764 return Handle<String>::cast(string);
17765 }
17766
17767
LookupKeyIfExists(Isolate * isolate,HashTableKey * key)17768 String* StringTable::LookupKeyIfExists(Isolate* isolate, HashTableKey* key) {
17769 Handle<StringTable> table = isolate->factory()->string_table();
17770 int entry = table->FindEntry(key);
17771 if (entry != kNotFound) return String::cast(table->KeyAt(entry));
17772 return NULL;
17773 }
17774
New(Isolate * isolate)17775 Handle<StringSet> StringSet::New(Isolate* isolate) {
17776 return HashTable::New(isolate, 0);
17777 }
17778
Add(Handle<StringSet> stringset,Handle<String> name)17779 Handle<StringSet> StringSet::Add(Handle<StringSet> stringset,
17780 Handle<String> name) {
17781 if (!stringset->Has(name)) {
17782 stringset = EnsureCapacity(stringset, 1, *name);
17783 uint32_t hash = StringSetShape::Hash(*name);
17784 int entry = stringset->FindInsertionEntry(hash);
17785 stringset->set(EntryToIndex(entry), *name);
17786 stringset->ElementAdded();
17787 }
17788 return stringset;
17789 }
17790
Has(Handle<String> name)17791 bool StringSet::Has(Handle<String> name) {
17792 return FindEntry(*name) != kNotFound;
17793 }
17794
Add(Handle<ObjectHashSet> set,Handle<Object> key)17795 Handle<ObjectHashSet> ObjectHashSet::Add(Handle<ObjectHashSet> set,
17796 Handle<Object> key) {
17797 Isolate* isolate = set->GetIsolate();
17798 int32_t hash = Object::GetOrCreateHash(isolate, key)->value();
17799
17800 if (!set->Has(isolate, key, hash)) {
17801 set = EnsureCapacity(set, 1, key);
17802 int entry = set->FindInsertionEntry(hash);
17803 set->set(EntryToIndex(entry), *key);
17804 set->ElementAdded();
17805 }
17806 return set;
17807 }
17808
Lookup(Handle<String> src,Handle<Context> context,LanguageMode language_mode)17809 Handle<Object> CompilationCacheTable::Lookup(Handle<String> src,
17810 Handle<Context> context,
17811 LanguageMode language_mode) {
17812 Isolate* isolate = GetIsolate();
17813 Handle<SharedFunctionInfo> shared(context->closure()->shared());
17814 StringSharedKey key(src, shared, language_mode, kNoSourcePosition);
17815 int entry = FindEntry(&key);
17816 if (entry == kNotFound) return isolate->factory()->undefined_value();
17817 int index = EntryToIndex(entry);
17818 if (!get(index)->IsFixedArray()) return isolate->factory()->undefined_value();
17819 return Handle<Object>(get(index + 1), isolate);
17820 }
17821
17822
LookupEval(Handle<String> src,Handle<SharedFunctionInfo> outer_info,LanguageMode language_mode,int scope_position)17823 Handle<Object> CompilationCacheTable::LookupEval(
17824 Handle<String> src, Handle<SharedFunctionInfo> outer_info,
17825 LanguageMode language_mode, int scope_position) {
17826 Isolate* isolate = GetIsolate();
17827 // Cache key is the tuple (source, outer shared function info, scope position)
17828 // to unambiguously identify the context chain the cached eval code assumes.
17829 StringSharedKey key(src, outer_info, language_mode, scope_position);
17830 int entry = FindEntry(&key);
17831 if (entry == kNotFound) return isolate->factory()->undefined_value();
17832 int index = EntryToIndex(entry);
17833 if (!get(index)->IsFixedArray()) return isolate->factory()->undefined_value();
17834 return Handle<Object>(get(EntryToIndex(entry) + 1), isolate);
17835 }
17836
17837
LookupRegExp(Handle<String> src,JSRegExp::Flags flags)17838 Handle<Object> CompilationCacheTable::LookupRegExp(Handle<String> src,
17839 JSRegExp::Flags flags) {
17840 Isolate* isolate = GetIsolate();
17841 DisallowHeapAllocation no_allocation;
17842 RegExpKey key(src, flags);
17843 int entry = FindEntry(&key);
17844 if (entry == kNotFound) return isolate->factory()->undefined_value();
17845 return Handle<Object>(get(EntryToIndex(entry) + 1), isolate);
17846 }
17847
17848
Put(Handle<CompilationCacheTable> cache,Handle<String> src,Handle<Context> context,LanguageMode language_mode,Handle<Object> value)17849 Handle<CompilationCacheTable> CompilationCacheTable::Put(
17850 Handle<CompilationCacheTable> cache, Handle<String> src,
17851 Handle<Context> context, LanguageMode language_mode, Handle<Object> value) {
17852 Isolate* isolate = cache->GetIsolate();
17853 Handle<SharedFunctionInfo> shared(context->closure()->shared());
17854 StringSharedKey key(src, shared, language_mode, kNoSourcePosition);
17855 Handle<Object> k = key.AsHandle(isolate);
17856 cache = EnsureCapacity(cache, 1, &key);
17857 int entry = cache->FindInsertionEntry(key.Hash());
17858 cache->set(EntryToIndex(entry), *k);
17859 cache->set(EntryToIndex(entry) + 1, *value);
17860 cache->ElementAdded();
17861 return cache;
17862 }
17863
17864
PutEval(Handle<CompilationCacheTable> cache,Handle<String> src,Handle<SharedFunctionInfo> outer_info,Handle<SharedFunctionInfo> value,int scope_position)17865 Handle<CompilationCacheTable> CompilationCacheTable::PutEval(
17866 Handle<CompilationCacheTable> cache, Handle<String> src,
17867 Handle<SharedFunctionInfo> outer_info, Handle<SharedFunctionInfo> value,
17868 int scope_position) {
17869 Isolate* isolate = cache->GetIsolate();
17870 StringSharedKey key(src, outer_info, value->language_mode(), scope_position);
17871 {
17872 Handle<Object> k = key.AsHandle(isolate);
17873 DisallowHeapAllocation no_allocation_scope;
17874 int entry = cache->FindEntry(&key);
17875 if (entry != kNotFound) {
17876 cache->set(EntryToIndex(entry), *k);
17877 cache->set(EntryToIndex(entry) + 1, *value);
17878 return cache;
17879 }
17880 }
17881
17882 cache = EnsureCapacity(cache, 1, &key);
17883 int entry = cache->FindInsertionEntry(key.Hash());
17884 Handle<Object> k =
17885 isolate->factory()->NewNumber(static_cast<double>(key.Hash()));
17886 cache->set(EntryToIndex(entry), *k);
17887 cache->set(EntryToIndex(entry) + 1, Smi::FromInt(kHashGenerations));
17888 cache->ElementAdded();
17889 return cache;
17890 }
17891
17892
PutRegExp(Handle<CompilationCacheTable> cache,Handle<String> src,JSRegExp::Flags flags,Handle<FixedArray> value)17893 Handle<CompilationCacheTable> CompilationCacheTable::PutRegExp(
17894 Handle<CompilationCacheTable> cache, Handle<String> src,
17895 JSRegExp::Flags flags, Handle<FixedArray> value) {
17896 RegExpKey key(src, flags);
17897 cache = EnsureCapacity(cache, 1, &key);
17898 int entry = cache->FindInsertionEntry(key.Hash());
17899 // We store the value in the key slot, and compare the search key
17900 // to the stored value with a custon IsMatch function during lookups.
17901 cache->set(EntryToIndex(entry), *value);
17902 cache->set(EntryToIndex(entry) + 1, *value);
17903 cache->ElementAdded();
17904 return cache;
17905 }
17906
17907
Age()17908 void CompilationCacheTable::Age() {
17909 DisallowHeapAllocation no_allocation;
17910 Object* the_hole_value = GetHeap()->the_hole_value();
17911 for (int entry = 0, size = Capacity(); entry < size; entry++) {
17912 int entry_index = EntryToIndex(entry);
17913 int value_index = entry_index + 1;
17914
17915 if (get(entry_index)->IsNumber()) {
17916 Smi* count = Smi::cast(get(value_index));
17917 count = Smi::FromInt(count->value() - 1);
17918 if (count->value() == 0) {
17919 NoWriteBarrierSet(this, entry_index, the_hole_value);
17920 NoWriteBarrierSet(this, value_index, the_hole_value);
17921 ElementRemoved();
17922 } else {
17923 NoWriteBarrierSet(this, value_index, count);
17924 }
17925 } else if (get(entry_index)->IsFixedArray()) {
17926 SharedFunctionInfo* info = SharedFunctionInfo::cast(get(value_index));
17927 if (info->code()->kind() != Code::FUNCTION || info->code()->IsOld()) {
17928 NoWriteBarrierSet(this, entry_index, the_hole_value);
17929 NoWriteBarrierSet(this, value_index, the_hole_value);
17930 ElementRemoved();
17931 }
17932 }
17933 }
17934 }
17935
17936
Remove(Object * value)17937 void CompilationCacheTable::Remove(Object* value) {
17938 DisallowHeapAllocation no_allocation;
17939 Object* the_hole_value = GetHeap()->the_hole_value();
17940 for (int entry = 0, size = Capacity(); entry < size; entry++) {
17941 int entry_index = EntryToIndex(entry);
17942 int value_index = entry_index + 1;
17943 if (get(value_index) == value) {
17944 NoWriteBarrierSet(this, entry_index, the_hole_value);
17945 NoWriteBarrierSet(this, value_index, the_hole_value);
17946 ElementRemoved();
17947 }
17948 }
17949 return;
17950 }
17951
17952 template <typename Derived, typename Shape, typename Key>
New(Isolate * isolate,int at_least_space_for,PretenureFlag pretenure,MinimumCapacity capacity_option)17953 Handle<Derived> Dictionary<Derived, Shape, Key>::New(
17954 Isolate* isolate, int at_least_space_for, PretenureFlag pretenure,
17955 MinimumCapacity capacity_option) {
17956 DCHECK(0 <= at_least_space_for);
17957 Handle<Derived> dict = DerivedHashTable::New(isolate, at_least_space_for,
17958 capacity_option, pretenure);
17959
17960 // Initialize the next enumeration index.
17961 dict->SetNextEnumerationIndex(PropertyDetails::kInitialIndex);
17962 return dict;
17963 }
17964
17965
17966 template <typename Derived, typename Shape, typename Key>
BuildIterationIndicesArray(Handle<Derived> dictionary)17967 Handle<FixedArray> Dictionary<Derived, Shape, Key>::BuildIterationIndicesArray(
17968 Handle<Derived> dictionary) {
17969 Isolate* isolate = dictionary->GetIsolate();
17970 Factory* factory = isolate->factory();
17971 int length = dictionary->NumberOfElements();
17972
17973 Handle<FixedArray> iteration_order = factory->NewFixedArray(length);
17974 Handle<FixedArray> enumeration_order = factory->NewFixedArray(length);
17975
17976 // Fill both the iteration order array and the enumeration order array
17977 // with property details.
17978 int capacity = dictionary->Capacity();
17979 int pos = 0;
17980 for (int i = 0; i < capacity; i++) {
17981 if (dictionary->IsKey(isolate, dictionary->KeyAt(i))) {
17982 int index = dictionary->DetailsAt(i).dictionary_index();
17983 iteration_order->set(pos, Smi::FromInt(i));
17984 enumeration_order->set(pos, Smi::FromInt(index));
17985 pos++;
17986 }
17987 }
17988 DCHECK(pos == length);
17989
17990 // Sort the arrays wrt. enumeration order.
17991 iteration_order->SortPairs(*enumeration_order, enumeration_order->length());
17992 return iteration_order;
17993 }
17994
17995
17996 template <typename Derived, typename Shape, typename Key>
17997 Handle<FixedArray>
GenerateNewEnumerationIndices(Handle<Derived> dictionary)17998 Dictionary<Derived, Shape, Key>::GenerateNewEnumerationIndices(
17999 Handle<Derived> dictionary) {
18000 int length = dictionary->NumberOfElements();
18001
18002 Handle<FixedArray> iteration_order = BuildIterationIndicesArray(dictionary);
18003 DCHECK(iteration_order->length() == length);
18004
18005 // Iterate over the dictionary using the enumeration order and update
18006 // the dictionary with new enumeration indices.
18007 for (int i = 0; i < length; i++) {
18008 int index = Smi::cast(iteration_order->get(i))->value();
18009 DCHECK(dictionary->IsKey(dictionary->KeyAt(index)));
18010
18011 int enum_index = PropertyDetails::kInitialIndex + i;
18012
18013 PropertyDetails details = dictionary->DetailsAt(index);
18014 PropertyDetails new_details = details.set_index(enum_index);
18015 dictionary->DetailsAtPut(index, new_details);
18016 }
18017
18018 // Set the next enumeration index.
18019 dictionary->SetNextEnumerationIndex(PropertyDetails::kInitialIndex+length);
18020 return iteration_order;
18021 }
18022
18023
18024 template <typename Derived, typename Shape, typename Key>
SetRequiresCopyOnCapacityChange()18025 void Dictionary<Derived, Shape, Key>::SetRequiresCopyOnCapacityChange() {
18026 DCHECK_EQ(0, DerivedHashTable::NumberOfElements());
18027 DCHECK_EQ(0, DerivedHashTable::NumberOfDeletedElements());
18028 // Make sure that HashTable::EnsureCapacity will create a copy.
18029 DerivedHashTable::SetNumberOfDeletedElements(DerivedHashTable::Capacity());
18030 DCHECK(!DerivedHashTable::HasSufficientCapacityToAdd(1));
18031 }
18032
18033
18034 template <typename Derived, typename Shape, typename Key>
EnsureCapacity(Handle<Derived> dictionary,int n,Key key)18035 Handle<Derived> Dictionary<Derived, Shape, Key>::EnsureCapacity(
18036 Handle<Derived> dictionary, int n, Key key) {
18037 // Check whether there are enough enumeration indices to add n elements.
18038 if (Shape::kIsEnumerable &&
18039 !PropertyDetails::IsValidIndex(dictionary->NextEnumerationIndex() + n)) {
18040 // If not, we generate new indices for the properties.
18041 GenerateNewEnumerationIndices(dictionary);
18042 }
18043 return DerivedHashTable::EnsureCapacity(dictionary, n, key);
18044 }
18045
18046
18047 template <typename Derived, typename Shape, typename Key>
DeleteProperty(Handle<Derived> dictionary,int entry)18048 Handle<Object> Dictionary<Derived, Shape, Key>::DeleteProperty(
18049 Handle<Derived> dictionary, int entry) {
18050 Factory* factory = dictionary->GetIsolate()->factory();
18051 PropertyDetails details = dictionary->DetailsAt(entry);
18052 if (!details.IsConfigurable()) return factory->false_value();
18053
18054 dictionary->SetEntry(
18055 entry, factory->the_hole_value(), factory->the_hole_value());
18056 dictionary->ElementRemoved();
18057 return factory->true_value();
18058 }
18059
18060
18061 template<typename Derived, typename Shape, typename Key>
AtPut(Handle<Derived> dictionary,Key key,Handle<Object> value)18062 Handle<Derived> Dictionary<Derived, Shape, Key>::AtPut(
18063 Handle<Derived> dictionary, Key key, Handle<Object> value) {
18064 int entry = dictionary->FindEntry(key);
18065
18066 // If the entry is present set the value;
18067 if (entry != Dictionary::kNotFound) {
18068 dictionary->ValueAtPut(entry, *value);
18069 return dictionary;
18070 }
18071
18072 // Check whether the dictionary should be extended.
18073 dictionary = EnsureCapacity(dictionary, 1, key);
18074 #ifdef DEBUG
18075 USE(Shape::AsHandle(dictionary->GetIsolate(), key));
18076 #endif
18077 PropertyDetails details = PropertyDetails::Empty();
18078
18079 AddEntry(dictionary, key, value, details, dictionary->Hash(key));
18080 return dictionary;
18081 }
18082
18083 template <typename Derived, typename Shape, typename Key>
Add(Handle<Derived> dictionary,Key key,Handle<Object> value,PropertyDetails details,int * entry_out)18084 Handle<Derived> Dictionary<Derived, Shape, Key>::Add(Handle<Derived> dictionary,
18085 Key key,
18086 Handle<Object> value,
18087 PropertyDetails details,
18088 int* entry_out) {
18089 // Valdate key is absent.
18090 SLOW_DCHECK((dictionary->FindEntry(key) == Dictionary::kNotFound));
18091 // Check whether the dictionary should be extended.
18092 dictionary = EnsureCapacity(dictionary, 1, key);
18093
18094 int entry = AddEntry(dictionary, key, value, details, dictionary->Hash(key));
18095 if (entry_out) *entry_out = entry;
18096 return dictionary;
18097 }
18098
18099 // Add a key, value pair to the dictionary. Returns entry value.
18100 template <typename Derived, typename Shape, typename Key>
AddEntry(Handle<Derived> dictionary,Key key,Handle<Object> value,PropertyDetails details,uint32_t hash)18101 int Dictionary<Derived, Shape, Key>::AddEntry(Handle<Derived> dictionary,
18102 Key key, Handle<Object> value,
18103 PropertyDetails details,
18104 uint32_t hash) {
18105 // Compute the key object.
18106 Handle<Object> k = Shape::AsHandle(dictionary->GetIsolate(), key);
18107
18108 uint32_t entry = dictionary->FindInsertionEntry(hash);
18109 // Insert element at empty or deleted entry
18110 if (details.dictionary_index() == 0 && Shape::kIsEnumerable) {
18111 // Assign an enumeration index to the property and update
18112 // SetNextEnumerationIndex.
18113 int index = dictionary->NextEnumerationIndex();
18114 details = details.set_index(index);
18115 dictionary->SetNextEnumerationIndex(index + 1);
18116 }
18117 dictionary->SetEntry(entry, k, value, details);
18118 DCHECK((dictionary->KeyAt(entry)->IsNumber() ||
18119 dictionary->KeyAt(entry)->IsName()));
18120 dictionary->ElementAdded();
18121 return entry;
18122 }
18123
HasComplexElements()18124 bool SeededNumberDictionary::HasComplexElements() {
18125 if (!requires_slow_elements()) return false;
18126 Isolate* isolate = this->GetIsolate();
18127 int capacity = this->Capacity();
18128 for (int i = 0; i < capacity; i++) {
18129 Object* k = this->KeyAt(i);
18130 if (!this->IsKey(isolate, k)) continue;
18131 DCHECK(!IsDeleted(i));
18132 PropertyDetails details = this->DetailsAt(i);
18133 if (details.type() == ACCESSOR_CONSTANT) return true;
18134 PropertyAttributes attr = details.attributes();
18135 if (attr & ALL_ATTRIBUTES_MASK) return true;
18136 }
18137 return false;
18138 }
18139
UpdateMaxNumberKey(uint32_t key,bool used_as_prototype)18140 void SeededNumberDictionary::UpdateMaxNumberKey(uint32_t key,
18141 bool used_as_prototype) {
18142 DisallowHeapAllocation no_allocation;
18143 // If the dictionary requires slow elements an element has already
18144 // been added at a high index.
18145 if (requires_slow_elements()) return;
18146 // Check if this index is high enough that we should require slow
18147 // elements.
18148 if (key > kRequiresSlowElementsLimit) {
18149 if (used_as_prototype) {
18150 // TODO(verwaest): Remove this hack.
18151 TypeFeedbackVector::ClearAllKeyedStoreICs(GetIsolate());
18152 }
18153 set_requires_slow_elements();
18154 return;
18155 }
18156 // Update max key value.
18157 Object* max_index_object = get(kMaxNumberKeyIndex);
18158 if (!max_index_object->IsSmi() || max_number_key() < key) {
18159 FixedArray::set(kMaxNumberKeyIndex,
18160 Smi::FromInt(key << kRequiresSlowElementsTagSize));
18161 }
18162 }
18163
18164
AddNumberEntry(Handle<SeededNumberDictionary> dictionary,uint32_t key,Handle<Object> value,PropertyDetails details,bool used_as_prototype)18165 Handle<SeededNumberDictionary> SeededNumberDictionary::AddNumberEntry(
18166 Handle<SeededNumberDictionary> dictionary, uint32_t key,
18167 Handle<Object> value, PropertyDetails details, bool used_as_prototype) {
18168 dictionary->UpdateMaxNumberKey(key, used_as_prototype);
18169 SLOW_DCHECK(dictionary->FindEntry(key) == kNotFound);
18170 return Add(dictionary, key, value, details);
18171 }
18172
18173
AddNumberEntry(Handle<UnseededNumberDictionary> dictionary,uint32_t key,Handle<Object> value)18174 Handle<UnseededNumberDictionary> UnseededNumberDictionary::AddNumberEntry(
18175 Handle<UnseededNumberDictionary> dictionary,
18176 uint32_t key,
18177 Handle<Object> value) {
18178 SLOW_DCHECK(dictionary->FindEntry(key) == kNotFound);
18179 return Add(dictionary, key, value, PropertyDetails::Empty());
18180 }
18181
DeleteKey(Handle<UnseededNumberDictionary> dictionary,uint32_t key)18182 Handle<UnseededNumberDictionary> UnseededNumberDictionary::DeleteKey(
18183 Handle<UnseededNumberDictionary> dictionary, uint32_t key) {
18184 int entry = dictionary->FindEntry(key);
18185 if (entry == kNotFound) return dictionary;
18186
18187 Factory* factory = dictionary->GetIsolate()->factory();
18188 dictionary->SetEntry(entry, factory->the_hole_value(),
18189 factory->the_hole_value());
18190 dictionary->ElementRemoved();
18191 return dictionary->Shrink(dictionary, key);
18192 }
18193
AtNumberPut(Handle<SeededNumberDictionary> dictionary,uint32_t key,Handle<Object> value,bool used_as_prototype)18194 Handle<SeededNumberDictionary> SeededNumberDictionary::AtNumberPut(
18195 Handle<SeededNumberDictionary> dictionary, uint32_t key,
18196 Handle<Object> value, bool used_as_prototype) {
18197 dictionary->UpdateMaxNumberKey(key, used_as_prototype);
18198 return AtPut(dictionary, key, value);
18199 }
18200
18201
AtNumberPut(Handle<UnseededNumberDictionary> dictionary,uint32_t key,Handle<Object> value)18202 Handle<UnseededNumberDictionary> UnseededNumberDictionary::AtNumberPut(
18203 Handle<UnseededNumberDictionary> dictionary,
18204 uint32_t key,
18205 Handle<Object> value) {
18206 return AtPut(dictionary, key, value);
18207 }
18208
18209
Set(Handle<SeededNumberDictionary> dictionary,uint32_t key,Handle<Object> value,PropertyDetails details,bool used_as_prototype)18210 Handle<SeededNumberDictionary> SeededNumberDictionary::Set(
18211 Handle<SeededNumberDictionary> dictionary, uint32_t key,
18212 Handle<Object> value, PropertyDetails details, bool used_as_prototype) {
18213 int entry = dictionary->FindEntry(key);
18214 if (entry == kNotFound) {
18215 return AddNumberEntry(dictionary, key, value, details, used_as_prototype);
18216 }
18217 // Preserve enumeration index.
18218 details = details.set_index(dictionary->DetailsAt(entry).dictionary_index());
18219 Handle<Object> object_key =
18220 SeededNumberDictionaryShape::AsHandle(dictionary->GetIsolate(), key);
18221 dictionary->SetEntry(entry, object_key, value, details);
18222 return dictionary;
18223 }
18224
18225
Set(Handle<UnseededNumberDictionary> dictionary,uint32_t key,Handle<Object> value)18226 Handle<UnseededNumberDictionary> UnseededNumberDictionary::Set(
18227 Handle<UnseededNumberDictionary> dictionary,
18228 uint32_t key,
18229 Handle<Object> value) {
18230 int entry = dictionary->FindEntry(key);
18231 if (entry == kNotFound) return AddNumberEntry(dictionary, key, value);
18232 Handle<Object> object_key =
18233 UnseededNumberDictionaryShape::AsHandle(dictionary->GetIsolate(), key);
18234 dictionary->SetEntry(entry, object_key, value);
18235 return dictionary;
18236 }
18237
18238
18239 template <typename Derived, typename Shape, typename Key>
NumberOfElementsFilterAttributes(PropertyFilter filter)18240 int Dictionary<Derived, Shape, Key>::NumberOfElementsFilterAttributes(
18241 PropertyFilter filter) {
18242 Isolate* isolate = this->GetIsolate();
18243 int capacity = this->Capacity();
18244 int result = 0;
18245 for (int i = 0; i < capacity; i++) {
18246 Object* k = this->KeyAt(i);
18247 if (this->IsKey(isolate, k) && !k->FilterKey(filter)) {
18248 if (this->IsDeleted(i)) continue;
18249 PropertyDetails details = this->DetailsAt(i);
18250 PropertyAttributes attr = details.attributes();
18251 if ((attr & filter) == 0) result++;
18252 }
18253 }
18254 return result;
18255 }
18256
18257
18258 template <typename Dictionary>
18259 struct EnumIndexComparator {
EnumIndexComparatorv8::internal::EnumIndexComparator18260 explicit EnumIndexComparator(Dictionary* dict) : dict(dict) {}
operator ()v8::internal::EnumIndexComparator18261 bool operator() (Smi* a, Smi* b) {
18262 PropertyDetails da(dict->DetailsAt(a->value()));
18263 PropertyDetails db(dict->DetailsAt(b->value()));
18264 return da.dictionary_index() < db.dictionary_index();
18265 }
18266 Dictionary* dict;
18267 };
18268
18269 template <typename Derived, typename Shape, typename Key>
CopyEnumKeysTo(Handle<Dictionary<Derived,Shape,Key>> dictionary,Handle<FixedArray> storage,KeyCollectionMode mode,KeyAccumulator * accumulator)18270 void Dictionary<Derived, Shape, Key>::CopyEnumKeysTo(
18271 Handle<Dictionary<Derived, Shape, Key>> dictionary,
18272 Handle<FixedArray> storage, KeyCollectionMode mode,
18273 KeyAccumulator* accumulator) {
18274 Isolate* isolate = dictionary->GetIsolate();
18275 int length = storage->length();
18276 int capacity = dictionary->Capacity();
18277 int properties = 0;
18278 for (int i = 0; i < capacity; i++) {
18279 Object* key = dictionary->KeyAt(i);
18280 bool is_shadowing_key = false;
18281 if (!dictionary->IsKey(isolate, key)) continue;
18282 if (key->IsSymbol()) continue;
18283 PropertyDetails details = dictionary->DetailsAt(i);
18284 if (details.IsDontEnum()) {
18285 if (mode == KeyCollectionMode::kIncludePrototypes) {
18286 is_shadowing_key = true;
18287 } else {
18288 continue;
18289 }
18290 }
18291 if (dictionary->IsDeleted(i)) continue;
18292 if (is_shadowing_key) {
18293 accumulator->AddShadowingKey(key);
18294 continue;
18295 } else {
18296 storage->set(properties, Smi::FromInt(i));
18297 }
18298 properties++;
18299 if (properties == length) break;
18300 }
18301
18302 CHECK_EQ(length, properties);
18303 DisallowHeapAllocation no_gc;
18304 Dictionary<Derived, Shape, Key>* raw_dictionary = *dictionary;
18305 FixedArray* raw_storage = *storage;
18306 EnumIndexComparator<Derived> cmp(static_cast<Derived*>(*dictionary));
18307 Smi** start = reinterpret_cast<Smi**>(storage->GetFirstElementAddress());
18308 std::sort(start, start + length, cmp);
18309 for (int i = 0; i < length; i++) {
18310 int index = Smi::cast(raw_storage->get(i))->value();
18311 raw_storage->set(i, raw_dictionary->KeyAt(index));
18312 }
18313 }
18314
18315 template <typename Derived, typename Shape, typename Key>
CollectKeysTo(Handle<Dictionary<Derived,Shape,Key>> dictionary,KeyAccumulator * keys)18316 void Dictionary<Derived, Shape, Key>::CollectKeysTo(
18317 Handle<Dictionary<Derived, Shape, Key>> dictionary, KeyAccumulator* keys) {
18318 Isolate* isolate = keys->isolate();
18319 int capacity = dictionary->Capacity();
18320 Handle<FixedArray> array =
18321 isolate->factory()->NewFixedArray(dictionary->NumberOfElements());
18322 int array_size = 0;
18323 PropertyFilter filter = keys->filter();
18324 {
18325 DisallowHeapAllocation no_gc;
18326 Dictionary<Derived, Shape, Key>* raw_dict = *dictionary;
18327 for (int i = 0; i < capacity; i++) {
18328 Object* k = raw_dict->KeyAt(i);
18329 if (!raw_dict->IsKey(isolate, k) || k->FilterKey(filter)) continue;
18330 if (raw_dict->IsDeleted(i)) continue;
18331 PropertyDetails details = raw_dict->DetailsAt(i);
18332 if ((details.attributes() & filter) != 0) {
18333 keys->AddShadowingKey(k);
18334 continue;
18335 }
18336 if (filter & ONLY_ALL_CAN_READ) {
18337 if (details.kind() != kAccessor) continue;
18338 Object* accessors = raw_dict->ValueAt(i);
18339 if (accessors->IsPropertyCell()) {
18340 accessors = PropertyCell::cast(accessors)->value();
18341 }
18342 if (!accessors->IsAccessorInfo()) continue;
18343 if (!AccessorInfo::cast(accessors)->all_can_read()) continue;
18344 }
18345 array->set(array_size++, Smi::FromInt(i));
18346 }
18347
18348 EnumIndexComparator<Derived> cmp(static_cast<Derived*>(raw_dict));
18349 Smi** start = reinterpret_cast<Smi**>(array->GetFirstElementAddress());
18350 std::sort(start, start + array_size, cmp);
18351 }
18352
18353 bool has_seen_symbol = false;
18354 for (int i = 0; i < array_size; i++) {
18355 int index = Smi::cast(array->get(i))->value();
18356 Object* key = dictionary->KeyAt(index);
18357 if (key->IsSymbol()) {
18358 has_seen_symbol = true;
18359 continue;
18360 }
18361 keys->AddKey(key, DO_NOT_CONVERT);
18362 }
18363 if (has_seen_symbol) {
18364 for (int i = 0; i < array_size; i++) {
18365 int index = Smi::cast(array->get(i))->value();
18366 Object* key = dictionary->KeyAt(index);
18367 if (!key->IsSymbol()) continue;
18368 keys->AddKey(key, DO_NOT_CONVERT);
18369 }
18370 }
18371 }
18372
18373
18374 // Backwards lookup (slow).
18375 template<typename Derived, typename Shape, typename Key>
SlowReverseLookup(Object * value)18376 Object* Dictionary<Derived, Shape, Key>::SlowReverseLookup(Object* value) {
18377 Isolate* isolate = this->GetIsolate();
18378 int capacity = this->Capacity();
18379 for (int i = 0; i < capacity; i++) {
18380 Object* k = this->KeyAt(i);
18381 if (!this->IsKey(isolate, k)) continue;
18382 Object* e = this->ValueAt(i);
18383 // TODO(dcarney): this should be templatized.
18384 if (e->IsPropertyCell()) {
18385 e = PropertyCell::cast(e)->value();
18386 }
18387 if (e == value) return k;
18388 }
18389 return isolate->heap()->undefined_value();
18390 }
18391
18392
Lookup(Isolate * isolate,Handle<Object> key,int32_t hash)18393 Object* ObjectHashTable::Lookup(Isolate* isolate, Handle<Object> key,
18394 int32_t hash) {
18395 DisallowHeapAllocation no_gc;
18396 DCHECK(IsKey(isolate, *key));
18397
18398 int entry = FindEntry(isolate, key, hash);
18399 if (entry == kNotFound) return isolate->heap()->the_hole_value();
18400 return get(EntryToIndex(entry) + 1);
18401 }
18402
18403
Lookup(Handle<Object> key)18404 Object* ObjectHashTable::Lookup(Handle<Object> key) {
18405 DisallowHeapAllocation no_gc;
18406
18407 Isolate* isolate = GetIsolate();
18408 DCHECK(IsKey(isolate, *key));
18409
18410 // If the object does not have an identity hash, it was never used as a key.
18411 Object* hash = key->GetHash();
18412 if (hash->IsUndefined(isolate)) {
18413 return isolate->heap()->the_hole_value();
18414 }
18415 return Lookup(isolate, key, Smi::cast(hash)->value());
18416 }
18417
ValueAt(int entry)18418 Object* ObjectHashTable::ValueAt(int entry) {
18419 return get(EntryToValueIndex(entry));
18420 }
18421
Lookup(Handle<Object> key,int32_t hash)18422 Object* ObjectHashTable::Lookup(Handle<Object> key, int32_t hash) {
18423 return Lookup(GetIsolate(), key, hash);
18424 }
18425
18426
Put(Handle<ObjectHashTable> table,Handle<Object> key,Handle<Object> value)18427 Handle<ObjectHashTable> ObjectHashTable::Put(Handle<ObjectHashTable> table,
18428 Handle<Object> key,
18429 Handle<Object> value) {
18430 Isolate* isolate = table->GetIsolate();
18431 DCHECK(table->IsKey(isolate, *key));
18432 DCHECK(!value->IsTheHole(isolate));
18433
18434 // Make sure the key object has an identity hash code.
18435 int32_t hash = Object::GetOrCreateHash(isolate, key)->value();
18436
18437 return Put(table, key, value, hash);
18438 }
18439
18440
Put(Handle<ObjectHashTable> table,Handle<Object> key,Handle<Object> value,int32_t hash)18441 Handle<ObjectHashTable> ObjectHashTable::Put(Handle<ObjectHashTable> table,
18442 Handle<Object> key,
18443 Handle<Object> value,
18444 int32_t hash) {
18445 Isolate* isolate = table->GetIsolate();
18446 DCHECK(table->IsKey(isolate, *key));
18447 DCHECK(!value->IsTheHole(isolate));
18448
18449 int entry = table->FindEntry(isolate, key, hash);
18450
18451 // Key is already in table, just overwrite value.
18452 if (entry != kNotFound) {
18453 table->set(EntryToIndex(entry) + 1, *value);
18454 return table;
18455 }
18456
18457 // Rehash if more than 33% of the entries are deleted entries.
18458 // TODO(jochen): Consider to shrink the fixed array in place.
18459 if ((table->NumberOfDeletedElements() << 1) > table->NumberOfElements()) {
18460 table->Rehash(isolate->factory()->undefined_value());
18461 }
18462 // If we're out of luck, we didn't get a GC recently, and so rehashing
18463 // isn't enough to avoid a crash.
18464 if (!table->HasSufficientCapacityToAdd(1)) {
18465 int nof = table->NumberOfElements() + 1;
18466 int capacity = ObjectHashTable::ComputeCapacity(nof * 2);
18467 if (capacity > ObjectHashTable::kMaxCapacity) {
18468 for (size_t i = 0; i < 2; ++i) {
18469 isolate->heap()->CollectAllGarbage(
18470 Heap::kFinalizeIncrementalMarkingMask,
18471 GarbageCollectionReason::kFullHashtable);
18472 }
18473 table->Rehash(isolate->factory()->undefined_value());
18474 }
18475 }
18476
18477 // Check whether the hash table should be extended.
18478 table = EnsureCapacity(table, 1, key);
18479 table->AddEntry(table->FindInsertionEntry(hash), *key, *value);
18480 return table;
18481 }
18482
18483
Remove(Handle<ObjectHashTable> table,Handle<Object> key,bool * was_present)18484 Handle<ObjectHashTable> ObjectHashTable::Remove(Handle<ObjectHashTable> table,
18485 Handle<Object> key,
18486 bool* was_present) {
18487 DCHECK(table->IsKey(table->GetIsolate(), *key));
18488
18489 Object* hash = key->GetHash();
18490 if (hash->IsUndefined(table->GetIsolate())) {
18491 *was_present = false;
18492 return table;
18493 }
18494
18495 return Remove(table, key, was_present, Smi::cast(hash)->value());
18496 }
18497
18498
Remove(Handle<ObjectHashTable> table,Handle<Object> key,bool * was_present,int32_t hash)18499 Handle<ObjectHashTable> ObjectHashTable::Remove(Handle<ObjectHashTable> table,
18500 Handle<Object> key,
18501 bool* was_present,
18502 int32_t hash) {
18503 Isolate* isolate = table->GetIsolate();
18504 DCHECK(table->IsKey(isolate, *key));
18505
18506 int entry = table->FindEntry(isolate, key, hash);
18507 if (entry == kNotFound) {
18508 *was_present = false;
18509 return table;
18510 }
18511
18512 *was_present = true;
18513 table->RemoveEntry(entry);
18514 return Shrink(table, key);
18515 }
18516
18517
AddEntry(int entry,Object * key,Object * value)18518 void ObjectHashTable::AddEntry(int entry, Object* key, Object* value) {
18519 set(EntryToIndex(entry), key);
18520 set(EntryToIndex(entry) + 1, value);
18521 ElementAdded();
18522 }
18523
18524
RemoveEntry(int entry)18525 void ObjectHashTable::RemoveEntry(int entry) {
18526 set_the_hole(EntryToIndex(entry));
18527 set_the_hole(EntryToIndex(entry) + 1);
18528 ElementRemoved();
18529 }
18530
18531
Lookup(Handle<HeapObject> key)18532 Object* WeakHashTable::Lookup(Handle<HeapObject> key) {
18533 DisallowHeapAllocation no_gc;
18534 Isolate* isolate = GetIsolate();
18535 DCHECK(IsKey(isolate, *key));
18536 int entry = FindEntry(key);
18537 if (entry == kNotFound) return isolate->heap()->the_hole_value();
18538 return get(EntryToValueIndex(entry));
18539 }
18540
18541
Put(Handle<WeakHashTable> table,Handle<HeapObject> key,Handle<HeapObject> value)18542 Handle<WeakHashTable> WeakHashTable::Put(Handle<WeakHashTable> table,
18543 Handle<HeapObject> key,
18544 Handle<HeapObject> value) {
18545 Isolate* isolate = key->GetIsolate();
18546 DCHECK(table->IsKey(isolate, *key));
18547 int entry = table->FindEntry(key);
18548 // Key is already in table, just overwrite value.
18549 if (entry != kNotFound) {
18550 table->set(EntryToValueIndex(entry), *value);
18551 return table;
18552 }
18553
18554 Handle<WeakCell> key_cell = isolate->factory()->NewWeakCell(key);
18555
18556 // Check whether the hash table should be extended.
18557 table = EnsureCapacity(table, 1, key, TENURED);
18558
18559 table->AddEntry(table->FindInsertionEntry(table->Hash(key)), key_cell, value);
18560 return table;
18561 }
18562
18563
AddEntry(int entry,Handle<WeakCell> key_cell,Handle<HeapObject> value)18564 void WeakHashTable::AddEntry(int entry, Handle<WeakCell> key_cell,
18565 Handle<HeapObject> value) {
18566 DisallowHeapAllocation no_allocation;
18567 set(EntryToIndex(entry), *key_cell);
18568 set(EntryToValueIndex(entry), *value);
18569 ElementAdded();
18570 }
18571
18572
18573 template<class Derived, class Iterator, int entrysize>
Allocate(Isolate * isolate,int capacity,PretenureFlag pretenure)18574 Handle<Derived> OrderedHashTable<Derived, Iterator, entrysize>::Allocate(
18575 Isolate* isolate, int capacity, PretenureFlag pretenure) {
18576 // Capacity must be a power of two, since we depend on being able
18577 // to divide and multiple by 2 (kLoadFactor) to derive capacity
18578 // from number of buckets. If we decide to change kLoadFactor
18579 // to something other than 2, capacity should be stored as another
18580 // field of this object.
18581 capacity = base::bits::RoundUpToPowerOfTwo32(Max(kMinCapacity, capacity));
18582 if (capacity > kMaxCapacity) {
18583 v8::internal::Heap::FatalProcessOutOfMemory("invalid table size", true);
18584 }
18585 int num_buckets = capacity / kLoadFactor;
18586 Handle<FixedArray> backing_store = isolate->factory()->NewFixedArray(
18587 kHashTableStartIndex + num_buckets + (capacity * kEntrySize), pretenure);
18588 backing_store->set_map_no_write_barrier(
18589 isolate->heap()->ordered_hash_table_map());
18590 Handle<Derived> table = Handle<Derived>::cast(backing_store);
18591 for (int i = 0; i < num_buckets; ++i) {
18592 table->set(kHashTableStartIndex + i, Smi::FromInt(kNotFound));
18593 }
18594 table->SetNumberOfBuckets(num_buckets);
18595 table->SetNumberOfElements(0);
18596 table->SetNumberOfDeletedElements(0);
18597 return table;
18598 }
18599
18600
18601 template<class Derived, class Iterator, int entrysize>
EnsureGrowable(Handle<Derived> table)18602 Handle<Derived> OrderedHashTable<Derived, Iterator, entrysize>::EnsureGrowable(
18603 Handle<Derived> table) {
18604 DCHECK(!table->IsObsolete());
18605
18606 int nof = table->NumberOfElements();
18607 int nod = table->NumberOfDeletedElements();
18608 int capacity = table->Capacity();
18609 if ((nof + nod) < capacity) return table;
18610 // Don't need to grow if we can simply clear out deleted entries instead.
18611 // Note that we can't compact in place, though, so we always allocate
18612 // a new table.
18613 return Rehash(table, (nod < (capacity >> 1)) ? capacity << 1 : capacity);
18614 }
18615
18616
18617 template<class Derived, class Iterator, int entrysize>
Shrink(Handle<Derived> table)18618 Handle<Derived> OrderedHashTable<Derived, Iterator, entrysize>::Shrink(
18619 Handle<Derived> table) {
18620 DCHECK(!table->IsObsolete());
18621
18622 int nof = table->NumberOfElements();
18623 int capacity = table->Capacity();
18624 if (nof >= (capacity >> 2)) return table;
18625 return Rehash(table, capacity / 2);
18626 }
18627
18628
18629 template<class Derived, class Iterator, int entrysize>
Clear(Handle<Derived> table)18630 Handle<Derived> OrderedHashTable<Derived, Iterator, entrysize>::Clear(
18631 Handle<Derived> table) {
18632 DCHECK(!table->IsObsolete());
18633
18634 Handle<Derived> new_table =
18635 Allocate(table->GetIsolate(),
18636 kMinCapacity,
18637 table->GetHeap()->InNewSpace(*table) ? NOT_TENURED : TENURED);
18638
18639 table->SetNextTable(*new_table);
18640 table->SetNumberOfDeletedElements(kClearedTableSentinel);
18641
18642 return new_table;
18643 }
18644
18645 template <class Derived, class Iterator, int entrysize>
HasKey(Handle<Derived> table,Handle<Object> key)18646 bool OrderedHashTable<Derived, Iterator, entrysize>::HasKey(
18647 Handle<Derived> table, Handle<Object> key) {
18648 DisallowHeapAllocation no_gc;
18649 Isolate* isolate = table->GetIsolate();
18650 Object* raw_key = *key;
18651 int entry = table->KeyToFirstEntry(isolate, raw_key);
18652 // Walk the chain in the bucket to find the key.
18653 while (entry != kNotFound) {
18654 Object* candidate_key = table->KeyAt(entry);
18655 if (candidate_key->SameValueZero(raw_key)) return true;
18656 entry = table->NextChainEntry(entry);
18657 }
18658 return false;
18659 }
18660
18661
Add(Handle<OrderedHashSet> table,Handle<Object> key)18662 Handle<OrderedHashSet> OrderedHashSet::Add(Handle<OrderedHashSet> table,
18663 Handle<Object> key) {
18664 int hash = Object::GetOrCreateHash(table->GetIsolate(), key)->value();
18665 int entry = table->HashToEntry(hash);
18666 // Walk the chain of the bucket and try finding the key.
18667 while (entry != kNotFound) {
18668 Object* candidate_key = table->KeyAt(entry);
18669 // Do not add if we have the key already
18670 if (candidate_key->SameValueZero(*key)) return table;
18671 entry = table->NextChainEntry(entry);
18672 }
18673
18674 table = OrderedHashSet::EnsureGrowable(table);
18675 // Read the existing bucket values.
18676 int bucket = table->HashToBucket(hash);
18677 int previous_entry = table->HashToEntry(hash);
18678 int nof = table->NumberOfElements();
18679 // Insert a new entry at the end,
18680 int new_entry = nof + table->NumberOfDeletedElements();
18681 int new_index = table->EntryToIndex(new_entry);
18682 table->set(new_index, *key);
18683 table->set(new_index + kChainOffset, Smi::FromInt(previous_entry));
18684 // and point the bucket to the new entry.
18685 table->set(kHashTableStartIndex + bucket, Smi::FromInt(new_entry));
18686 table->SetNumberOfElements(nof + 1);
18687 return table;
18688 }
18689
ConvertToKeysArray(Handle<OrderedHashSet> table,GetKeysConversion convert)18690 Handle<FixedArray> OrderedHashSet::ConvertToKeysArray(
18691 Handle<OrderedHashSet> table, GetKeysConversion convert) {
18692 Isolate* isolate = table->GetIsolate();
18693 int length = table->NumberOfElements();
18694 int nof_buckets = table->NumberOfBuckets();
18695 // Convert the dictionary to a linear list.
18696 Handle<FixedArray> result = Handle<FixedArray>::cast(table);
18697 // From this point on table is no longer a valid OrderedHashSet.
18698 result->set_map(isolate->heap()->fixed_array_map());
18699 for (int i = 0; i < length; i++) {
18700 int index = kHashTableStartIndex + nof_buckets + (i * kEntrySize);
18701 Object* key = table->get(index);
18702 if (convert == GetKeysConversion::kConvertToString && key->IsNumber()) {
18703 key = *isolate->factory()->NumberToString(handle(key, isolate));
18704 }
18705 result->set(i, key);
18706 }
18707 result->Shrink(length);
18708 return result;
18709 }
18710
18711 template<class Derived, class Iterator, int entrysize>
Rehash(Handle<Derived> table,int new_capacity)18712 Handle<Derived> OrderedHashTable<Derived, Iterator, entrysize>::Rehash(
18713 Handle<Derived> table, int new_capacity) {
18714 Isolate* isolate = table->GetIsolate();
18715 DCHECK(!table->IsObsolete());
18716
18717 Handle<Derived> new_table =
18718 Allocate(isolate, new_capacity,
18719 isolate->heap()->InNewSpace(*table) ? NOT_TENURED : TENURED);
18720 int nof = table->NumberOfElements();
18721 int nod = table->NumberOfDeletedElements();
18722 int new_buckets = new_table->NumberOfBuckets();
18723 int new_entry = 0;
18724 int removed_holes_index = 0;
18725
18726 DisallowHeapAllocation no_gc;
18727 for (int old_entry = 0; old_entry < (nof + nod); ++old_entry) {
18728 Object* key = table->KeyAt(old_entry);
18729 if (key->IsTheHole(isolate)) {
18730 table->SetRemovedIndexAt(removed_holes_index++, old_entry);
18731 continue;
18732 }
18733
18734 Object* hash = key->GetHash();
18735 int bucket = Smi::cast(hash)->value() & (new_buckets - 1);
18736 Object* chain_entry = new_table->get(kHashTableStartIndex + bucket);
18737 new_table->set(kHashTableStartIndex + bucket, Smi::FromInt(new_entry));
18738 int new_index = new_table->EntryToIndex(new_entry);
18739 int old_index = table->EntryToIndex(old_entry);
18740 for (int i = 0; i < entrysize; ++i) {
18741 Object* value = table->get(old_index + i);
18742 new_table->set(new_index + i, value);
18743 }
18744 new_table->set(new_index + kChainOffset, chain_entry);
18745 ++new_entry;
18746 }
18747
18748 DCHECK_EQ(nod, removed_holes_index);
18749
18750 new_table->SetNumberOfElements(nof);
18751 table->SetNextTable(*new_table);
18752
18753 return new_table;
18754 }
18755
18756
18757 template Handle<OrderedHashSet>
18758 OrderedHashTable<OrderedHashSet, JSSetIterator, 1>::Allocate(
18759 Isolate* isolate, int capacity, PretenureFlag pretenure);
18760
18761 template Handle<OrderedHashSet>
18762 OrderedHashTable<OrderedHashSet, JSSetIterator, 1>::EnsureGrowable(
18763 Handle<OrderedHashSet> table);
18764
18765 template Handle<OrderedHashSet>
18766 OrderedHashTable<OrderedHashSet, JSSetIterator, 1>::Shrink(
18767 Handle<OrderedHashSet> table);
18768
18769 template Handle<OrderedHashSet>
18770 OrderedHashTable<OrderedHashSet, JSSetIterator, 1>::Clear(
18771 Handle<OrderedHashSet> table);
18772
18773 template bool OrderedHashTable<OrderedHashSet, JSSetIterator, 1>::HasKey(
18774 Handle<OrderedHashSet> table, Handle<Object> key);
18775
18776
18777 template Handle<OrderedHashMap>
18778 OrderedHashTable<OrderedHashMap, JSMapIterator, 2>::Allocate(
18779 Isolate* isolate, int capacity, PretenureFlag pretenure);
18780
18781 template Handle<OrderedHashMap>
18782 OrderedHashTable<OrderedHashMap, JSMapIterator, 2>::EnsureGrowable(
18783 Handle<OrderedHashMap> table);
18784
18785 template Handle<OrderedHashMap>
18786 OrderedHashTable<OrderedHashMap, JSMapIterator, 2>::Shrink(
18787 Handle<OrderedHashMap> table);
18788
18789 template Handle<OrderedHashMap>
18790 OrderedHashTable<OrderedHashMap, JSMapIterator, 2>::Clear(
18791 Handle<OrderedHashMap> table);
18792
18793 template bool OrderedHashTable<OrderedHashMap, JSMapIterator, 2>::HasKey(
18794 Handle<OrderedHashMap> table, Handle<Object> key);
18795
18796
18797 template<class Derived, class TableType>
Transition()18798 void OrderedHashTableIterator<Derived, TableType>::Transition() {
18799 DisallowHeapAllocation no_allocation;
18800 TableType* table = TableType::cast(this->table());
18801 if (!table->IsObsolete()) return;
18802
18803 int index = Smi::cast(this->index())->value();
18804 while (table->IsObsolete()) {
18805 TableType* next_table = table->NextTable();
18806
18807 if (index > 0) {
18808 int nod = table->NumberOfDeletedElements();
18809
18810 if (nod == TableType::kClearedTableSentinel) {
18811 index = 0;
18812 } else {
18813 int old_index = index;
18814 for (int i = 0; i < nod; ++i) {
18815 int removed_index = table->RemovedIndexAt(i);
18816 if (removed_index >= old_index) break;
18817 --index;
18818 }
18819 }
18820 }
18821
18822 table = next_table;
18823 }
18824
18825 set_table(table);
18826 set_index(Smi::FromInt(index));
18827 }
18828
18829
18830 template<class Derived, class TableType>
HasMore()18831 bool OrderedHashTableIterator<Derived, TableType>::HasMore() {
18832 DisallowHeapAllocation no_allocation;
18833 Isolate* isolate = this->GetIsolate();
18834 if (this->table()->IsUndefined(isolate)) return false;
18835
18836 Transition();
18837
18838 TableType* table = TableType::cast(this->table());
18839 int index = Smi::cast(this->index())->value();
18840 int used_capacity = table->UsedCapacity();
18841
18842 while (index < used_capacity && table->KeyAt(index)->IsTheHole(isolate)) {
18843 index++;
18844 }
18845
18846 set_index(Smi::FromInt(index));
18847
18848 if (index < used_capacity) return true;
18849
18850 set_table(isolate->heap()->undefined_value());
18851 return false;
18852 }
18853
18854
18855 template<class Derived, class TableType>
Next(JSArray * value_array)18856 Smi* OrderedHashTableIterator<Derived, TableType>::Next(JSArray* value_array) {
18857 DisallowHeapAllocation no_allocation;
18858 if (HasMore()) {
18859 FixedArray* array = FixedArray::cast(value_array->elements());
18860 static_cast<Derived*>(this)->PopulateValueArray(array);
18861 MoveNext();
18862 return Smi::cast(kind());
18863 }
18864 return Smi::kZero;
18865 }
18866
18867
18868 template Smi*
18869 OrderedHashTableIterator<JSSetIterator, OrderedHashSet>::Next(
18870 JSArray* value_array);
18871
18872 template bool
18873 OrderedHashTableIterator<JSSetIterator, OrderedHashSet>::HasMore();
18874
18875 template void
18876 OrderedHashTableIterator<JSSetIterator, OrderedHashSet>::MoveNext();
18877
18878 template Object*
18879 OrderedHashTableIterator<JSSetIterator, OrderedHashSet>::CurrentKey();
18880
18881 template void
18882 OrderedHashTableIterator<JSSetIterator, OrderedHashSet>::Transition();
18883
18884
18885 template Smi*
18886 OrderedHashTableIterator<JSMapIterator, OrderedHashMap>::Next(
18887 JSArray* value_array);
18888
18889 template bool
18890 OrderedHashTableIterator<JSMapIterator, OrderedHashMap>::HasMore();
18891
18892 template void
18893 OrderedHashTableIterator<JSMapIterator, OrderedHashMap>::MoveNext();
18894
18895 template Object*
18896 OrderedHashTableIterator<JSMapIterator, OrderedHashMap>::CurrentKey();
18897
18898 template void
18899 OrderedHashTableIterator<JSMapIterator, OrderedHashMap>::Transition();
18900
18901
Initialize(Handle<JSSet> set,Isolate * isolate)18902 void JSSet::Initialize(Handle<JSSet> set, Isolate* isolate) {
18903 Handle<OrderedHashSet> table = isolate->factory()->NewOrderedHashSet();
18904 set->set_table(*table);
18905 }
18906
18907
Clear(Handle<JSSet> set)18908 void JSSet::Clear(Handle<JSSet> set) {
18909 Handle<OrderedHashSet> table(OrderedHashSet::cast(set->table()));
18910 table = OrderedHashSet::Clear(table);
18911 set->set_table(*table);
18912 }
18913
18914
Initialize(Handle<JSMap> map,Isolate * isolate)18915 void JSMap::Initialize(Handle<JSMap> map, Isolate* isolate) {
18916 Handle<OrderedHashMap> table = isolate->factory()->NewOrderedHashMap();
18917 map->set_table(*table);
18918 }
18919
18920
Clear(Handle<JSMap> map)18921 void JSMap::Clear(Handle<JSMap> map) {
18922 Handle<OrderedHashMap> table(OrderedHashMap::cast(map->table()));
18923 table = OrderedHashMap::Clear(table);
18924 map->set_table(*table);
18925 }
18926
18927
Initialize(Handle<JSWeakCollection> weak_collection,Isolate * isolate)18928 void JSWeakCollection::Initialize(Handle<JSWeakCollection> weak_collection,
18929 Isolate* isolate) {
18930 Handle<ObjectHashTable> table = ObjectHashTable::New(isolate, 0);
18931 weak_collection->set_table(*table);
18932 }
18933
18934
Set(Handle<JSWeakCollection> weak_collection,Handle<Object> key,Handle<Object> value,int32_t hash)18935 void JSWeakCollection::Set(Handle<JSWeakCollection> weak_collection,
18936 Handle<Object> key, Handle<Object> value,
18937 int32_t hash) {
18938 DCHECK(key->IsJSReceiver() || key->IsSymbol());
18939 Handle<ObjectHashTable> table(
18940 ObjectHashTable::cast(weak_collection->table()));
18941 DCHECK(table->IsKey(*key));
18942 Handle<ObjectHashTable> new_table =
18943 ObjectHashTable::Put(table, key, value, hash);
18944 weak_collection->set_table(*new_table);
18945 if (*table != *new_table) {
18946 // Zap the old table since we didn't record slots for its elements.
18947 table->FillWithHoles(0, table->length());
18948 }
18949 }
18950
18951
Delete(Handle<JSWeakCollection> weak_collection,Handle<Object> key,int32_t hash)18952 bool JSWeakCollection::Delete(Handle<JSWeakCollection> weak_collection,
18953 Handle<Object> key, int32_t hash) {
18954 DCHECK(key->IsJSReceiver() || key->IsSymbol());
18955 Handle<ObjectHashTable> table(
18956 ObjectHashTable::cast(weak_collection->table()));
18957 DCHECK(table->IsKey(*key));
18958 bool was_present = false;
18959 Handle<ObjectHashTable> new_table =
18960 ObjectHashTable::Remove(table, key, &was_present, hash);
18961 weak_collection->set_table(*new_table);
18962 if (*table != *new_table) {
18963 // Zap the old table since we didn't record slots for its elements.
18964 table->FillWithHoles(0, table->length());
18965 }
18966 return was_present;
18967 }
18968
18969 // Check if there is a break point at this source position.
HasBreakPoint(int source_position)18970 bool DebugInfo::HasBreakPoint(int source_position) {
18971 // Get the break point info object for this code offset.
18972 Object* break_point_info = GetBreakPointInfo(source_position);
18973
18974 // If there is no break point info object or no break points in the break
18975 // point info object there is no break point at this code offset.
18976 if (break_point_info->IsUndefined(GetIsolate())) return false;
18977 return BreakPointInfo::cast(break_point_info)->GetBreakPointCount() > 0;
18978 }
18979
18980 // Get the break point info object for this source position.
GetBreakPointInfo(int source_position)18981 Object* DebugInfo::GetBreakPointInfo(int source_position) {
18982 Isolate* isolate = GetIsolate();
18983 if (!break_points()->IsUndefined(isolate)) {
18984 for (int i = 0; i < break_points()->length(); i++) {
18985 if (!break_points()->get(i)->IsUndefined(isolate)) {
18986 BreakPointInfo* break_point_info =
18987 BreakPointInfo::cast(break_points()->get(i));
18988 if (break_point_info->source_position() == source_position) {
18989 return break_point_info;
18990 }
18991 }
18992 }
18993 }
18994 return isolate->heap()->undefined_value();
18995 }
18996
ClearBreakPoint(Handle<DebugInfo> debug_info,Handle<Object> break_point_object)18997 bool DebugInfo::ClearBreakPoint(Handle<DebugInfo> debug_info,
18998 Handle<Object> break_point_object) {
18999 Isolate* isolate = debug_info->GetIsolate();
19000 if (debug_info->break_points()->IsUndefined(isolate)) return false;
19001
19002 for (int i = 0; i < debug_info->break_points()->length(); i++) {
19003 if (debug_info->break_points()->get(i)->IsUndefined(isolate)) continue;
19004 Handle<BreakPointInfo> break_point_info = Handle<BreakPointInfo>(
19005 BreakPointInfo::cast(debug_info->break_points()->get(i)), isolate);
19006 if (BreakPointInfo::HasBreakPointObject(break_point_info,
19007 break_point_object)) {
19008 BreakPointInfo::ClearBreakPoint(break_point_info, break_point_object);
19009 return true;
19010 }
19011 }
19012 return false;
19013 }
19014
SetBreakPoint(Handle<DebugInfo> debug_info,int source_position,Handle<Object> break_point_object)19015 void DebugInfo::SetBreakPoint(Handle<DebugInfo> debug_info, int source_position,
19016 Handle<Object> break_point_object) {
19017 Isolate* isolate = debug_info->GetIsolate();
19018 Handle<Object> break_point_info(
19019 debug_info->GetBreakPointInfo(source_position), isolate);
19020 if (!break_point_info->IsUndefined(isolate)) {
19021 BreakPointInfo::SetBreakPoint(
19022 Handle<BreakPointInfo>::cast(break_point_info),
19023 break_point_object);
19024 return;
19025 }
19026
19027 // Adding a new break point for a code offset which did not have any
19028 // break points before. Try to find a free slot.
19029 static const int kNoBreakPointInfo = -1;
19030 int index = kNoBreakPointInfo;
19031 for (int i = 0; i < debug_info->break_points()->length(); i++) {
19032 if (debug_info->break_points()->get(i)->IsUndefined(isolate)) {
19033 index = i;
19034 break;
19035 }
19036 }
19037 if (index == kNoBreakPointInfo) {
19038 // No free slot - extend break point info array.
19039 Handle<FixedArray> old_break_points = Handle<FixedArray>(
19040 FixedArray::cast(debug_info->break_points()), isolate);
19041 Handle<FixedArray> new_break_points =
19042 isolate->factory()->NewFixedArray(
19043 old_break_points->length() +
19044 DebugInfo::kEstimatedNofBreakPointsInFunction);
19045
19046 debug_info->set_break_points(*new_break_points);
19047 for (int i = 0; i < old_break_points->length(); i++) {
19048 new_break_points->set(i, old_break_points->get(i));
19049 }
19050 index = old_break_points->length();
19051 }
19052 DCHECK(index != kNoBreakPointInfo);
19053
19054 // Allocate new BreakPointInfo object and set the break point.
19055 Handle<BreakPointInfo> new_break_point_info = Handle<BreakPointInfo>::cast(
19056 isolate->factory()->NewStruct(BREAK_POINT_INFO_TYPE));
19057 new_break_point_info->set_source_position(source_position);
19058 new_break_point_info->set_break_point_objects(
19059 isolate->heap()->undefined_value());
19060 BreakPointInfo::SetBreakPoint(new_break_point_info, break_point_object);
19061 debug_info->break_points()->set(index, *new_break_point_info);
19062 }
19063
19064 // Get the break point objects for a source position.
GetBreakPointObjects(int source_position)19065 Handle<Object> DebugInfo::GetBreakPointObjects(int source_position) {
19066 Object* break_point_info = GetBreakPointInfo(source_position);
19067 Isolate* isolate = GetIsolate();
19068 if (break_point_info->IsUndefined(isolate)) {
19069 return isolate->factory()->undefined_value();
19070 }
19071 return Handle<Object>(
19072 BreakPointInfo::cast(break_point_info)->break_point_objects(), isolate);
19073 }
19074
19075
19076 // Get the total number of break points.
GetBreakPointCount()19077 int DebugInfo::GetBreakPointCount() {
19078 Isolate* isolate = GetIsolate();
19079 if (break_points()->IsUndefined(isolate)) return 0;
19080 int count = 0;
19081 for (int i = 0; i < break_points()->length(); i++) {
19082 if (!break_points()->get(i)->IsUndefined(isolate)) {
19083 BreakPointInfo* break_point_info =
19084 BreakPointInfo::cast(break_points()->get(i));
19085 count += break_point_info->GetBreakPointCount();
19086 }
19087 }
19088 return count;
19089 }
19090
19091
FindBreakPointInfo(Handle<DebugInfo> debug_info,Handle<Object> break_point_object)19092 Handle<Object> DebugInfo::FindBreakPointInfo(
19093 Handle<DebugInfo> debug_info, Handle<Object> break_point_object) {
19094 Isolate* isolate = debug_info->GetIsolate();
19095 if (!debug_info->break_points()->IsUndefined(isolate)) {
19096 for (int i = 0; i < debug_info->break_points()->length(); i++) {
19097 if (!debug_info->break_points()->get(i)->IsUndefined(isolate)) {
19098 Handle<BreakPointInfo> break_point_info = Handle<BreakPointInfo>(
19099 BreakPointInfo::cast(debug_info->break_points()->get(i)), isolate);
19100 if (BreakPointInfo::HasBreakPointObject(break_point_info,
19101 break_point_object)) {
19102 return break_point_info;
19103 }
19104 }
19105 }
19106 }
19107 return isolate->factory()->undefined_value();
19108 }
19109
19110 // Remove the specified break point object.
ClearBreakPoint(Handle<BreakPointInfo> break_point_info,Handle<Object> break_point_object)19111 void BreakPointInfo::ClearBreakPoint(Handle<BreakPointInfo> break_point_info,
19112 Handle<Object> break_point_object) {
19113 Isolate* isolate = break_point_info->GetIsolate();
19114 // If there are no break points just ignore.
19115 if (break_point_info->break_point_objects()->IsUndefined(isolate)) return;
19116 // If there is a single break point clear it if it is the same.
19117 if (!break_point_info->break_point_objects()->IsFixedArray()) {
19118 if (break_point_info->break_point_objects() == *break_point_object) {
19119 break_point_info->set_break_point_objects(
19120 isolate->heap()->undefined_value());
19121 }
19122 return;
19123 }
19124 // If there are multiple break points shrink the array
19125 DCHECK(break_point_info->break_point_objects()->IsFixedArray());
19126 Handle<FixedArray> old_array =
19127 Handle<FixedArray>(
19128 FixedArray::cast(break_point_info->break_point_objects()));
19129 Handle<FixedArray> new_array =
19130 isolate->factory()->NewFixedArray(old_array->length() - 1);
19131 int found_count = 0;
19132 for (int i = 0; i < old_array->length(); i++) {
19133 if (old_array->get(i) == *break_point_object) {
19134 DCHECK(found_count == 0);
19135 found_count++;
19136 } else {
19137 new_array->set(i - found_count, old_array->get(i));
19138 }
19139 }
19140 // If the break point was found in the list change it.
19141 if (found_count > 0) break_point_info->set_break_point_objects(*new_array);
19142 }
19143
19144
19145 // Add the specified break point object.
SetBreakPoint(Handle<BreakPointInfo> break_point_info,Handle<Object> break_point_object)19146 void BreakPointInfo::SetBreakPoint(Handle<BreakPointInfo> break_point_info,
19147 Handle<Object> break_point_object) {
19148 Isolate* isolate = break_point_info->GetIsolate();
19149
19150 // If there was no break point objects before just set it.
19151 if (break_point_info->break_point_objects()->IsUndefined(isolate)) {
19152 break_point_info->set_break_point_objects(*break_point_object);
19153 return;
19154 }
19155 // If the break point object is the same as before just ignore.
19156 if (break_point_info->break_point_objects() == *break_point_object) return;
19157 // If there was one break point object before replace with array.
19158 if (!break_point_info->break_point_objects()->IsFixedArray()) {
19159 Handle<FixedArray> array = isolate->factory()->NewFixedArray(2);
19160 array->set(0, break_point_info->break_point_objects());
19161 array->set(1, *break_point_object);
19162 break_point_info->set_break_point_objects(*array);
19163 return;
19164 }
19165 // If there was more than one break point before extend array.
19166 Handle<FixedArray> old_array =
19167 Handle<FixedArray>(
19168 FixedArray::cast(break_point_info->break_point_objects()));
19169 Handle<FixedArray> new_array =
19170 isolate->factory()->NewFixedArray(old_array->length() + 1);
19171 for (int i = 0; i < old_array->length(); i++) {
19172 // If the break point was there before just ignore.
19173 if (old_array->get(i) == *break_point_object) return;
19174 new_array->set(i, old_array->get(i));
19175 }
19176 // Add the new break point.
19177 new_array->set(old_array->length(), *break_point_object);
19178 break_point_info->set_break_point_objects(*new_array);
19179 }
19180
19181
HasBreakPointObject(Handle<BreakPointInfo> break_point_info,Handle<Object> break_point_object)19182 bool BreakPointInfo::HasBreakPointObject(
19183 Handle<BreakPointInfo> break_point_info,
19184 Handle<Object> break_point_object) {
19185 // No break point.
19186 Isolate* isolate = break_point_info->GetIsolate();
19187 if (break_point_info->break_point_objects()->IsUndefined(isolate)) {
19188 return false;
19189 }
19190 // Single break point.
19191 if (!break_point_info->break_point_objects()->IsFixedArray()) {
19192 return break_point_info->break_point_objects() == *break_point_object;
19193 }
19194 // Multiple break points.
19195 FixedArray* array = FixedArray::cast(break_point_info->break_point_objects());
19196 for (int i = 0; i < array->length(); i++) {
19197 if (array->get(i) == *break_point_object) {
19198 return true;
19199 }
19200 }
19201 return false;
19202 }
19203
19204
19205 // Get the number of break points.
GetBreakPointCount()19206 int BreakPointInfo::GetBreakPointCount() {
19207 // No break point.
19208 if (break_point_objects()->IsUndefined(GetIsolate())) return 0;
19209 // Single break point.
19210 if (!break_point_objects()->IsFixedArray()) return 1;
19211 // Multiple break points.
19212 return FixedArray::cast(break_point_objects())->length();
19213 }
19214
19215
19216 // static
New(Handle<JSFunction> constructor,Handle<JSReceiver> new_target,double tv)19217 MaybeHandle<JSDate> JSDate::New(Handle<JSFunction> constructor,
19218 Handle<JSReceiver> new_target, double tv) {
19219 Isolate* const isolate = constructor->GetIsolate();
19220 Handle<JSObject> result;
19221 ASSIGN_RETURN_ON_EXCEPTION(isolate, result,
19222 JSObject::New(constructor, new_target), JSDate);
19223 if (-DateCache::kMaxTimeInMs <= tv && tv <= DateCache::kMaxTimeInMs) {
19224 tv = DoubleToInteger(tv) + 0.0;
19225 } else {
19226 tv = std::numeric_limits<double>::quiet_NaN();
19227 }
19228 Handle<Object> value = isolate->factory()->NewNumber(tv);
19229 Handle<JSDate>::cast(result)->SetValue(*value, std::isnan(tv));
19230 return Handle<JSDate>::cast(result);
19231 }
19232
19233
19234 // static
CurrentTimeValue(Isolate * isolate)19235 double JSDate::CurrentTimeValue(Isolate* isolate) {
19236 if (FLAG_log_timer_events || FLAG_prof_cpp) LOG(isolate, CurrentTimeEvent());
19237
19238 // According to ECMA-262, section 15.9.1, page 117, the precision of
19239 // the number in a Date object representing a particular instant in
19240 // time is milliseconds. Therefore, we floor the result of getting
19241 // the OS time.
19242 return Floor(FLAG_verify_predictable
19243 ? isolate->heap()->MonotonicallyIncreasingTimeInMs()
19244 : base::OS::TimeCurrentMillis());
19245 }
19246
19247
19248 // static
GetField(Object * object,Smi * index)19249 Object* JSDate::GetField(Object* object, Smi* index) {
19250 return JSDate::cast(object)->DoGetField(
19251 static_cast<FieldIndex>(index->value()));
19252 }
19253
19254
DoGetField(FieldIndex index)19255 Object* JSDate::DoGetField(FieldIndex index) {
19256 DCHECK(index != kDateValue);
19257
19258 DateCache* date_cache = GetIsolate()->date_cache();
19259
19260 if (index < kFirstUncachedField) {
19261 Object* stamp = cache_stamp();
19262 if (stamp != date_cache->stamp() && stamp->IsSmi()) {
19263 // Since the stamp is not NaN, the value is also not NaN.
19264 int64_t local_time_ms =
19265 date_cache->ToLocal(static_cast<int64_t>(value()->Number()));
19266 SetCachedFields(local_time_ms, date_cache);
19267 }
19268 switch (index) {
19269 case kYear: return year();
19270 case kMonth: return month();
19271 case kDay: return day();
19272 case kWeekday: return weekday();
19273 case kHour: return hour();
19274 case kMinute: return min();
19275 case kSecond: return sec();
19276 default: UNREACHABLE();
19277 }
19278 }
19279
19280 if (index >= kFirstUTCField) {
19281 return GetUTCField(index, value()->Number(), date_cache);
19282 }
19283
19284 double time = value()->Number();
19285 if (std::isnan(time)) return GetIsolate()->heap()->nan_value();
19286
19287 int64_t local_time_ms = date_cache->ToLocal(static_cast<int64_t>(time));
19288 int days = DateCache::DaysFromTime(local_time_ms);
19289
19290 if (index == kDays) return Smi::FromInt(days);
19291
19292 int time_in_day_ms = DateCache::TimeInDay(local_time_ms, days);
19293 if (index == kMillisecond) return Smi::FromInt(time_in_day_ms % 1000);
19294 DCHECK(index == kTimeInDay);
19295 return Smi::FromInt(time_in_day_ms);
19296 }
19297
19298
GetUTCField(FieldIndex index,double value,DateCache * date_cache)19299 Object* JSDate::GetUTCField(FieldIndex index,
19300 double value,
19301 DateCache* date_cache) {
19302 DCHECK(index >= kFirstUTCField);
19303
19304 if (std::isnan(value)) return GetIsolate()->heap()->nan_value();
19305
19306 int64_t time_ms = static_cast<int64_t>(value);
19307
19308 if (index == kTimezoneOffset) {
19309 return Smi::FromInt(date_cache->TimezoneOffset(time_ms));
19310 }
19311
19312 int days = DateCache::DaysFromTime(time_ms);
19313
19314 if (index == kWeekdayUTC) return Smi::FromInt(date_cache->Weekday(days));
19315
19316 if (index <= kDayUTC) {
19317 int year, month, day;
19318 date_cache->YearMonthDayFromDays(days, &year, &month, &day);
19319 if (index == kYearUTC) return Smi::FromInt(year);
19320 if (index == kMonthUTC) return Smi::FromInt(month);
19321 DCHECK(index == kDayUTC);
19322 return Smi::FromInt(day);
19323 }
19324
19325 int time_in_day_ms = DateCache::TimeInDay(time_ms, days);
19326 switch (index) {
19327 case kHourUTC: return Smi::FromInt(time_in_day_ms / (60 * 60 * 1000));
19328 case kMinuteUTC: return Smi::FromInt((time_in_day_ms / (60 * 1000)) % 60);
19329 case kSecondUTC: return Smi::FromInt((time_in_day_ms / 1000) % 60);
19330 case kMillisecondUTC: return Smi::FromInt(time_in_day_ms % 1000);
19331 case kDaysUTC: return Smi::FromInt(days);
19332 case kTimeInDayUTC: return Smi::FromInt(time_in_day_ms);
19333 default: UNREACHABLE();
19334 }
19335
19336 UNREACHABLE();
19337 return NULL;
19338 }
19339
19340
19341 // static
SetValue(Handle<JSDate> date,double v)19342 Handle<Object> JSDate::SetValue(Handle<JSDate> date, double v) {
19343 Isolate* const isolate = date->GetIsolate();
19344 Handle<Object> value = isolate->factory()->NewNumber(v);
19345 bool value_is_nan = std::isnan(v);
19346 date->SetValue(*value, value_is_nan);
19347 return value;
19348 }
19349
19350
SetValue(Object * value,bool is_value_nan)19351 void JSDate::SetValue(Object* value, bool is_value_nan) {
19352 set_value(value);
19353 if (is_value_nan) {
19354 HeapNumber* nan = GetIsolate()->heap()->nan_value();
19355 set_cache_stamp(nan, SKIP_WRITE_BARRIER);
19356 set_year(nan, SKIP_WRITE_BARRIER);
19357 set_month(nan, SKIP_WRITE_BARRIER);
19358 set_day(nan, SKIP_WRITE_BARRIER);
19359 set_hour(nan, SKIP_WRITE_BARRIER);
19360 set_min(nan, SKIP_WRITE_BARRIER);
19361 set_sec(nan, SKIP_WRITE_BARRIER);
19362 set_weekday(nan, SKIP_WRITE_BARRIER);
19363 } else {
19364 set_cache_stamp(Smi::FromInt(DateCache::kInvalidStamp), SKIP_WRITE_BARRIER);
19365 }
19366 }
19367
19368
19369 // static
ToPrimitive(Handle<JSReceiver> receiver,Handle<Object> hint)19370 MaybeHandle<Object> JSDate::ToPrimitive(Handle<JSReceiver> receiver,
19371 Handle<Object> hint) {
19372 Isolate* const isolate = receiver->GetIsolate();
19373 if (hint->IsString()) {
19374 Handle<String> hint_string = Handle<String>::cast(hint);
19375 if (hint_string->Equals(isolate->heap()->number_string())) {
19376 return JSReceiver::OrdinaryToPrimitive(receiver,
19377 OrdinaryToPrimitiveHint::kNumber);
19378 }
19379 if (hint_string->Equals(isolate->heap()->default_string()) ||
19380 hint_string->Equals(isolate->heap()->string_string())) {
19381 return JSReceiver::OrdinaryToPrimitive(receiver,
19382 OrdinaryToPrimitiveHint::kString);
19383 }
19384 }
19385 THROW_NEW_ERROR(isolate, NewTypeError(MessageTemplate::kInvalidHint, hint),
19386 Object);
19387 }
19388
19389
SetCachedFields(int64_t local_time_ms,DateCache * date_cache)19390 void JSDate::SetCachedFields(int64_t local_time_ms, DateCache* date_cache) {
19391 int days = DateCache::DaysFromTime(local_time_ms);
19392 int time_in_day_ms = DateCache::TimeInDay(local_time_ms, days);
19393 int year, month, day;
19394 date_cache->YearMonthDayFromDays(days, &year, &month, &day);
19395 int weekday = date_cache->Weekday(days);
19396 int hour = time_in_day_ms / (60 * 60 * 1000);
19397 int min = (time_in_day_ms / (60 * 1000)) % 60;
19398 int sec = (time_in_day_ms / 1000) % 60;
19399 set_cache_stamp(date_cache->stamp());
19400 set_year(Smi::FromInt(year), SKIP_WRITE_BARRIER);
19401 set_month(Smi::FromInt(month), SKIP_WRITE_BARRIER);
19402 set_day(Smi::FromInt(day), SKIP_WRITE_BARRIER);
19403 set_weekday(Smi::FromInt(weekday), SKIP_WRITE_BARRIER);
19404 set_hour(Smi::FromInt(hour), SKIP_WRITE_BARRIER);
19405 set_min(Smi::FromInt(min), SKIP_WRITE_BARRIER);
19406 set_sec(Smi::FromInt(sec), SKIP_WRITE_BARRIER);
19407 }
19408
19409 namespace {
19410
ScriptFromJSValue(Object * in)19411 Script* ScriptFromJSValue(Object* in) {
19412 DCHECK(in->IsJSValue());
19413 JSValue* jsvalue = JSValue::cast(in);
19414 DCHECK(jsvalue->value()->IsScript());
19415 return Script::cast(jsvalue->value());
19416 }
19417
19418 } // namespace
19419
GetLineNumber() const19420 int JSMessageObject::GetLineNumber() const {
19421 if (start_position() == -1) return Message::kNoLineNumberInfo;
19422
19423 Handle<Script> the_script = handle(ScriptFromJSValue(script()));
19424
19425 Script::PositionInfo info;
19426 const Script::OffsetFlag offset_flag = Script::WITH_OFFSET;
19427 if (!Script::GetPositionInfo(the_script, start_position(), &info,
19428 offset_flag)) {
19429 return Message::kNoLineNumberInfo;
19430 }
19431
19432 return info.line + 1;
19433 }
19434
GetColumnNumber() const19435 int JSMessageObject::GetColumnNumber() const {
19436 if (start_position() == -1) return -1;
19437
19438 Handle<Script> the_script = handle(ScriptFromJSValue(script()));
19439
19440 Script::PositionInfo info;
19441 const Script::OffsetFlag offset_flag = Script::WITH_OFFSET;
19442 if (!Script::GetPositionInfo(the_script, start_position(), &info,
19443 offset_flag)) {
19444 return -1;
19445 }
19446
19447 return info.column; // Note: No '+1' in contrast to GetLineNumber.
19448 }
19449
GetSourceLine() const19450 Handle<String> JSMessageObject::GetSourceLine() const {
19451 Handle<Script> the_script = handle(ScriptFromJSValue(script()));
19452
19453 Isolate* isolate = the_script->GetIsolate();
19454 if (the_script->type() == Script::TYPE_WASM) {
19455 return isolate->factory()->empty_string();
19456 }
19457
19458 Script::PositionInfo info;
19459 const Script::OffsetFlag offset_flag = Script::WITH_OFFSET;
19460 if (!Script::GetPositionInfo(the_script, start_position(), &info,
19461 offset_flag)) {
19462 return isolate->factory()->empty_string();
19463 }
19464
19465 Handle<String> src = handle(String::cast(the_script->source()), isolate);
19466 return isolate->factory()->NewSubString(src, info.line_start, info.line_end);
19467 }
19468
Neuter()19469 void JSArrayBuffer::Neuter() {
19470 CHECK(is_neuterable());
19471 CHECK(is_external());
19472 set_backing_store(NULL);
19473 set_byte_length(Smi::kZero);
19474 set_was_neutered(true);
19475 }
19476
19477
Setup(Handle<JSArrayBuffer> array_buffer,Isolate * isolate,bool is_external,void * data,size_t allocated_length,SharedFlag shared)19478 void JSArrayBuffer::Setup(Handle<JSArrayBuffer> array_buffer, Isolate* isolate,
19479 bool is_external, void* data, size_t allocated_length,
19480 SharedFlag shared) {
19481 DCHECK(array_buffer->GetInternalFieldCount() ==
19482 v8::ArrayBuffer::kInternalFieldCount);
19483 for (int i = 0; i < v8::ArrayBuffer::kInternalFieldCount; i++) {
19484 array_buffer->SetInternalField(i, Smi::kZero);
19485 }
19486 array_buffer->set_bit_field(0);
19487 array_buffer->set_is_external(is_external);
19488 array_buffer->set_is_neuterable(shared == SharedFlag::kNotShared);
19489 array_buffer->set_is_shared(shared == SharedFlag::kShared);
19490
19491 Handle<Object> byte_length =
19492 isolate->factory()->NewNumberFromSize(allocated_length);
19493 CHECK(byte_length->IsSmi() || byte_length->IsHeapNumber());
19494 array_buffer->set_byte_length(*byte_length);
19495 // Initialize backing store at last to avoid handling of |JSArrayBuffers| that
19496 // are currently being constructed in the |ArrayBufferTracker|. The
19497 // registration method below handles the case of registering a buffer that has
19498 // already been promoted.
19499 array_buffer->set_backing_store(data);
19500
19501 if (data && !is_external) {
19502 isolate->heap()->RegisterNewArrayBuffer(*array_buffer);
19503 }
19504 }
19505
19506
SetupAllocatingData(Handle<JSArrayBuffer> array_buffer,Isolate * isolate,size_t allocated_length,bool initialize,SharedFlag shared)19507 bool JSArrayBuffer::SetupAllocatingData(Handle<JSArrayBuffer> array_buffer,
19508 Isolate* isolate,
19509 size_t allocated_length,
19510 bool initialize, SharedFlag shared) {
19511 void* data;
19512 CHECK(isolate->array_buffer_allocator() != NULL);
19513 // Prevent creating array buffers when serializing.
19514 DCHECK(!isolate->serializer_enabled());
19515 if (allocated_length != 0) {
19516 if (initialize) {
19517 data = isolate->array_buffer_allocator()->Allocate(allocated_length);
19518 } else {
19519 data = isolate->array_buffer_allocator()->AllocateUninitialized(
19520 allocated_length);
19521 }
19522 if (data == NULL) return false;
19523 } else {
19524 data = NULL;
19525 }
19526
19527 JSArrayBuffer::Setup(array_buffer, isolate, false, data, allocated_length,
19528 shared);
19529 return true;
19530 }
19531
19532
MaterializeArrayBuffer(Handle<JSTypedArray> typed_array)19533 Handle<JSArrayBuffer> JSTypedArray::MaterializeArrayBuffer(
19534 Handle<JSTypedArray> typed_array) {
19535
19536 Handle<Map> map(typed_array->map());
19537 Isolate* isolate = typed_array->GetIsolate();
19538
19539 DCHECK(IsFixedTypedArrayElementsKind(map->elements_kind()));
19540
19541 Handle<FixedTypedArrayBase> fixed_typed_array(
19542 FixedTypedArrayBase::cast(typed_array->elements()));
19543
19544 Handle<JSArrayBuffer> buffer(JSArrayBuffer::cast(typed_array->buffer()),
19545 isolate);
19546 void* backing_store =
19547 isolate->array_buffer_allocator()->AllocateUninitialized(
19548 fixed_typed_array->DataSize());
19549 buffer->set_is_external(false);
19550 DCHECK(buffer->byte_length()->IsSmi() ||
19551 buffer->byte_length()->IsHeapNumber());
19552 DCHECK(NumberToInt32(buffer->byte_length()) == fixed_typed_array->DataSize());
19553 // Initialize backing store at last to avoid handling of |JSArrayBuffers| that
19554 // are currently being constructed in the |ArrayBufferTracker|. The
19555 // registration method below handles the case of registering a buffer that has
19556 // already been promoted.
19557 buffer->set_backing_store(backing_store);
19558 isolate->heap()->RegisterNewArrayBuffer(*buffer);
19559 memcpy(buffer->backing_store(),
19560 fixed_typed_array->DataPtr(),
19561 fixed_typed_array->DataSize());
19562 Handle<FixedTypedArrayBase> new_elements =
19563 isolate->factory()->NewFixedTypedArrayWithExternalPointer(
19564 fixed_typed_array->length(), typed_array->type(),
19565 static_cast<uint8_t*>(buffer->backing_store()));
19566
19567 typed_array->set_elements(*new_elements);
19568
19569 return buffer;
19570 }
19571
19572
GetBuffer()19573 Handle<JSArrayBuffer> JSTypedArray::GetBuffer() {
19574 Handle<JSArrayBuffer> array_buffer(JSArrayBuffer::cast(buffer()),
19575 GetIsolate());
19576 if (array_buffer->was_neutered() ||
19577 array_buffer->backing_store() != nullptr) {
19578 return array_buffer;
19579 }
19580 Handle<JSTypedArray> self(this);
19581 return MaterializeArrayBuffer(self);
19582 }
19583
InvalidateEntry(Handle<GlobalDictionary> dictionary,int entry)19584 Handle<PropertyCell> PropertyCell::InvalidateEntry(
19585 Handle<GlobalDictionary> dictionary, int entry) {
19586 Isolate* isolate = dictionary->GetIsolate();
19587 // Swap with a copy.
19588 DCHECK(dictionary->ValueAt(entry)->IsPropertyCell());
19589 Handle<PropertyCell> cell(PropertyCell::cast(dictionary->ValueAt(entry)));
19590 Handle<PropertyCell> new_cell = isolate->factory()->NewPropertyCell();
19591 new_cell->set_value(cell->value());
19592 dictionary->ValueAtPut(entry, *new_cell);
19593 bool is_the_hole = cell->value()->IsTheHole(isolate);
19594 // Cell is officially mutable henceforth.
19595 PropertyDetails details = cell->property_details();
19596 details = details.set_cell_type(is_the_hole ? PropertyCellType::kUninitialized
19597 : PropertyCellType::kMutable);
19598 new_cell->set_property_details(details);
19599 // Old cell is ready for invalidation.
19600 if (is_the_hole) {
19601 cell->set_value(isolate->heap()->undefined_value());
19602 } else {
19603 cell->set_value(isolate->heap()->the_hole_value());
19604 }
19605 details = details.set_cell_type(PropertyCellType::kInvalidated);
19606 cell->set_property_details(details);
19607 cell->dependent_code()->DeoptimizeDependentCodeGroup(
19608 isolate, DependentCode::kPropertyCellChangedGroup);
19609 return new_cell;
19610 }
19611
19612
GetConstantType()19613 PropertyCellConstantType PropertyCell::GetConstantType() {
19614 if (value()->IsSmi()) return PropertyCellConstantType::kSmi;
19615 return PropertyCellConstantType::kStableMap;
19616 }
19617
19618
RemainsConstantType(Handle<PropertyCell> cell,Handle<Object> value)19619 static bool RemainsConstantType(Handle<PropertyCell> cell,
19620 Handle<Object> value) {
19621 // TODO(dcarney): double->smi and smi->double transition from kConstant
19622 if (cell->value()->IsSmi() && value->IsSmi()) {
19623 return true;
19624 } else if (cell->value()->IsHeapObject() && value->IsHeapObject()) {
19625 return HeapObject::cast(cell->value())->map() ==
19626 HeapObject::cast(*value)->map() &&
19627 HeapObject::cast(*value)->map()->is_stable();
19628 }
19629 return false;
19630 }
19631
19632
UpdatedType(Handle<PropertyCell> cell,Handle<Object> value,PropertyDetails details)19633 PropertyCellType PropertyCell::UpdatedType(Handle<PropertyCell> cell,
19634 Handle<Object> value,
19635 PropertyDetails details) {
19636 PropertyCellType type = details.cell_type();
19637 Isolate* isolate = cell->GetIsolate();
19638 DCHECK(!value->IsTheHole(isolate));
19639 if (cell->value()->IsTheHole(isolate)) {
19640 switch (type) {
19641 // Only allow a cell to transition once into constant state.
19642 case PropertyCellType::kUninitialized:
19643 if (value->IsUndefined(isolate)) return PropertyCellType::kUndefined;
19644 return PropertyCellType::kConstant;
19645 case PropertyCellType::kInvalidated:
19646 return PropertyCellType::kMutable;
19647 default:
19648 UNREACHABLE();
19649 return PropertyCellType::kMutable;
19650 }
19651 }
19652 switch (type) {
19653 case PropertyCellType::kUndefined:
19654 return PropertyCellType::kConstant;
19655 case PropertyCellType::kConstant:
19656 if (*value == cell->value()) return PropertyCellType::kConstant;
19657 // Fall through.
19658 case PropertyCellType::kConstantType:
19659 if (RemainsConstantType(cell, value)) {
19660 return PropertyCellType::kConstantType;
19661 }
19662 // Fall through.
19663 case PropertyCellType::kMutable:
19664 return PropertyCellType::kMutable;
19665 }
19666 UNREACHABLE();
19667 return PropertyCellType::kMutable;
19668 }
19669
PrepareForValue(Handle<GlobalDictionary> dictionary,int entry,Handle<Object> value,PropertyDetails details)19670 Handle<PropertyCell> PropertyCell::PrepareForValue(
19671 Handle<GlobalDictionary> dictionary, int entry, Handle<Object> value,
19672 PropertyDetails details) {
19673 Isolate* isolate = dictionary->GetIsolate();
19674 DCHECK(!value->IsTheHole(isolate));
19675 DCHECK(dictionary->ValueAt(entry)->IsPropertyCell());
19676 Handle<PropertyCell> cell(PropertyCell::cast(dictionary->ValueAt(entry)));
19677 const PropertyDetails original_details = cell->property_details();
19678 // Data accesses could be cached in ics or optimized code.
19679 bool invalidate =
19680 original_details.kind() == kData && details.kind() == kAccessor;
19681 int index = original_details.dictionary_index();
19682 PropertyCellType old_type = original_details.cell_type();
19683 // Preserve the enumeration index unless the property was deleted or never
19684 // initialized.
19685 if (cell->value()->IsTheHole(isolate)) {
19686 index = dictionary->NextEnumerationIndex();
19687 dictionary->SetNextEnumerationIndex(index + 1);
19688 }
19689 DCHECK(index > 0);
19690 details = details.set_index(index);
19691
19692 PropertyCellType new_type = UpdatedType(cell, value, original_details);
19693 if (invalidate) cell = PropertyCell::InvalidateEntry(dictionary, entry);
19694
19695 // Install new property details.
19696 details = details.set_cell_type(new_type);
19697 cell->set_property_details(details);
19698
19699 // Deopt when transitioning from a constant type.
19700 if (!invalidate && (old_type != new_type ||
19701 original_details.IsReadOnly() != details.IsReadOnly())) {
19702 cell->dependent_code()->DeoptimizeDependentCodeGroup(
19703 isolate, DependentCode::kPropertyCellChangedGroup);
19704 }
19705 return cell;
19706 }
19707
19708
19709 // static
SetValueWithInvalidation(Handle<PropertyCell> cell,Handle<Object> new_value)19710 void PropertyCell::SetValueWithInvalidation(Handle<PropertyCell> cell,
19711 Handle<Object> new_value) {
19712 if (cell->value() != *new_value) {
19713 cell->set_value(*new_value);
19714 Isolate* isolate = cell->GetIsolate();
19715 cell->dependent_code()->DeoptimizeDependentCodeGroup(
19716 isolate, DependentCode::kPropertyCellChangedGroup);
19717 }
19718 }
19719
source_position() const19720 int JSGeneratorObject::source_position() const {
19721 CHECK(is_suspended());
19722 AbstractCode* code;
19723 int code_offset;
19724 if (function()->shared()->HasBytecodeArray()) {
19725 // New-style generators.
19726 DCHECK(!function()->shared()->HasBaselineCode());
19727 code_offset = Smi::cast(input_or_debug_pos())->value();
19728 // The stored bytecode offset is relative to a different base than what
19729 // is used in the source position table, hence the subtraction.
19730 code_offset -= BytecodeArray::kHeaderSize - kHeapObjectTag;
19731 code = AbstractCode::cast(function()->shared()->bytecode_array());
19732 } else {
19733 // Old-style generators.
19734 DCHECK(function()->shared()->HasBaselineCode());
19735 code_offset = continuation();
19736 CHECK(0 <= code_offset);
19737 CHECK(code_offset < function()->code()->instruction_size());
19738 code = AbstractCode::cast(function()->shared()->code());
19739 }
19740 return code->SourcePosition(code_offset);
19741 }
19742
19743 // static
Get(Isolate * isolate,Handle<JSObject> receiver)19744 AccessCheckInfo* AccessCheckInfo::Get(Isolate* isolate,
19745 Handle<JSObject> receiver) {
19746 DisallowHeapAllocation no_gc;
19747 DCHECK(receiver->map()->is_access_check_needed());
19748 Object* maybe_constructor = receiver->map()->GetConstructor();
19749 // Might happen for a detached context.
19750 if (!maybe_constructor->IsJSFunction()) return nullptr;
19751 JSFunction* constructor = JSFunction::cast(maybe_constructor);
19752 // Might happen for the debug context.
19753 if (!constructor->shared()->IsApiFunction()) return nullptr;
19754
19755 Object* data_obj =
19756 constructor->shared()->get_api_func_data()->access_check_info();
19757 if (data_obj->IsUndefined(isolate)) return nullptr;
19758
19759 return AccessCheckInfo::cast(data_obj);
19760 }
19761
HasProxyInPrototype(Isolate * isolate)19762 bool JSReceiver::HasProxyInPrototype(Isolate* isolate) {
19763 for (PrototypeIterator iter(isolate, this, kStartAtReceiver,
19764 PrototypeIterator::END_AT_NULL);
19765 !iter.IsAtEnd(); iter.AdvanceIgnoringProxies()) {
19766 if (iter.GetCurrent<Object>()->IsJSProxy()) return true;
19767 }
19768 return false;
19769 }
19770
GetExport(Handle<String> name)19771 MaybeHandle<Object> JSModuleNamespace::GetExport(Handle<String> name) {
19772 Isolate* isolate = name->GetIsolate();
19773
19774 Handle<Object> object(module()->exports()->Lookup(name), isolate);
19775 if (object->IsTheHole(isolate)) {
19776 return isolate->factory()->undefined_value();
19777 }
19778
19779 Handle<Object> value(Handle<Cell>::cast(object)->value(), isolate);
19780 if (value->IsTheHole(isolate)) {
19781 THROW_NEW_ERROR(
19782 isolate, NewReferenceError(MessageTemplate::kNotDefined, name), Object);
19783 }
19784
19785 return value;
19786 }
19787
19788 namespace {
19789
19790 struct ModuleHandleHash {
operator ()v8::internal::__anon91478ca21511::ModuleHandleHash19791 V8_INLINE size_t operator()(Handle<Module> module) const {
19792 return module->hash();
19793 }
19794 };
19795
19796 struct ModuleHandleEqual {
operator ()v8::internal::__anon91478ca21511::ModuleHandleEqual19797 V8_INLINE bool operator()(Handle<Module> lhs, Handle<Module> rhs) const {
19798 return *lhs == *rhs;
19799 }
19800 };
19801
19802 struct StringHandleHash {
operator ()v8::internal::__anon91478ca21511::StringHandleHash19803 V8_INLINE size_t operator()(Handle<String> string) const {
19804 return string->Hash();
19805 }
19806 };
19807
19808 struct StringHandleEqual {
operator ()v8::internal::__anon91478ca21511::StringHandleEqual19809 V8_INLINE bool operator()(Handle<String> lhs, Handle<String> rhs) const {
19810 return lhs->Equals(*rhs);
19811 }
19812 };
19813
19814 class UnorderedStringSet
19815 : public std::unordered_set<Handle<String>, StringHandleHash,
19816 StringHandleEqual,
19817 zone_allocator<Handle<String>>> {
19818 public:
UnorderedStringSet(Zone * zone)19819 explicit UnorderedStringSet(Zone* zone)
19820 : std::unordered_set<Handle<String>, StringHandleHash, StringHandleEqual,
19821 zone_allocator<Handle<String>>>(
19822 2 /* bucket count */, StringHandleHash(), StringHandleEqual(),
19823 zone_allocator<Handle<String>>(zone)) {}
19824 };
19825
19826 class UnorderedModuleSet
19827 : public std::unordered_set<Handle<Module>, ModuleHandleHash,
19828 ModuleHandleEqual,
19829 zone_allocator<Handle<Module>>> {
19830 public:
UnorderedModuleSet(Zone * zone)19831 explicit UnorderedModuleSet(Zone* zone)
19832 : std::unordered_set<Handle<Module>, ModuleHandleHash, ModuleHandleEqual,
19833 zone_allocator<Handle<Module>>>(
19834 2 /* bucket count */, ModuleHandleHash(), ModuleHandleEqual(),
19835 zone_allocator<Handle<Module>>(zone)) {}
19836 };
19837
19838 class UnorderedStringMap
19839 : public std::unordered_map<
19840 Handle<String>, Handle<Object>, StringHandleHash, StringHandleEqual,
19841 zone_allocator<std::pair<const Handle<String>, Handle<Object>>>> {
19842 public:
UnorderedStringMap(Zone * zone)19843 explicit UnorderedStringMap(Zone* zone)
19844 : std::unordered_map<
19845 Handle<String>, Handle<Object>, StringHandleHash, StringHandleEqual,
19846 zone_allocator<std::pair<const Handle<String>, Handle<Object>>>>(
19847 2 /* bucket count */, StringHandleHash(), StringHandleEqual(),
19848 zone_allocator<std::pair<const Handle<String>, Handle<Object>>>(
19849 zone)) {}
19850 };
19851
19852 } // anonymous namespace
19853
19854 class Module::ResolveSet
19855 : public std::unordered_map<
19856 Handle<Module>, UnorderedStringSet*, ModuleHandleHash,
19857 ModuleHandleEqual, zone_allocator<std::pair<const Handle<Module>,
19858 UnorderedStringSet*>>> {
19859 public:
ResolveSet(Zone * zone)19860 explicit ResolveSet(Zone* zone)
19861 : std::unordered_map<Handle<Module>, UnorderedStringSet*,
19862 ModuleHandleHash, ModuleHandleEqual,
19863 zone_allocator<std::pair<const Handle<Module>,
19864 UnorderedStringSet*>>>(
19865 2 /* bucket count */, ModuleHandleHash(), ModuleHandleEqual(),
19866 zone_allocator<
19867 std::pair<const Handle<Module>, UnorderedStringSet*>>(zone)),
19868 zone_(zone) {}
19869
zone() const19870 Zone* zone() const { return zone_; }
19871
19872 private:
19873 Zone* zone_;
19874 };
19875
19876 namespace {
19877
ExportIndex(int cell_index)19878 int ExportIndex(int cell_index) {
19879 DCHECK_EQ(ModuleDescriptor::GetCellIndexKind(cell_index),
19880 ModuleDescriptor::kExport);
19881 return cell_index - 1;
19882 }
19883
ImportIndex(int cell_index)19884 int ImportIndex(int cell_index) {
19885 DCHECK_EQ(ModuleDescriptor::GetCellIndexKind(cell_index),
19886 ModuleDescriptor::kImport);
19887 return -cell_index - 1;
19888 }
19889
19890 } // anonymous namespace
19891
CreateIndirectExport(Handle<Module> module,Handle<String> name,Handle<ModuleInfoEntry> entry)19892 void Module::CreateIndirectExport(Handle<Module> module, Handle<String> name,
19893 Handle<ModuleInfoEntry> entry) {
19894 Isolate* isolate = module->GetIsolate();
19895 Handle<ObjectHashTable> exports(module->exports(), isolate);
19896 DCHECK(exports->Lookup(name)->IsTheHole(isolate));
19897 exports = ObjectHashTable::Put(exports, name, entry);
19898 module->set_exports(*exports);
19899 }
19900
CreateExport(Handle<Module> module,int cell_index,Handle<FixedArray> names)19901 void Module::CreateExport(Handle<Module> module, int cell_index,
19902 Handle<FixedArray> names) {
19903 DCHECK_LT(0, names->length());
19904 Isolate* isolate = module->GetIsolate();
19905
19906 Handle<Cell> cell =
19907 isolate->factory()->NewCell(isolate->factory()->undefined_value());
19908 module->regular_exports()->set(ExportIndex(cell_index), *cell);
19909
19910 Handle<ObjectHashTable> exports(module->exports(), isolate);
19911 for (int i = 0, n = names->length(); i < n; ++i) {
19912 Handle<String> name(String::cast(names->get(i)), isolate);
19913 DCHECK(exports->Lookup(name)->IsTheHole(isolate));
19914 exports = ObjectHashTable::Put(exports, name, cell);
19915 }
19916 module->set_exports(*exports);
19917 }
19918
LoadVariable(Handle<Module> module,int cell_index)19919 Handle<Object> Module::LoadVariable(Handle<Module> module, int cell_index) {
19920 Isolate* isolate = module->GetIsolate();
19921 Handle<Object> object;
19922 switch (ModuleDescriptor::GetCellIndexKind(cell_index)) {
19923 case ModuleDescriptor::kImport:
19924 object = handle(module->regular_imports()->get(ImportIndex(cell_index)),
19925 isolate);
19926 break;
19927 case ModuleDescriptor::kExport:
19928 object = handle(module->regular_exports()->get(ExportIndex(cell_index)),
19929 isolate);
19930 break;
19931 case ModuleDescriptor::kInvalid:
19932 UNREACHABLE();
19933 break;
19934 }
19935 return handle(Handle<Cell>::cast(object)->value(), isolate);
19936 }
19937
StoreVariable(Handle<Module> module,int cell_index,Handle<Object> value)19938 void Module::StoreVariable(Handle<Module> module, int cell_index,
19939 Handle<Object> value) {
19940 Isolate* isolate = module->GetIsolate();
19941 DCHECK_EQ(ModuleDescriptor::GetCellIndexKind(cell_index),
19942 ModuleDescriptor::kExport);
19943 Handle<Object> object(module->regular_exports()->get(ExportIndex(cell_index)),
19944 isolate);
19945 Handle<Cell>::cast(object)->set_value(*value);
19946 }
19947
ResolveImport(Handle<Module> module,Handle<String> name,int module_request,MessageLocation loc,bool must_resolve,Module::ResolveSet * resolve_set)19948 MaybeHandle<Cell> Module::ResolveImport(Handle<Module> module,
19949 Handle<String> name, int module_request,
19950 MessageLocation loc, bool must_resolve,
19951 Module::ResolveSet* resolve_set) {
19952 Isolate* isolate = module->GetIsolate();
19953 Handle<Module> requested_module(
19954 Module::cast(module->requested_modules()->get(module_request)), isolate);
19955 return Module::ResolveExport(requested_module, name, loc, must_resolve,
19956 resolve_set);
19957 }
19958
ResolveExport(Handle<Module> module,Handle<String> name,MessageLocation loc,bool must_resolve,Module::ResolveSet * resolve_set)19959 MaybeHandle<Cell> Module::ResolveExport(Handle<Module> module,
19960 Handle<String> name,
19961 MessageLocation loc, bool must_resolve,
19962 Module::ResolveSet* resolve_set) {
19963 Isolate* isolate = module->GetIsolate();
19964 Handle<Object> object(module->exports()->Lookup(name), isolate);
19965 if (object->IsCell()) {
19966 // Already resolved (e.g. because it's a local export).
19967 return Handle<Cell>::cast(object);
19968 }
19969
19970 // Check for cycle before recursing.
19971 {
19972 // Attempt insertion with a null string set.
19973 auto result = resolve_set->insert({module, nullptr});
19974 UnorderedStringSet*& name_set = result.first->second;
19975 if (result.second) {
19976 // |module| wasn't in the map previously, so allocate a new name set.
19977 Zone* zone = resolve_set->zone();
19978 name_set =
19979 new (zone->New(sizeof(UnorderedStringSet))) UnorderedStringSet(zone);
19980 } else if (name_set->count(name)) {
19981 // Cycle detected.
19982 if (must_resolve) {
19983 return isolate->Throw<Cell>(
19984 isolate->factory()->NewSyntaxError(
19985 MessageTemplate::kCyclicModuleDependency, name),
19986 &loc);
19987 }
19988 return MaybeHandle<Cell>();
19989 }
19990 name_set->insert(name);
19991 }
19992
19993 if (object->IsModuleInfoEntry()) {
19994 // Not yet resolved indirect export.
19995 Handle<ModuleInfoEntry> entry = Handle<ModuleInfoEntry>::cast(object);
19996 Handle<String> import_name(String::cast(entry->import_name()), isolate);
19997 Handle<Script> script(
19998 Script::cast(JSFunction::cast(module->code())->shared()->script()),
19999 isolate);
20000 MessageLocation new_loc(script, entry->beg_pos(), entry->end_pos());
20001
20002 Handle<Cell> cell;
20003 if (!ResolveImport(module, import_name, entry->module_request(), new_loc,
20004 true, resolve_set)
20005 .ToHandle(&cell)) {
20006 DCHECK(isolate->has_pending_exception());
20007 return MaybeHandle<Cell>();
20008 }
20009
20010 // The export table may have changed but the entry in question should be
20011 // unchanged.
20012 Handle<ObjectHashTable> exports(module->exports(), isolate);
20013 DCHECK(exports->Lookup(name)->IsModuleInfoEntry());
20014
20015 exports = ObjectHashTable::Put(exports, name, cell);
20016 module->set_exports(*exports);
20017 return cell;
20018 }
20019
20020 DCHECK(object->IsTheHole(isolate));
20021 return Module::ResolveExportUsingStarExports(module, name, loc, must_resolve,
20022 resolve_set);
20023 }
20024
ResolveExportUsingStarExports(Handle<Module> module,Handle<String> name,MessageLocation loc,bool must_resolve,Module::ResolveSet * resolve_set)20025 MaybeHandle<Cell> Module::ResolveExportUsingStarExports(
20026 Handle<Module> module, Handle<String> name, MessageLocation loc,
20027 bool must_resolve, Module::ResolveSet* resolve_set) {
20028 Isolate* isolate = module->GetIsolate();
20029 if (!name->Equals(isolate->heap()->default_string())) {
20030 // Go through all star exports looking for the given name. If multiple star
20031 // exports provide the name, make sure they all map it to the same cell.
20032 Handle<Cell> unique_cell;
20033 Handle<FixedArray> special_exports(module->info()->special_exports(),
20034 isolate);
20035 for (int i = 0, n = special_exports->length(); i < n; ++i) {
20036 i::Handle<i::ModuleInfoEntry> entry(
20037 i::ModuleInfoEntry::cast(special_exports->get(i)), isolate);
20038 if (!entry->export_name()->IsUndefined(isolate)) {
20039 continue; // Indirect export.
20040 }
20041
20042 Handle<Script> script(
20043 Script::cast(JSFunction::cast(module->code())->shared()->script()),
20044 isolate);
20045 MessageLocation new_loc(script, entry->beg_pos(), entry->end_pos());
20046
20047 Handle<Cell> cell;
20048 if (ResolveImport(module, name, entry->module_request(), new_loc, false,
20049 resolve_set)
20050 .ToHandle(&cell)) {
20051 if (unique_cell.is_null()) unique_cell = cell;
20052 if (*unique_cell != *cell) {
20053 return isolate->Throw<Cell>(
20054 isolate->factory()->NewSyntaxError(
20055 MessageTemplate::kAmbiguousExport, name),
20056 &loc);
20057 }
20058 } else if (isolate->has_pending_exception()) {
20059 return MaybeHandle<Cell>();
20060 }
20061 }
20062
20063 if (!unique_cell.is_null()) {
20064 // Found a unique star export for this name.
20065 Handle<ObjectHashTable> exports(module->exports(), isolate);
20066 DCHECK(exports->Lookup(name)->IsTheHole(isolate));
20067 exports = ObjectHashTable::Put(exports, name, unique_cell);
20068 module->set_exports(*exports);
20069 return unique_cell;
20070 }
20071 }
20072
20073 // Unresolvable.
20074 if (must_resolve) {
20075 return isolate->Throw<Cell>(isolate->factory()->NewSyntaxError(
20076 MessageTemplate::kUnresolvableExport, name),
20077 &loc);
20078 }
20079 return MaybeHandle<Cell>();
20080 }
20081
Instantiate(Handle<Module> module,v8::Local<v8::Context> context,v8::Module::ResolveCallback callback)20082 bool Module::Instantiate(Handle<Module> module, v8::Local<v8::Context> context,
20083 v8::Module::ResolveCallback callback) {
20084 if (module->instantiated()) return true;
20085
20086 Isolate* isolate = module->GetIsolate();
20087 Handle<SharedFunctionInfo> shared(SharedFunctionInfo::cast(module->code()),
20088 isolate);
20089 Handle<JSFunction> function =
20090 isolate->factory()->NewFunctionFromSharedFunctionInfo(
20091 shared,
20092 handle(Utils::OpenHandle(*context)->native_context(), isolate));
20093 module->set_code(*function);
20094 DCHECK(module->instantiated());
20095
20096 Handle<ModuleInfo> module_info(shared->scope_info()->ModuleDescriptorInfo(),
20097 isolate);
20098
20099 // Set up local exports.
20100 // TODO(neis): Create regular_exports array here instead of in factory method?
20101 for (int i = 0, n = module_info->RegularExportCount(); i < n; ++i) {
20102 int cell_index = module_info->RegularExportCellIndex(i);
20103 Handle<FixedArray> export_names(module_info->RegularExportExportNames(i),
20104 isolate);
20105 CreateExport(module, cell_index, export_names);
20106 }
20107
20108 // Partially set up indirect exports.
20109 // For each indirect export, we create the appropriate slot in the export
20110 // table and store its ModuleInfoEntry there. When we later find the correct
20111 // Cell in the module that actually provides the value, we replace the
20112 // ModuleInfoEntry by that Cell (see ResolveExport).
20113 Handle<FixedArray> special_exports(module_info->special_exports(), isolate);
20114 for (int i = 0, n = special_exports->length(); i < n; ++i) {
20115 Handle<ModuleInfoEntry> entry(
20116 ModuleInfoEntry::cast(special_exports->get(i)), isolate);
20117 Handle<Object> export_name(entry->export_name(), isolate);
20118 if (export_name->IsUndefined(isolate)) continue; // Star export.
20119 CreateIndirectExport(module, Handle<String>::cast(export_name), entry);
20120 }
20121
20122 Handle<FixedArray> module_requests(module_info->module_requests(), isolate);
20123 for (int i = 0, length = module_requests->length(); i < length; ++i) {
20124 Handle<String> specifier(String::cast(module_requests->get(i)), isolate);
20125 v8::Local<v8::Module> api_requested_module;
20126 // TODO(adamk): Revisit these failure cases once d8 knows how to
20127 // persist a module_map across multiple top-level module loads, as
20128 // the current module is left in a "half-instantiated" state.
20129 if (!callback(context, v8::Utils::ToLocal(specifier),
20130 v8::Utils::ToLocal(module))
20131 .ToLocal(&api_requested_module)) {
20132 // TODO(adamk): Give this a better error message. But this is a
20133 // misuse of the API anyway.
20134 isolate->ThrowIllegalOperation();
20135 return false;
20136 }
20137 Handle<Module> requested_module = Utils::OpenHandle(*api_requested_module);
20138 module->requested_modules()->set(i, *requested_module);
20139 if (!Instantiate(requested_module, context, callback)) {
20140 return false;
20141 }
20142 }
20143
20144 Zone zone(isolate->allocator(), ZONE_NAME);
20145
20146 // Resolve imports.
20147 Handle<FixedArray> regular_imports(module_info->regular_imports(), isolate);
20148 for (int i = 0, n = regular_imports->length(); i < n; ++i) {
20149 Handle<ModuleInfoEntry> entry(
20150 ModuleInfoEntry::cast(regular_imports->get(i)), isolate);
20151 Handle<String> name(String::cast(entry->import_name()), isolate);
20152 Handle<Script> script(
20153 Script::cast(JSFunction::cast(module->code())->shared()->script()),
20154 isolate);
20155 MessageLocation loc(script, entry->beg_pos(), entry->end_pos());
20156 ResolveSet resolve_set(&zone);
20157 Handle<Cell> cell;
20158 if (!ResolveImport(module, name, entry->module_request(), loc, true,
20159 &resolve_set)
20160 .ToHandle(&cell)) {
20161 return false;
20162 }
20163 module->regular_imports()->set(ImportIndex(entry->cell_index()), *cell);
20164 }
20165
20166 // Resolve indirect exports.
20167 for (int i = 0, n = special_exports->length(); i < n; ++i) {
20168 Handle<ModuleInfoEntry> entry(
20169 ModuleInfoEntry::cast(special_exports->get(i)), isolate);
20170 Handle<Object> name(entry->export_name(), isolate);
20171 if (name->IsUndefined(isolate)) continue; // Star export.
20172 Handle<Script> script(
20173 Script::cast(JSFunction::cast(module->code())->shared()->script()),
20174 isolate);
20175 MessageLocation loc(script, entry->beg_pos(), entry->end_pos());
20176 ResolveSet resolve_set(&zone);
20177 if (ResolveExport(module, Handle<String>::cast(name), loc, true,
20178 &resolve_set)
20179 .is_null()) {
20180 return false;
20181 }
20182 }
20183
20184 return true;
20185 }
20186
Evaluate(Handle<Module> module)20187 MaybeHandle<Object> Module::Evaluate(Handle<Module> module) {
20188 DCHECK(module->instantiated());
20189
20190 // Each module can only be evaluated once.
20191 Isolate* isolate = module->GetIsolate();
20192 if (module->evaluated()) return isolate->factory()->undefined_value();
20193 Handle<JSFunction> function(JSFunction::cast(module->code()), isolate);
20194 module->set_evaluated();
20195
20196 // Initialization.
20197 DCHECK_EQ(MODULE_SCOPE, function->shared()->scope_info()->scope_type());
20198 Handle<Object> receiver = isolate->factory()->undefined_value();
20199 Handle<Object> argv[] = {module};
20200 Handle<Object> generator;
20201 ASSIGN_RETURN_ON_EXCEPTION(
20202 isolate, generator,
20203 Execution::Call(isolate, function, receiver, arraysize(argv), argv),
20204 Object);
20205
20206 // Recursion.
20207 Handle<FixedArray> requested_modules(module->requested_modules(), isolate);
20208 for (int i = 0, length = requested_modules->length(); i < length; ++i) {
20209 Handle<Module> import(Module::cast(requested_modules->get(i)), isolate);
20210 RETURN_ON_EXCEPTION(isolate, Evaluate(import), Object);
20211 }
20212
20213 // Evaluation of module body.
20214 Handle<JSFunction> resume(
20215 isolate->native_context()->generator_next_internal(), isolate);
20216 return Execution::Call(isolate, resume, generator, 0, nullptr);
20217 }
20218
20219 namespace {
20220
FetchStarExports(Handle<Module> module,Zone * zone,UnorderedModuleSet * visited)20221 void FetchStarExports(Handle<Module> module, Zone* zone,
20222 UnorderedModuleSet* visited) {
20223 DCHECK(module->instantiated());
20224
20225 bool cycle = !visited->insert(module).second;
20226 if (cycle) return;
20227
20228 Isolate* isolate = module->GetIsolate();
20229 Handle<ObjectHashTable> exports(module->exports(), isolate);
20230 UnorderedStringMap more_exports(zone);
20231
20232 // TODO(neis): Only allocate more_exports if there are star exports.
20233 // Maybe split special_exports into indirect_exports and star_exports.
20234
20235 Handle<FixedArray> special_exports(module->info()->special_exports(),
20236 isolate);
20237 for (int i = 0, n = special_exports->length(); i < n; ++i) {
20238 Handle<ModuleInfoEntry> entry(
20239 ModuleInfoEntry::cast(special_exports->get(i)), isolate);
20240 if (!entry->export_name()->IsUndefined(isolate)) {
20241 continue; // Indirect export.
20242 }
20243
20244 Handle<Module> requested_module(
20245 Module::cast(module->requested_modules()->get(entry->module_request())),
20246 isolate);
20247
20248 // Recurse.
20249 FetchStarExports(requested_module, zone, visited);
20250
20251 // Collect all of [requested_module]'s exports that must be added to
20252 // [module]'s exports (i.e. to [exports]). We record these in
20253 // [more_exports]. Ambiguities (conflicting exports) are marked by mapping
20254 // the name to undefined instead of a Cell.
20255 Handle<ObjectHashTable> requested_exports(requested_module->exports(),
20256 isolate);
20257 for (int i = 0, n = requested_exports->Capacity(); i < n; ++i) {
20258 Handle<Object> key(requested_exports->KeyAt(i), isolate);
20259 if (!requested_exports->IsKey(isolate, *key)) continue;
20260 Handle<String> name = Handle<String>::cast(key);
20261
20262 if (name->Equals(isolate->heap()->default_string())) continue;
20263 if (!exports->Lookup(name)->IsTheHole(isolate)) continue;
20264
20265 Handle<Cell> cell(Cell::cast(requested_exports->ValueAt(i)), isolate);
20266 auto insert_result = more_exports.insert(std::make_pair(name, cell));
20267 if (!insert_result.second) {
20268 auto it = insert_result.first;
20269 if (*it->second == *cell || it->second->IsUndefined(isolate)) {
20270 // We already recorded this mapping before, or the name is already
20271 // known to be ambiguous. In either case, there's nothing to do.
20272 } else {
20273 DCHECK(it->second->IsCell());
20274 // Different star exports provide different cells for this name, hence
20275 // mark the name as ambiguous.
20276 it->second = isolate->factory()->undefined_value();
20277 }
20278 }
20279 }
20280 }
20281
20282 // Copy [more_exports] into [exports].
20283 for (const auto& elem : more_exports) {
20284 if (elem.second->IsUndefined(isolate)) continue; // Ambiguous export.
20285 DCHECK(!elem.first->Equals(isolate->heap()->default_string()));
20286 DCHECK(elem.second->IsCell());
20287 exports = ObjectHashTable::Put(exports, elem.first, elem.second);
20288 }
20289 module->set_exports(*exports);
20290 }
20291
20292 } // anonymous namespace
20293
GetModuleNamespace(Handle<Module> module,int module_request)20294 Handle<JSModuleNamespace> Module::GetModuleNamespace(Handle<Module> module,
20295 int module_request) {
20296 Isolate* isolate = module->GetIsolate();
20297 Handle<Module> requested_module(
20298 Module::cast(module->requested_modules()->get(module_request)), isolate);
20299 return Module::GetModuleNamespace(requested_module);
20300 }
20301
GetModuleNamespace(Handle<Module> module)20302 Handle<JSModuleNamespace> Module::GetModuleNamespace(Handle<Module> module) {
20303 Isolate* isolate = module->GetIsolate();
20304
20305 Handle<HeapObject> object(module->module_namespace(), isolate);
20306 if (!object->IsUndefined(isolate)) {
20307 // Namespace object already exists.
20308 return Handle<JSModuleNamespace>::cast(object);
20309 }
20310
20311 // Create the namespace object (initially empty).
20312 Handle<JSModuleNamespace> ns = isolate->factory()->NewJSModuleNamespace();
20313 ns->set_module(*module);
20314 module->set_module_namespace(*ns);
20315
20316 // Collect the export names.
20317 Zone zone(isolate->allocator(), ZONE_NAME);
20318 UnorderedModuleSet visited(&zone);
20319 FetchStarExports(module, &zone, &visited);
20320 Handle<ObjectHashTable> exports(module->exports(), isolate);
20321 ZoneVector<Handle<String>> names(&zone);
20322 names.reserve(exports->NumberOfElements());
20323 for (int i = 0, n = exports->Capacity(); i < n; ++i) {
20324 Handle<Object> key(exports->KeyAt(i), isolate);
20325 if (!exports->IsKey(isolate, *key)) continue;
20326 DCHECK(exports->ValueAt(i)->IsCell());
20327 names.push_back(Handle<String>::cast(key));
20328 }
20329 DCHECK_EQ(static_cast<int>(names.size()), exports->NumberOfElements());
20330
20331 // Sort them alphabetically.
20332 struct {
20333 bool operator()(Handle<String> a, Handle<String> b) {
20334 return String::Compare(a, b) == ComparisonResult::kLessThan;
20335 }
20336 } StringLess;
20337 std::sort(names.begin(), names.end(), StringLess);
20338
20339 // Create the corresponding properties in the namespace object.
20340 PropertyAttributes attr = DONT_DELETE;
20341 for (const auto& name : names) {
20342 JSObject::SetAccessor(
20343 ns, Accessors::ModuleNamespaceEntryInfo(isolate, name, attr))
20344 .Check();
20345 }
20346 JSObject::PreventExtensions(ns, THROW_ON_ERROR).ToChecked();
20347
20348 return ns;
20349 }
20350
TryGetCachedPropertyName(Isolate * isolate,Handle<Object> getter)20351 MaybeHandle<Name> FunctionTemplateInfo::TryGetCachedPropertyName(
20352 Isolate* isolate, Handle<Object> getter) {
20353 if (getter->IsFunctionTemplateInfo()) {
20354 Handle<FunctionTemplateInfo> fti =
20355 Handle<FunctionTemplateInfo>::cast(getter);
20356 // Check if the accessor uses a cached property.
20357 if (!fti->cached_property_name()->IsTheHole(isolate)) {
20358 return handle(Name::cast(fti->cached_property_name()));
20359 }
20360 }
20361 return MaybeHandle<Name>();
20362 }
20363
20364 // static
ElementsKindForInstanceType(InstanceType type)20365 ElementsKind JSArrayIterator::ElementsKindForInstanceType(InstanceType type) {
20366 DCHECK_GE(type, FIRST_ARRAY_ITERATOR_TYPE);
20367 DCHECK_LE(type, LAST_ARRAY_ITERATOR_TYPE);
20368
20369 if (type <= LAST_ARRAY_KEY_ITERATOR_TYPE) {
20370 // Should be ignored for key iterators.
20371 return FAST_ELEMENTS;
20372 } else {
20373 ElementsKind kind;
20374 if (type < FIRST_ARRAY_VALUE_ITERATOR_TYPE) {
20375 // Convert `type` to a value iterator from an entries iterator
20376 type = static_cast<InstanceType>(type +
20377 (FIRST_ARRAY_VALUE_ITERATOR_TYPE -
20378 FIRST_ARRAY_KEY_VALUE_ITERATOR_TYPE));
20379 DCHECK_GE(type, FIRST_ARRAY_VALUE_ITERATOR_TYPE);
20380 DCHECK_LE(type, LAST_ARRAY_ITERATOR_TYPE);
20381 }
20382
20383 if (type <= JS_UINT8_CLAMPED_ARRAY_VALUE_ITERATOR_TYPE) {
20384 kind =
20385 static_cast<ElementsKind>(FIRST_FIXED_TYPED_ARRAY_ELEMENTS_KIND +
20386 (type - FIRST_ARRAY_VALUE_ITERATOR_TYPE));
20387 DCHECK_LE(kind, LAST_FIXED_TYPED_ARRAY_ELEMENTS_KIND);
20388 } else if (type < JS_GENERIC_ARRAY_VALUE_ITERATOR_TYPE) {
20389 kind = static_cast<ElementsKind>(
20390 FIRST_FAST_ELEMENTS_KIND +
20391 (type - JS_FAST_SMI_ARRAY_VALUE_ITERATOR_TYPE));
20392 DCHECK_LE(kind, LAST_FAST_ELEMENTS_KIND);
20393 } else {
20394 // For any slow element cases, the actual elements kind is not known.
20395 // Simply
20396 // return a slow elements kind in this case. Users of this function must
20397 // not
20398 // depend on this.
20399 return DICTIONARY_ELEMENTS;
20400 }
20401 DCHECK_LE(kind, LAST_ELEMENTS_KIND);
20402 return kind;
20403 }
20404 }
20405
20406 } // namespace internal
20407 } // namespace v8
20408