blob: d9d8213e24eaa72f985ed1ebceb589db3c3bbb57 [file] [log] [blame]
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001// Copyright 2015 the V8 project authors. All rights reserved.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
Steve Blocka7e24c12009-10-30 11:49:00 +00004
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00005#include "src/objects.h"
Emily Bernierd0a1eb72015-03-24 16:35:39 -04006
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00007#include <cmath>
8#include <iomanip>
9#include <sstream>
Steve Blocka7e24c12009-10-30 11:49:00 +000010
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011#include "src/accessors.h"
12#include "src/allocation-site-scopes.h"
13#include "src/api.h"
14#include "src/arguments.h"
15#include "src/base/bits.h"
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000016#include "src/base/utils/random-number-generator.h"
Ben Murdochb8a8cc12014-11-26 15:28:44 +000017#include "src/bootstrapper.h"
18#include "src/code-stubs.h"
19#include "src/codegen.h"
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000020#include "src/compilation-dependencies.h"
21#include "src/compiler.h"
Ben Murdochb8a8cc12014-11-26 15:28:44 +000022#include "src/date.h"
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000023#include "src/debug/debug.h"
Ben Murdochb8a8cc12014-11-26 15:28:44 +000024#include "src/deoptimizer.h"
25#include "src/elements.h"
26#include "src/execution.h"
Ben Murdochb8a8cc12014-11-26 15:28:44 +000027#include "src/field-index.h"
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000028#include "src/field-index-inl.h"
29#include "src/full-codegen/full-codegen.h"
Ben Murdochb8a8cc12014-11-26 15:28:44 +000030#include "src/ic/ic.h"
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000031#include "src/identity-map.h"
32#include "src/interpreter/bytecodes.h"
Ben Murdochb8a8cc12014-11-26 15:28:44 +000033#include "src/isolate-inl.h"
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000034#include "src/key-accumulator.h"
35#include "src/list.h"
Ben Murdochb8a8cc12014-11-26 15:28:44 +000036#include "src/log.h"
37#include "src/lookup.h"
38#include "src/macro-assembler.h"
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000039#include "src/messages.h"
Ben Murdochb8a8cc12014-11-26 15:28:44 +000040#include "src/objects-inl.h"
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000041#include "src/objects-body-descriptors-inl.h"
42#include "src/profiler/cpu-profiler.h"
43#include "src/property-descriptor.h"
Ben Murdochb8a8cc12014-11-26 15:28:44 +000044#include "src/prototype.h"
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000045#include "src/regexp/jsregexp.h"
Ben Murdochb8a8cc12014-11-26 15:28:44 +000046#include "src/safepoint-table.h"
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000047#include "src/string-builder.h"
Ben Murdochb8a8cc12014-11-26 15:28:44 +000048#include "src/string-search.h"
49#include "src/string-stream.h"
50#include "src/utils.h"
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000051#include "src/zone.h"
Steve Blocka7e24c12009-10-30 11:49:00 +000052
53#ifdef ENABLE_DISASSEMBLER
Ben Murdochb8a8cc12014-11-26 15:28:44 +000054#include "src/disasm.h"
55#include "src/disassembler.h"
Steve Blocka7e24c12009-10-30 11:49:00 +000056#endif
57
Steve Blocka7e24c12009-10-30 11:49:00 +000058namespace v8 {
59namespace internal {
60
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000061std::ostream& operator<<(std::ostream& os, InstanceType instance_type) {
62 switch (instance_type) {
63#define WRITE_TYPE(TYPE) \
64 case TYPE: \
65 return os << #TYPE;
66 INSTANCE_TYPE_LIST(WRITE_TYPE)
67#undef WRITE_TYPE
68 }
69 UNREACHABLE();
70 return os << "UNKNOWN"; // Keep the compiler happy.
71}
72
73
Ben Murdochb8a8cc12014-11-26 15:28:44 +000074Handle<HeapType> Object::OptimalType(Isolate* isolate,
75 Representation representation) {
76 if (representation.IsNone()) return HeapType::None(isolate);
77 if (FLAG_track_field_types) {
78 if (representation.IsHeapObject() && IsHeapObject()) {
79 // We can track only JavaScript objects with stable maps.
80 Handle<Map> map(HeapObject::cast(this)->map(), isolate);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000081 if (map->is_stable() && map->IsJSReceiverMap()) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000082 return HeapType::Class(map, isolate);
83 }
84 }
85 }
86 return HeapType::Any(isolate);
Ben Murdoch3ef787d2012-04-12 10:51:47 +010087}
88
Steve Blocka7e24c12009-10-30 11:49:00 +000089
Ben Murdochb8a8cc12014-11-26 15:28:44 +000090MaybeHandle<JSReceiver> Object::ToObject(Isolate* isolate,
91 Handle<Object> object,
92 Handle<Context> native_context) {
93 if (object->IsJSReceiver()) return Handle<JSReceiver>::cast(object);
94 Handle<JSFunction> constructor;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000095 if (object->IsSmi()) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000096 constructor = handle(native_context->number_function(), isolate);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000097 } else {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000098 int constructor_function_index =
99 Handle<HeapObject>::cast(object)->map()->GetConstructorFunctionIndex();
100 if (constructor_function_index == Map::kNoConstructorFunctionIndex) {
101 return MaybeHandle<JSReceiver>();
102 }
103 constructor = handle(
104 JSFunction::cast(native_context->get(constructor_function_index)),
105 isolate);
John Reck59135872010-11-02 12:39:01 -0700106 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000107 Handle<JSObject> result = isolate->factory()->NewJSObject(constructor);
108 Handle<JSValue>::cast(result)->set_value(*object);
Steve Blocka7e24c12009-10-30 11:49:00 +0000109 return result;
110}
111
112
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000113// static
114MaybeHandle<Name> Object::ToName(Isolate* isolate, Handle<Object> input) {
115 ASSIGN_RETURN_ON_EXCEPTION(
116 isolate, input, Object::ToPrimitive(input, ToPrimitiveHint::kString),
117 Name);
118 if (input->IsName()) return Handle<Name>::cast(input);
119 return ToString(isolate, input);
120}
121
122
123// static
124MaybeHandle<Object> Object::ToNumber(Handle<Object> input) {
125 while (true) {
126 if (input->IsNumber()) {
127 return input;
128 }
129 if (input->IsString()) {
130 return String::ToNumber(Handle<String>::cast(input));
131 }
132 if (input->IsOddball()) {
133 return Oddball::ToNumber(Handle<Oddball>::cast(input));
134 }
135 Isolate* const isolate = Handle<HeapObject>::cast(input)->GetIsolate();
136 if (input->IsSymbol()) {
137 THROW_NEW_ERROR(isolate, NewTypeError(MessageTemplate::kSymbolToNumber),
138 Object);
139 }
140 if (input->IsSimd128Value()) {
141 THROW_NEW_ERROR(isolate, NewTypeError(MessageTemplate::kSimdToNumber),
142 Object);
143 }
144 ASSIGN_RETURN_ON_EXCEPTION(
145 isolate, input, JSReceiver::ToPrimitive(Handle<JSReceiver>::cast(input),
146 ToPrimitiveHint::kNumber),
147 Object);
148 }
149}
150
151
152// static
153MaybeHandle<Object> Object::ToInteger(Isolate* isolate, Handle<Object> input) {
154 ASSIGN_RETURN_ON_EXCEPTION(isolate, input, ToNumber(input), Object);
155 return isolate->factory()->NewNumber(DoubleToInteger(input->Number()));
156}
157
158
159// static
160MaybeHandle<Object> Object::ToInt32(Isolate* isolate, Handle<Object> input) {
161 ASSIGN_RETURN_ON_EXCEPTION(isolate, input, ToNumber(input), Object);
162 return isolate->factory()->NewNumberFromInt(DoubleToInt32(input->Number()));
163}
164
165
166// static
167MaybeHandle<Object> Object::ToUint32(Isolate* isolate, Handle<Object> input) {
168 ASSIGN_RETURN_ON_EXCEPTION(isolate, input, ToNumber(input), Object);
169 return isolate->factory()->NewNumberFromUint(DoubleToUint32(input->Number()));
170}
171
172
173// static
174MaybeHandle<String> Object::ToString(Isolate* isolate, Handle<Object> input) {
175 while (true) {
176 if (input->IsString()) {
177 return Handle<String>::cast(input);
178 }
179 if (input->IsOddball()) {
180 return handle(Handle<Oddball>::cast(input)->to_string(), isolate);
181 }
182 if (input->IsNumber()) {
183 return isolate->factory()->NumberToString(input);
184 }
185 if (input->IsSymbol()) {
186 THROW_NEW_ERROR(isolate, NewTypeError(MessageTemplate::kSymbolToString),
187 String);
188 }
189 if (input->IsSimd128Value()) {
190 return Simd128Value::ToString(Handle<Simd128Value>::cast(input));
191 }
192 ASSIGN_RETURN_ON_EXCEPTION(
193 isolate, input, JSReceiver::ToPrimitive(Handle<JSReceiver>::cast(input),
194 ToPrimitiveHint::kString),
195 String);
196 }
197}
198
199
200// static
201MaybeHandle<Object> Object::ToLength(Isolate* isolate, Handle<Object> input) {
202 ASSIGN_RETURN_ON_EXCEPTION(isolate, input, ToNumber(input), Object);
203 double len = DoubleToInteger(input->Number());
204 if (len <= 0.0) {
205 len = 0.0;
206 } else if (len >= kMaxSafeInteger) {
207 len = kMaxSafeInteger;
208 }
209 return isolate->factory()->NewNumber(len);
210}
211
212
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000213bool Object::BooleanValue() {
214 if (IsBoolean()) return IsTrue();
215 if (IsSmi()) return Smi::cast(this)->value() != 0;
216 if (IsUndefined() || IsNull()) return false;
217 if (IsUndetectableObject()) return false; // Undetectable object is false.
218 if (IsString()) return String::cast(this)->length() != 0;
219 if (IsHeapNumber()) return HeapNumber::cast(this)->HeapNumberBooleanValue();
220 return true;
Steve Blocka7e24c12009-10-30 11:49:00 +0000221}
222
223
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000224namespace {
225
226// TODO(bmeurer): Maybe we should introduce a marker interface Number,
227// where we put all these methods at some point?
228ComparisonResult NumberCompare(double x, double y) {
229 if (std::isnan(x) || std::isnan(y)) {
230 return ComparisonResult::kUndefined;
231 } else if (x < y) {
232 return ComparisonResult::kLessThan;
233 } else if (x > y) {
234 return ComparisonResult::kGreaterThan;
235 } else {
236 return ComparisonResult::kEqual;
Steve Blocka7e24c12009-10-30 11:49:00 +0000237 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000238}
239
240
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000241bool NumberEquals(double x, double y) {
242 // Must check explicitly for NaN's on Windows, but -0 works fine.
243 if (std::isnan(x)) return false;
244 if (std::isnan(y)) return false;
245 return x == y;
246}
247
248
249bool NumberEquals(const Object* x, const Object* y) {
250 return NumberEquals(x->Number(), y->Number());
251}
252
253
254bool NumberEquals(Handle<Object> x, Handle<Object> y) {
255 return NumberEquals(*x, *y);
256}
257
258} // namespace
259
260
261// static
262Maybe<ComparisonResult> Object::Compare(Handle<Object> x, Handle<Object> y,
263 Strength strength) {
264 if (!is_strong(strength)) {
265 // ES6 section 7.2.11 Abstract Relational Comparison step 3 and 4.
266 if (!Object::ToPrimitive(x, ToPrimitiveHint::kNumber).ToHandle(&x) ||
267 !Object::ToPrimitive(y, ToPrimitiveHint::kNumber).ToHandle(&y)) {
268 return Nothing<ComparisonResult>();
269 }
270 }
271 if (x->IsString() && y->IsString()) {
272 // ES6 section 7.2.11 Abstract Relational Comparison step 5.
273 return Just(
274 String::Compare(Handle<String>::cast(x), Handle<String>::cast(y)));
275 }
276 // ES6 section 7.2.11 Abstract Relational Comparison step 6.
277 if (!is_strong(strength)) {
278 if (!Object::ToNumber(x).ToHandle(&x) ||
279 !Object::ToNumber(y).ToHandle(&y)) {
280 return Nothing<ComparisonResult>();
281 }
282 } else {
283 if (!x->IsNumber()) {
284 Isolate* const isolate = Handle<HeapObject>::cast(x)->GetIsolate();
285 isolate->Throw(*isolate->factory()->NewTypeError(
286 MessageTemplate::kStrongImplicitConversion));
287 return Nothing<ComparisonResult>();
288 } else if (!y->IsNumber()) {
289 Isolate* const isolate = Handle<HeapObject>::cast(y)->GetIsolate();
290 isolate->Throw(*isolate->factory()->NewTypeError(
291 MessageTemplate::kStrongImplicitConversion));
292 return Nothing<ComparisonResult>();
293 }
294 }
295 return Just(NumberCompare(x->Number(), y->Number()));
296}
297
298
299// static
300Maybe<bool> Object::Equals(Handle<Object> x, Handle<Object> y) {
301 while (true) {
302 if (x->IsNumber()) {
303 if (y->IsNumber()) {
304 return Just(NumberEquals(x, y));
305 } else if (y->IsBoolean()) {
306 return Just(NumberEquals(*x, Handle<Oddball>::cast(y)->to_number()));
307 } else if (y->IsString()) {
308 return Just(NumberEquals(x, String::ToNumber(Handle<String>::cast(y))));
309 } else if (y->IsJSReceiver() && !y->IsUndetectableObject()) {
310 if (!JSReceiver::ToPrimitive(Handle<JSReceiver>::cast(y))
311 .ToHandle(&y)) {
312 return Nothing<bool>();
313 }
314 } else {
315 return Just(false);
316 }
317 } else if (x->IsString()) {
318 if (y->IsString()) {
319 return Just(
320 String::Equals(Handle<String>::cast(x), Handle<String>::cast(y)));
321 } else if (y->IsNumber()) {
322 x = String::ToNumber(Handle<String>::cast(x));
323 return Just(NumberEquals(x, y));
324 } else if (y->IsBoolean()) {
325 x = String::ToNumber(Handle<String>::cast(x));
326 return Just(NumberEquals(*x, Handle<Oddball>::cast(y)->to_number()));
327 } else if (y->IsJSReceiver() && !y->IsUndetectableObject()) {
328 if (!JSReceiver::ToPrimitive(Handle<JSReceiver>::cast(y))
329 .ToHandle(&y)) {
330 return Nothing<bool>();
331 }
332 } else {
333 return Just(false);
334 }
335 } else if (x->IsBoolean()) {
336 if (y->IsOddball()) {
337 return Just(x.is_identical_to(y));
338 } else if (y->IsNumber()) {
339 return Just(NumberEquals(Handle<Oddball>::cast(x)->to_number(), *y));
340 } else if (y->IsString()) {
341 y = String::ToNumber(Handle<String>::cast(y));
342 return Just(NumberEquals(Handle<Oddball>::cast(x)->to_number(), *y));
343 } else if (y->IsJSReceiver() && !y->IsUndetectableObject()) {
344 if (!JSReceiver::ToPrimitive(Handle<JSReceiver>::cast(y))
345 .ToHandle(&y)) {
346 return Nothing<bool>();
347 }
348 x = Oddball::ToNumber(Handle<Oddball>::cast(x));
349 } else {
350 return Just(false);
351 }
352 } else if (x->IsSymbol()) {
353 if (y->IsSymbol()) {
354 return Just(x.is_identical_to(y));
355 } else if (y->IsJSReceiver() && !y->IsUndetectableObject()) {
356 if (!JSReceiver::ToPrimitive(Handle<JSReceiver>::cast(y))
357 .ToHandle(&y)) {
358 return Nothing<bool>();
359 }
360 } else {
361 return Just(false);
362 }
363 } else if (x->IsSimd128Value()) {
364 if (y->IsSimd128Value()) {
365 return Just(Simd128Value::Equals(Handle<Simd128Value>::cast(x),
366 Handle<Simd128Value>::cast(y)));
367 } else if (y->IsJSReceiver() && !y->IsUndetectableObject()) {
368 if (!JSReceiver::ToPrimitive(Handle<JSReceiver>::cast(y))
369 .ToHandle(&y)) {
370 return Nothing<bool>();
371 }
372 } else {
373 return Just(false);
374 }
375 } else if (x->IsJSReceiver() && !x->IsUndetectableObject()) {
376 if (y->IsJSReceiver()) {
377 return Just(x.is_identical_to(y));
378 } else if (y->IsNull() || y->IsUndefined()) {
379 return Just(false);
380 } else if (y->IsBoolean()) {
381 y = Oddball::ToNumber(Handle<Oddball>::cast(y));
382 } else if (!JSReceiver::ToPrimitive(Handle<JSReceiver>::cast(x))
383 .ToHandle(&x)) {
384 return Nothing<bool>();
385 }
386 } else {
387 return Just(
388 (x->IsNull() || x->IsUndefined() || x->IsUndetectableObject()) &&
389 (y->IsNull() || y->IsUndefined() || y->IsUndetectableObject()));
390 }
391 }
392}
393
394
395bool Object::StrictEquals(Object* that) {
396 if (this->IsNumber()) {
397 if (!that->IsNumber()) return false;
398 return NumberEquals(this, that);
399 } else if (this->IsString()) {
400 if (!that->IsString()) return false;
401 return String::cast(this)->Equals(String::cast(that));
402 } else if (this->IsSimd128Value()) {
403 if (!that->IsSimd128Value()) return false;
404 return Simd128Value::cast(this)->Equals(Simd128Value::cast(that));
405 }
406 return this == that;
407}
408
409
410// static
411Handle<String> Object::TypeOf(Isolate* isolate, Handle<Object> object) {
412 if (object->IsNumber()) return isolate->factory()->number_string();
413 if (object->IsUndefined() || object->IsUndetectableObject()) {
414 return isolate->factory()->undefined_string();
415 }
416 if (object->IsBoolean()) return isolate->factory()->boolean_string();
417 if (object->IsString()) return isolate->factory()->string_string();
418 if (object->IsSymbol()) return isolate->factory()->symbol_string();
419 if (object->IsString()) return isolate->factory()->string_string();
420#define SIMD128_TYPE(TYPE, Type, type, lane_count, lane_type) \
421 if (object->Is##Type()) return isolate->factory()->type##_string();
422 SIMD128_TYPES(SIMD128_TYPE)
423#undef SIMD128_TYPE
424 if (object->IsCallable()) return isolate->factory()->function_string();
425 return isolate->factory()->object_string();
426}
427
428
429// static
430MaybeHandle<Object> Object::Multiply(Isolate* isolate, Handle<Object> lhs,
431 Handle<Object> rhs, Strength strength) {
432 if (!lhs->IsNumber() || !rhs->IsNumber()) {
433 if (is_strong(strength)) {
434 THROW_NEW_ERROR(isolate,
435 NewTypeError(MessageTemplate::kStrongImplicitConversion),
436 Object);
437 }
438 ASSIGN_RETURN_ON_EXCEPTION(isolate, lhs, Object::ToNumber(lhs), Object);
439 ASSIGN_RETURN_ON_EXCEPTION(isolate, rhs, Object::ToNumber(rhs), Object);
440 }
441 return isolate->factory()->NewNumber(lhs->Number() * rhs->Number());
442}
443
444
445// static
446MaybeHandle<Object> Object::Divide(Isolate* isolate, Handle<Object> lhs,
447 Handle<Object> rhs, Strength strength) {
448 if (!lhs->IsNumber() || !rhs->IsNumber()) {
449 if (is_strong(strength)) {
450 THROW_NEW_ERROR(isolate,
451 NewTypeError(MessageTemplate::kStrongImplicitConversion),
452 Object);
453 }
454 ASSIGN_RETURN_ON_EXCEPTION(isolate, lhs, Object::ToNumber(lhs), Object);
455 ASSIGN_RETURN_ON_EXCEPTION(isolate, rhs, Object::ToNumber(rhs), Object);
456 }
457 return isolate->factory()->NewNumber(lhs->Number() / rhs->Number());
458}
459
460
461// static
462MaybeHandle<Object> Object::Modulus(Isolate* isolate, Handle<Object> lhs,
463 Handle<Object> rhs, Strength strength) {
464 if (!lhs->IsNumber() || !rhs->IsNumber()) {
465 if (is_strong(strength)) {
466 THROW_NEW_ERROR(isolate,
467 NewTypeError(MessageTemplate::kStrongImplicitConversion),
468 Object);
469 }
470 ASSIGN_RETURN_ON_EXCEPTION(isolate, lhs, Object::ToNumber(lhs), Object);
471 ASSIGN_RETURN_ON_EXCEPTION(isolate, rhs, Object::ToNumber(rhs), Object);
472 }
473 return isolate->factory()->NewNumber(modulo(lhs->Number(), rhs->Number()));
474}
475
476
477// static
478MaybeHandle<Object> Object::Add(Isolate* isolate, Handle<Object> lhs,
479 Handle<Object> rhs, Strength strength) {
480 if (lhs->IsNumber() && rhs->IsNumber()) {
481 return isolate->factory()->NewNumber(lhs->Number() + rhs->Number());
482 } else if (lhs->IsString() && rhs->IsString()) {
483 return isolate->factory()->NewConsString(Handle<String>::cast(lhs),
484 Handle<String>::cast(rhs));
485 } else if (is_strong(strength)) {
486 THROW_NEW_ERROR(isolate,
487 NewTypeError(MessageTemplate::kStrongImplicitConversion),
488 Object);
489 }
490 ASSIGN_RETURN_ON_EXCEPTION(isolate, lhs, Object::ToPrimitive(lhs), Object);
491 ASSIGN_RETURN_ON_EXCEPTION(isolate, rhs, Object::ToPrimitive(rhs), Object);
492 if (lhs->IsString() || rhs->IsString()) {
493 ASSIGN_RETURN_ON_EXCEPTION(isolate, rhs, Object::ToString(isolate, rhs),
494 Object);
495 ASSIGN_RETURN_ON_EXCEPTION(isolate, lhs, Object::ToString(isolate, lhs),
496 Object);
497 return isolate->factory()->NewConsString(Handle<String>::cast(lhs),
498 Handle<String>::cast(rhs));
499 }
500 ASSIGN_RETURN_ON_EXCEPTION(isolate, rhs, Object::ToNumber(rhs), Object);
501 ASSIGN_RETURN_ON_EXCEPTION(isolate, lhs, Object::ToNumber(lhs), Object);
502 return isolate->factory()->NewNumber(lhs->Number() + rhs->Number());
503}
504
505
506// static
507MaybeHandle<Object> Object::Subtract(Isolate* isolate, Handle<Object> lhs,
508 Handle<Object> rhs, Strength strength) {
509 if (!lhs->IsNumber() || !rhs->IsNumber()) {
510 if (is_strong(strength)) {
511 THROW_NEW_ERROR(isolate,
512 NewTypeError(MessageTemplate::kStrongImplicitConversion),
513 Object);
514 }
515 ASSIGN_RETURN_ON_EXCEPTION(isolate, lhs, Object::ToNumber(lhs), Object);
516 ASSIGN_RETURN_ON_EXCEPTION(isolate, rhs, Object::ToNumber(rhs), Object);
517 }
518 return isolate->factory()->NewNumber(lhs->Number() - rhs->Number());
519}
520
521
522// static
523MaybeHandle<Object> Object::ShiftLeft(Isolate* isolate, Handle<Object> lhs,
524 Handle<Object> rhs, Strength strength) {
525 if (!lhs->IsNumber() || !rhs->IsNumber()) {
526 if (is_strong(strength)) {
527 THROW_NEW_ERROR(isolate,
528 NewTypeError(MessageTemplate::kStrongImplicitConversion),
529 Object);
530 }
531 ASSIGN_RETURN_ON_EXCEPTION(isolate, lhs, Object::ToNumber(lhs), Object);
532 ASSIGN_RETURN_ON_EXCEPTION(isolate, rhs, Object::ToNumber(rhs), Object);
533 }
534 return isolate->factory()->NewNumberFromInt(NumberToInt32(*lhs)
535 << (NumberToUint32(*rhs) & 0x1F));
536}
537
538
539// static
540MaybeHandle<Object> Object::ShiftRight(Isolate* isolate, Handle<Object> lhs,
541 Handle<Object> rhs, Strength strength) {
542 if (!lhs->IsNumber() || !rhs->IsNumber()) {
543 if (is_strong(strength)) {
544 THROW_NEW_ERROR(isolate,
545 NewTypeError(MessageTemplate::kStrongImplicitConversion),
546 Object);
547 }
548 ASSIGN_RETURN_ON_EXCEPTION(isolate, lhs, Object::ToNumber(lhs), Object);
549 ASSIGN_RETURN_ON_EXCEPTION(isolate, rhs, Object::ToNumber(rhs), Object);
550 }
551 return isolate->factory()->NewNumberFromInt(NumberToInt32(*lhs) >>
552 (NumberToUint32(*rhs) & 0x1F));
553}
554
555
556// static
557MaybeHandle<Object> Object::ShiftRightLogical(Isolate* isolate,
558 Handle<Object> lhs,
559 Handle<Object> rhs,
560 Strength strength) {
561 if (!lhs->IsNumber() || !rhs->IsNumber()) {
562 if (is_strong(strength)) {
563 THROW_NEW_ERROR(isolate,
564 NewTypeError(MessageTemplate::kStrongImplicitConversion),
565 Object);
566 }
567 ASSIGN_RETURN_ON_EXCEPTION(isolate, lhs, Object::ToNumber(lhs), Object);
568 ASSIGN_RETURN_ON_EXCEPTION(isolate, rhs, Object::ToNumber(rhs), Object);
569 }
570 return isolate->factory()->NewNumberFromUint(NumberToUint32(*lhs) >>
571 (NumberToUint32(*rhs) & 0x1F));
572}
573
574
575// static
576MaybeHandle<Object> Object::BitwiseAnd(Isolate* isolate, Handle<Object> lhs,
577 Handle<Object> rhs, Strength strength) {
578 if (!lhs->IsNumber() || !rhs->IsNumber()) {
579 if (is_strong(strength)) {
580 THROW_NEW_ERROR(isolate,
581 NewTypeError(MessageTemplate::kStrongImplicitConversion),
582 Object);
583 }
584 ASSIGN_RETURN_ON_EXCEPTION(isolate, lhs, Object::ToNumber(lhs), Object);
585 ASSIGN_RETURN_ON_EXCEPTION(isolate, rhs, Object::ToNumber(rhs), Object);
586 }
587 return isolate->factory()->NewNumberFromInt(NumberToInt32(*lhs) &
588 NumberToInt32(*rhs));
589}
590
591
592// static
593MaybeHandle<Object> Object::BitwiseOr(Isolate* isolate, Handle<Object> lhs,
594 Handle<Object> rhs, Strength strength) {
595 if (!lhs->IsNumber() || !rhs->IsNumber()) {
596 if (is_strong(strength)) {
597 THROW_NEW_ERROR(isolate,
598 NewTypeError(MessageTemplate::kStrongImplicitConversion),
599 Object);
600 }
601 ASSIGN_RETURN_ON_EXCEPTION(isolate, lhs, Object::ToNumber(lhs), Object);
602 ASSIGN_RETURN_ON_EXCEPTION(isolate, rhs, Object::ToNumber(rhs), Object);
603 }
604 return isolate->factory()->NewNumberFromInt(NumberToInt32(*lhs) |
605 NumberToInt32(*rhs));
606}
607
608
609// static
610MaybeHandle<Object> Object::BitwiseXor(Isolate* isolate, Handle<Object> lhs,
611 Handle<Object> rhs, Strength strength) {
612 if (!lhs->IsNumber() || !rhs->IsNumber()) {
613 if (is_strong(strength)) {
614 THROW_NEW_ERROR(isolate,
615 NewTypeError(MessageTemplate::kStrongImplicitConversion),
616 Object);
617 }
618 ASSIGN_RETURN_ON_EXCEPTION(isolate, lhs, Object::ToNumber(lhs), Object);
619 ASSIGN_RETURN_ON_EXCEPTION(isolate, rhs, Object::ToNumber(rhs), Object);
620 }
621 return isolate->factory()->NewNumberFromInt(NumberToInt32(*lhs) ^
622 NumberToInt32(*rhs));
623}
624
625
626Maybe<bool> Object::IsArray(Handle<Object> object) {
627 if (object->IsJSArray()) return Just(true);
628 if (object->IsJSProxy()) {
629 Handle<JSProxy> proxy = Handle<JSProxy>::cast(object);
630 Isolate* isolate = proxy->GetIsolate();
631 if (proxy->IsRevoked()) {
632 isolate->Throw(*isolate->factory()->NewTypeError(
633 MessageTemplate::kProxyRevoked,
634 isolate->factory()->NewStringFromAsciiChecked("IsArray")));
635 return Nothing<bool>();
636 }
637 return Object::IsArray(handle(proxy->target(), isolate));
638 }
639 return Just(false);
640}
641
642
643bool Object::IsPromise(Handle<Object> object) {
644 if (!object->IsJSObject()) return false;
645 auto js_object = Handle<JSObject>::cast(object);
646 // Promises can't have access checks.
647 if (js_object->map()->is_access_check_needed()) return false;
648 auto isolate = js_object->GetIsolate();
649 // TODO(dcarney): this should just be read from the symbol registry so as not
650 // to be context dependent.
651 auto key = isolate->factory()->promise_status_symbol();
652 // Shouldn't be possible to throw here.
653 return JSObject::HasRealNamedProperty(js_object, key).FromJust();
654}
655
656
657// static
658MaybeHandle<Object> Object::GetMethod(Handle<JSReceiver> receiver,
659 Handle<Name> name) {
660 Handle<Object> func;
661 Isolate* isolate = receiver->GetIsolate();
662 ASSIGN_RETURN_ON_EXCEPTION(isolate, func,
663 JSReceiver::GetProperty(receiver, name), Object);
664 if (func->IsNull() || func->IsUndefined()) {
665 return isolate->factory()->undefined_value();
666 }
667 if (!func->IsCallable()) {
668 THROW_NEW_ERROR(isolate, NewTypeError(MessageTemplate::kPropertyNotFunction,
669 func, name, receiver),
670 Object);
671 }
672 return func;
673}
674
675
676// static
677MaybeHandle<FixedArray> Object::CreateListFromArrayLike(
678 Isolate* isolate, Handle<Object> object, ElementTypes element_types) {
679 // 1. ReturnIfAbrupt(object).
680 // 2. (default elementTypes -- not applicable.)
681 // 3. If Type(obj) is not Object, throw a TypeError exception.
682 if (!object->IsJSReceiver()) {
683 THROW_NEW_ERROR(isolate,
684 NewTypeError(MessageTemplate::kCalledOnNonObject,
685 isolate->factory()->NewStringFromAsciiChecked(
686 "CreateListFromArrayLike")),
687 FixedArray);
688 }
689 // 4. Let len be ? ToLength(? Get(obj, "length")).
690 Handle<Object> raw_length_obj;
691 ASSIGN_RETURN_ON_EXCEPTION(
692 isolate, raw_length_obj,
693 JSReceiver::GetProperty(object, isolate->factory()->length_string()),
694 FixedArray);
695 Handle<Object> raw_length_number;
696 ASSIGN_RETURN_ON_EXCEPTION(isolate, raw_length_number,
697 Object::ToLength(isolate, raw_length_obj),
698 FixedArray);
699 uint32_t len;
700 if (!raw_length_number->ToUint32(&len) ||
701 len > static_cast<uint32_t>(FixedArray::kMaxLength)) {
702 THROW_NEW_ERROR(isolate,
703 NewRangeError(MessageTemplate::kInvalidArrayLength),
704 FixedArray);
705 }
706 // 5. Let list be an empty List.
707 Handle<FixedArray> list = isolate->factory()->NewFixedArray(len);
708 // 6. Let index be 0.
709 // 7. Repeat while index < len:
710 for (uint32_t index = 0; index < len; ++index) {
711 // 7a. Let indexName be ToString(index).
712 // 7b. Let next be ? Get(obj, indexName).
713 Handle<Object> next;
714 ASSIGN_RETURN_ON_EXCEPTION(
715 isolate, next, Object::GetElement(isolate, object, index), FixedArray);
716 switch (element_types) {
717 case ElementTypes::kAll:
718 // Nothing to do.
719 break;
720 case ElementTypes::kStringAndSymbol: {
721 // 7c. If Type(next) is not an element of elementTypes, throw a
722 // TypeError exception.
723 if (!next->IsName()) {
724 THROW_NEW_ERROR(isolate,
725 NewTypeError(MessageTemplate::kNotPropertyName, next),
726 FixedArray);
727 }
728 // 7d. Append next as the last element of list.
729 // Internalize on the fly so we can use pointer identity later.
730 next = isolate->factory()->InternalizeName(Handle<Name>::cast(next));
731 break;
732 }
733 }
734 list->set(index, *next);
735 // 7e. Set index to index + 1. (See loop header.)
736 }
737 // 8. Return list.
738 return list;
739}
740
741
742// static
743Maybe<bool> JSReceiver::HasProperty(LookupIterator* it) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000744 for (; it->IsFound(); it->Next()) {
745 switch (it->state()) {
746 case LookupIterator::NOT_FOUND:
747 case LookupIterator::TRANSITION:
748 UNREACHABLE();
749 case LookupIterator::JSPROXY:
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000750 // Call the "has" trap on proxies.
751 return JSProxy::HasProperty(it->isolate(), it->GetHolder<JSProxy>(),
752 it->GetName());
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000753 case LookupIterator::INTERCEPTOR: {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000754 Maybe<PropertyAttributes> result =
755 JSObject::GetPropertyAttributesWithInterceptor(it);
756 if (!result.IsJust()) return Nothing<bool>();
757 if (result.FromJust() != ABSENT) return Just(true);
758 break;
759 }
760 case LookupIterator::ACCESS_CHECK: {
761 if (it->HasAccess()) break;
762 Maybe<PropertyAttributes> result =
763 JSObject::GetPropertyAttributesWithFailedAccessCheck(it);
764 if (!result.IsJust()) return Nothing<bool>();
765 return Just(result.FromJust() != ABSENT);
766 }
767 case LookupIterator::INTEGER_INDEXED_EXOTIC:
768 // TypedArray out-of-bounds access.
769 return Just(false);
770 case LookupIterator::ACCESSOR:
771 case LookupIterator::DATA:
772 return Just(true);
773 }
774 }
775 return Just(false);
776}
777
778
779// static
780MaybeHandle<Object> Object::GetProperty(LookupIterator* it,
781 LanguageMode language_mode) {
782 for (; it->IsFound(); it->Next()) {
783 switch (it->state()) {
784 case LookupIterator::NOT_FOUND:
785 case LookupIterator::TRANSITION:
786 UNREACHABLE();
787 case LookupIterator::JSPROXY:
788 return JSProxy::GetProperty(it->isolate(), it->GetHolder<JSProxy>(),
789 it->GetName(), it->GetReceiver(),
790 language_mode);
791 case LookupIterator::INTERCEPTOR: {
792 bool done;
793 Handle<Object> result;
794 ASSIGN_RETURN_ON_EXCEPTION(
795 it->isolate(), result,
796 JSObject::GetPropertyWithInterceptor(it, &done), Object);
797 if (done) return result;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000798 break;
799 }
800 case LookupIterator::ACCESS_CHECK:
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000801 if (it->HasAccess()) break;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000802 return JSObject::GetPropertyWithFailedAccessCheck(it);
803 case LookupIterator::ACCESSOR:
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000804 return GetPropertyWithAccessor(it, language_mode);
805 case LookupIterator::INTEGER_INDEXED_EXOTIC:
806 return ReadAbsentProperty(it, language_mode);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000807 case LookupIterator::DATA:
808 return it->GetDataValue();
Ben Murdoch8b112d22011-06-08 16:22:53 +0100809 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000810 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000811 return ReadAbsentProperty(it, language_mode);
Steve Blocka7e24c12009-10-30 11:49:00 +0000812}
813
814
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000815#define STACK_CHECK(result_value) \
816 do { \
817 StackLimitCheck stack_check(isolate); \
818 if (stack_check.HasOverflowed()) { \
819 isolate->Throw(*isolate->factory()->NewRangeError( \
820 MessageTemplate::kStackOverflow)); \
821 return result_value; \
822 } \
823 } while (false)
824
825
826// static
827MaybeHandle<Object> JSProxy::GetProperty(Isolate* isolate,
828 Handle<JSProxy> proxy,
829 Handle<Name> name,
830 Handle<Object> receiver,
831 LanguageMode language_mode) {
832 if (receiver->IsJSGlobalObject()) {
833 THROW_NEW_ERROR(
834 isolate,
835 NewTypeError(MessageTemplate::kReadGlobalReferenceThroughProxy, name),
836 Object);
837 }
838
839 DCHECK(!name->IsPrivate());
840 STACK_CHECK(MaybeHandle<Object>());
841 Handle<Name> trap_name = isolate->factory()->get_string();
842 // 1. Assert: IsPropertyKey(P) is true.
843 // 2. Let handler be the value of the [[ProxyHandler]] internal slot of O.
844 Handle<Object> handler(proxy->handler(), isolate);
845 // 3. If handler is null, throw a TypeError exception.
846 // 4. Assert: Type(handler) is Object.
847 if (proxy->IsRevoked()) {
848 THROW_NEW_ERROR(isolate,
849 NewTypeError(MessageTemplate::kProxyRevoked, trap_name),
850 Object);
851 }
852 // 5. Let target be the value of the [[ProxyTarget]] internal slot of O.
853 Handle<JSReceiver> target(proxy->target(), isolate);
854 // 6. Let trap be ? GetMethod(handler, "get").
855 Handle<Object> trap;
856 ASSIGN_RETURN_ON_EXCEPTION(
857 isolate, trap,
858 Object::GetMethod(Handle<JSReceiver>::cast(handler), trap_name), Object);
859 // 7. If trap is undefined, then
860 if (trap->IsUndefined()) {
861 // 7.a Return target.[[Get]](P, Receiver).
862 LookupIterator it =
863 LookupIterator::PropertyOrElement(isolate, receiver, name, target);
864 return Object::GetProperty(&it, language_mode);
865 }
866 // 8. Let trapResult be ? Call(trap, handler, «target, P, Receiver»).
867 Handle<Object> trap_result;
868 Handle<Object> args[] = {target, name, receiver};
869 ASSIGN_RETURN_ON_EXCEPTION(
870 isolate, trap_result,
871 Execution::Call(isolate, trap, handler, arraysize(args), args), Object);
872 // 9. Let targetDesc be ? target.[[GetOwnProperty]](P).
873 PropertyDescriptor target_desc;
874 Maybe<bool> target_found =
875 JSReceiver::GetOwnPropertyDescriptor(isolate, target, name, &target_desc);
876 MAYBE_RETURN_NULL(target_found);
877 // 10. If targetDesc is not undefined, then
878 if (target_found.FromJust()) {
879 // 10.a. If IsDataDescriptor(targetDesc) and targetDesc.[[Configurable]] is
880 // false and targetDesc.[[Writable]] is false, then
881 // 10.a.i. If SameValue(trapResult, targetDesc.[[Value]]) is false,
882 // throw a TypeError exception.
883 bool inconsistent = PropertyDescriptor::IsDataDescriptor(&target_desc) &&
884 !target_desc.configurable() &&
885 !target_desc.writable() &&
886 !trap_result->SameValue(*target_desc.value());
887 if (inconsistent) {
888 THROW_NEW_ERROR(
889 isolate, NewTypeError(MessageTemplate::kProxyGetNonConfigurableData,
890 name, target_desc.value(), trap_result),
891 Object);
892 }
893 // 10.b. If IsAccessorDescriptor(targetDesc) and targetDesc.[[Configurable]]
894 // is false and targetDesc.[[Get]] is undefined, then
895 // 10.b.i. If trapResult is not undefined, throw a TypeError exception.
896 inconsistent = PropertyDescriptor::IsAccessorDescriptor(&target_desc) &&
897 !target_desc.configurable() &&
898 target_desc.get()->IsUndefined() &&
899 !trap_result->IsUndefined();
900 if (inconsistent) {
901 THROW_NEW_ERROR(
902 isolate,
903 NewTypeError(MessageTemplate::kProxyGetNonConfigurableAccessor, name,
904 trap_result),
905 Object);
906 }
907 }
908 // 11. Return trap_result
909 return trap_result;
910}
911
912
913Handle<Object> JSReceiver::GetDataProperty(Handle<JSReceiver> object,
914 Handle<Name> name) {
915 LookupIterator it(object, name,
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000916 LookupIterator::PROTOTYPE_CHAIN_SKIP_INTERCEPTOR);
917 return GetDataProperty(&it);
Steve Blocka7e24c12009-10-30 11:49:00 +0000918}
919
920
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000921Handle<Object> JSReceiver::GetDataProperty(LookupIterator* it) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000922 for (; it->IsFound(); it->Next()) {
923 switch (it->state()) {
924 case LookupIterator::INTERCEPTOR:
925 case LookupIterator::NOT_FOUND:
926 case LookupIterator::TRANSITION:
927 UNREACHABLE();
928 case LookupIterator::ACCESS_CHECK:
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000929 // Support calling this method without an active context, but refuse
930 // access to access-checked objects in that case.
931 if (it->isolate()->context() != nullptr && it->HasAccess()) continue;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000932 // Fall through.
933 case LookupIterator::JSPROXY:
934 it->NotFound();
935 return it->isolate()->factory()->undefined_value();
936 case LookupIterator::ACCESSOR:
937 // TODO(verwaest): For now this doesn't call into
938 // ExecutableAccessorInfo, since clients don't need it. Update once
939 // relevant.
940 it->NotFound();
941 return it->isolate()->factory()->undefined_value();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000942 case LookupIterator::INTEGER_INDEXED_EXOTIC:
943 return it->isolate()->factory()->undefined_value();
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000944 case LookupIterator::DATA:
945 return it->GetDataValue();
946 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000947 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000948 return it->isolate()->factory()->undefined_value();
949}
Steve Blocka7e24c12009-10-30 11:49:00 +0000950
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000951
952bool Object::ToInt32(int32_t* value) {
953 if (IsSmi()) {
954 *value = Smi::cast(this)->value();
955 return true;
956 }
957 if (IsHeapNumber()) {
958 double num = HeapNumber::cast(this)->value();
959 if (FastI2D(FastD2I(num)) == num) {
960 *value = FastD2I(num);
961 return true;
962 }
963 }
964 return false;
965}
966
967
968bool Object::ToUint32(uint32_t* value) {
969 if (IsSmi()) {
970 int num = Smi::cast(this)->value();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000971 if (num < 0) return false;
972 *value = static_cast<uint32_t>(num);
973 return true;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000974 }
975 if (IsHeapNumber()) {
976 double num = HeapNumber::cast(this)->value();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000977 if (num < 0) return false;
978 uint32_t uint_value = FastD2UI(num);
979 if (FastUI2D(uint_value) == num) {
980 *value = uint_value;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000981 return true;
982 }
983 }
984 return false;
985}
986
987
988bool FunctionTemplateInfo::IsTemplateFor(Object* object) {
989 if (!object->IsHeapObject()) return false;
990 return IsTemplateFor(HeapObject::cast(object)->map());
991}
992
993
994bool FunctionTemplateInfo::IsTemplateFor(Map* map) {
995 // There is a constraint on the object; check.
996 if (!map->IsJSObjectMap()) return false;
997 // Fetch the constructor function of the object.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000998 Object* cons_obj = map->GetConstructor();
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000999 if (!cons_obj->IsJSFunction()) return false;
1000 JSFunction* fun = JSFunction::cast(cons_obj);
1001 // Iterate through the chain of inheriting function templates to
1002 // see if the required one occurs.
1003 for (Object* type = fun->shared()->function_data();
1004 type->IsFunctionTemplateInfo();
1005 type = FunctionTemplateInfo::cast(type)->parent_template()) {
1006 if (type == this) return true;
1007 }
1008 // Didn't find the required type in the inheritance chain.
1009 return false;
1010}
1011
1012
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001013// TODO(dcarney): CallOptimization duplicates this logic, merge.
1014Object* FunctionTemplateInfo::GetCompatibleReceiver(Isolate* isolate,
1015 Object* receiver) {
1016 // API calls are only supported with JSObject receivers.
1017 if (!receiver->IsJSObject()) return isolate->heap()->null_value();
1018 Object* recv_type = this->signature();
1019 // No signature, return holder.
1020 if (recv_type->IsUndefined()) return receiver;
1021 FunctionTemplateInfo* signature = FunctionTemplateInfo::cast(recv_type);
1022 // Check the receiver.
1023 for (PrototypeIterator iter(isolate, receiver,
1024 PrototypeIterator::START_AT_RECEIVER);
1025 !iter.IsAtEnd(PrototypeIterator::END_AT_NON_HIDDEN); iter.Advance()) {
1026 if (signature->IsTemplateFor(iter.GetCurrent())) return iter.GetCurrent();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001027 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001028 return isolate->heap()->null_value();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001029}
1030
1031
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001032// static
1033MaybeHandle<JSObject> JSObject::New(Handle<JSFunction> constructor,
1034 Handle<JSReceiver> new_target,
1035 Handle<AllocationSite> site) {
1036 // If called through new, new.target can be:
1037 // - a subclass of constructor,
1038 // - a proxy wrapper around constructor, or
1039 // - the constructor itself.
1040 // If called through Reflect.construct, it's guaranteed to be a constructor.
1041 Isolate* const isolate = constructor->GetIsolate();
1042 DCHECK(constructor->IsConstructor());
1043 DCHECK(new_target->IsConstructor());
1044 DCHECK(!constructor->has_initial_map() ||
1045 constructor->initial_map()->instance_type() != JS_FUNCTION_TYPE);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001046
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001047 Handle<Map> initial_map;
1048 ASSIGN_RETURN_ON_EXCEPTION(
1049 isolate, initial_map,
1050 JSFunction::GetDerivedMap(isolate, constructor, new_target), JSObject);
1051 Handle<JSObject> result =
1052 isolate->factory()->NewJSObjectFromMap(initial_map, NOT_TENURED, site);
1053 isolate->counters()->constructed_objects()->Increment();
1054 isolate->counters()->constructed_objects_runtime()->Increment();
1055 return result;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001056}
1057
1058
1059Handle<FixedArray> JSObject::EnsureWritableFastElements(
1060 Handle<JSObject> object) {
1061 DCHECK(object->HasFastSmiOrObjectElements());
1062 Isolate* isolate = object->GetIsolate();
1063 Handle<FixedArray> elems(FixedArray::cast(object->elements()), isolate);
1064 if (elems->map() != isolate->heap()->fixed_cow_array_map()) return elems;
1065 Handle<FixedArray> writable_elems = isolate->factory()->CopyFixedArrayWithMap(
1066 elems, isolate->factory()->fixed_array_map());
1067 object->set_elements(*writable_elems);
1068 isolate->counters()->cow_arrays_converted()->Increment();
1069 return writable_elems;
1070}
1071
1072
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001073// ES6 9.5.1
1074// static
1075MaybeHandle<Object> JSProxy::GetPrototype(Handle<JSProxy> proxy) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001076 Isolate* isolate = proxy->GetIsolate();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001077 Handle<String> trap_name = isolate->factory()->getPrototypeOf_string();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001078
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001079 STACK_CHECK(MaybeHandle<Object>());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001080
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001081 // 1. Let handler be the value of the [[ProxyHandler]] internal slot.
1082 // 2. If handler is null, throw a TypeError exception.
1083 // 3. Assert: Type(handler) is Object.
1084 // 4. Let target be the value of the [[ProxyTarget]] internal slot.
1085 if (proxy->IsRevoked()) {
1086 THROW_NEW_ERROR(isolate,
1087 NewTypeError(MessageTemplate::kProxyRevoked, trap_name),
1088 Object);
1089 }
1090 Handle<JSReceiver> target(proxy->target(), isolate);
1091 Handle<JSReceiver> handler(JSReceiver::cast(proxy->handler()), isolate);
1092
1093 // 5. Let trap be ? GetMethod(handler, "getPrototypeOf").
1094 Handle<Object> trap;
1095 ASSIGN_RETURN_ON_EXCEPTION(isolate, trap, GetMethod(handler, trap_name),
1096 Object);
1097 // 6. If trap is undefined, then return target.[[GetPrototypeOf]]().
1098 if (trap->IsUndefined()) {
1099 return Object::GetPrototype(isolate, target);
1100 }
1101 // 7. Let handlerProto be ? Call(trap, handler, «target»).
1102 Handle<Object> argv[] = {target};
1103 Handle<Object> handler_proto;
1104 ASSIGN_RETURN_ON_EXCEPTION(
1105 isolate, handler_proto,
1106 Execution::Call(isolate, trap, handler, arraysize(argv), argv), Object);
1107 // 8. If Type(handlerProto) is neither Object nor Null, throw a TypeError.
1108 if (!(handler_proto->IsJSReceiver() || handler_proto->IsNull())) {
1109 THROW_NEW_ERROR(isolate,
1110 NewTypeError(MessageTemplate::kProxyGetPrototypeOfInvalid),
1111 Object);
1112 }
1113 // 9. Let extensibleTarget be ? IsExtensible(target).
1114 Maybe<bool> is_extensible = JSReceiver::IsExtensible(target);
1115 MAYBE_RETURN_NULL(is_extensible);
1116 // 10. If extensibleTarget is true, return handlerProto.
1117 if (is_extensible.FromJust()) return handler_proto;
1118 // 11. Let targetProto be ? target.[[GetPrototypeOf]]().
1119 Handle<Object> target_proto;
1120 ASSIGN_RETURN_ON_EXCEPTION(isolate, target_proto,
1121 Object::GetPrototype(isolate, target), Object);
1122 // 12. If SameValue(handlerProto, targetProto) is false, throw a TypeError.
1123 if (!handler_proto->SameValue(*target_proto)) {
1124 THROW_NEW_ERROR(
1125 isolate,
1126 NewTypeError(MessageTemplate::kProxyGetPrototypeOfNonExtensible),
1127 Object);
1128 }
1129 // 13. Return handlerProto.
1130 return handler_proto;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001131}
1132
1133
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001134MaybeHandle<Object> Object::GetPropertyWithAccessor(
1135 LookupIterator* it, LanguageMode language_mode) {
1136 Isolate* isolate = it->isolate();
1137 Handle<Object> structure = it->GetAccessors();
1138 Handle<Object> receiver = it->GetReceiver();
1139
1140 // We should never get here to initialize a const with the hole value since a
1141 // const declaration would conflict with the getter.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001142 DCHECK(!structure->IsForeign());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001143
1144 // API style callbacks.
Steve Blocka7e24c12009-10-30 11:49:00 +00001145 if (structure->IsAccessorInfo()) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001146 Handle<JSObject> holder = it->GetHolder<JSObject>();
1147 Handle<Name> name = it->GetName();
1148 Handle<ExecutableAccessorInfo> info =
1149 Handle<ExecutableAccessorInfo>::cast(structure);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001150 if (!info->IsCompatibleReceiver(*receiver)) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001151 THROW_NEW_ERROR(isolate,
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001152 NewTypeError(MessageTemplate::kIncompatibleMethodReceiver,
1153 name, receiver),
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001154 Object);
Steve Blocka7e24c12009-10-30 11:49:00 +00001155 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001156
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001157 v8::AccessorNameGetterCallback call_fun =
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001158 v8::ToCData<v8::AccessorNameGetterCallback>(info->getter());
1159 if (call_fun == nullptr) return isolate->factory()->undefined_value();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001160
1161 LOG(isolate, ApiNamedPropertyAccess("load", *holder, *name));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001162 PropertyCallbackArguments args(isolate, info->data(), *receiver, *holder);
1163 v8::Local<v8::Value> result = args.Call(call_fun, v8::Utils::ToLocal(name));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001164 RETURN_EXCEPTION_IF_SCHEDULED_EXCEPTION(isolate, Object);
Steve Block44f0eee2011-05-26 01:26:41 +01001165 if (result.IsEmpty()) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001166 return ReadAbsentProperty(isolate, receiver, name, language_mode);
Steve Block44f0eee2011-05-26 01:26:41 +01001167 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001168 Handle<Object> return_value = v8::Utils::OpenHandle(*result);
1169 return_value->VerifyApiCallResultType();
1170 // Rebox handle before return.
1171 return handle(*return_value, isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00001172 }
1173
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001174 // Regular accessor.
1175 Handle<Object> getter(AccessorPair::cast(*structure)->getter(), isolate);
1176 if (getter->IsCallable()) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001177 // TODO(rossberg): nicer would be to cast to some JSCallable here...
1178 return Object::GetPropertyWithDefinedGetter(
1179 receiver, Handle<JSReceiver>::cast(getter));
1180 }
1181 // Getter is not a function.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001182 return ReadAbsentProperty(isolate, receiver, it->GetName(), language_mode);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001183}
1184
1185
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001186bool AccessorInfo::IsCompatibleReceiverMap(Isolate* isolate,
1187 Handle<AccessorInfo> info,
1188 Handle<Map> map) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001189 if (!info->HasExpectedReceiverType()) return true;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001190 if (!map->IsJSObjectMap()) return false;
1191 return FunctionTemplateInfo::cast(info->expected_receiver_type())
1192 ->IsTemplateFor(*map);
1193}
1194
1195
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001196Maybe<bool> Object::SetPropertyWithAccessor(LookupIterator* it,
1197 Handle<Object> value,
1198 ShouldThrow should_throw) {
1199 Isolate* isolate = it->isolate();
1200 Handle<Object> structure = it->GetAccessors();
1201 Handle<Object> receiver = it->GetReceiver();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001202
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001203 // We should never get here to initialize a const with the hole value since a
1204 // const declaration would conflict with the setter.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001205 DCHECK(!structure->IsForeign());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001206
1207 // API style callbacks.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001208 if (structure->IsExecutableAccessorInfo()) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001209 Handle<JSObject> holder = it->GetHolder<JSObject>();
1210 Handle<Name> name = it->GetName();
1211 Handle<ExecutableAccessorInfo> info =
1212 Handle<ExecutableAccessorInfo>::cast(structure);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001213 if (!info->IsCompatibleReceiver(*receiver)) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001214 isolate->Throw(*isolate->factory()->NewTypeError(
1215 MessageTemplate::kIncompatibleMethodReceiver, name, receiver));
1216 return Nothing<bool>();
Steve Blocka7e24c12009-10-30 11:49:00 +00001217 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001218
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001219 v8::AccessorNameSetterCallback call_fun =
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001220 v8::ToCData<v8::AccessorNameSetterCallback>(info->setter());
1221 if (call_fun == nullptr) return Just(true);
1222 // TODO(verwaest): Shouldn't this case be unreachable (at least in the
1223 // long run?) Should we have ExecutableAccessorPairs with missing setter
1224 // that are "writable"? If they aren't writable, shouldn't we have bailed
1225 // out already earlier?
1226
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001227 LOG(isolate, ApiNamedPropertyAccess("store", *holder, *name));
1228 PropertyCallbackArguments args(isolate, info->data(), *receiver, *holder);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001229 args.Call(call_fun, v8::Utils::ToLocal(name), v8::Utils::ToLocal(value));
1230 RETURN_VALUE_IF_SCHEDULED_EXCEPTION(isolate, Nothing<bool>());
1231 return Just(true);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001232 }
1233
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001234 // Regular accessor.
1235 Handle<Object> setter(AccessorPair::cast(*structure)->setter(), isolate);
1236 if (setter->IsCallable()) {
1237 // TODO(rossberg): nicer would be to cast to some JSCallable here...
1238 return SetPropertyWithDefinedSetter(
1239 receiver, Handle<JSReceiver>::cast(setter), value, should_throw);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001240 }
1241
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001242 RETURN_FAILURE(isolate, should_throw,
1243 NewTypeError(MessageTemplate::kNoSetterInCallback,
1244 it->GetName(), it->GetHolder<JSObject>()));
Steve Blocka7e24c12009-10-30 11:49:00 +00001245}
1246
1247
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001248MaybeHandle<Object> Object::GetPropertyWithDefinedGetter(
1249 Handle<Object> receiver,
1250 Handle<JSReceiver> getter) {
1251 Isolate* isolate = getter->GetIsolate();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001252
1253 // Platforms with simulators like arm/arm64 expose a funny issue. If the
1254 // simulator has a separate JS stack pointer from the C++ stack pointer, it
1255 // can miss C++ stack overflows in the stack guard at the start of JavaScript
1256 // functions. It would be very expensive to check the C++ stack pointer at
1257 // that location. The best solution seems to be to break the impasse by
1258 // adding checks at possible recursion points. What's more, we don't put
1259 // this stack check behind the USE_SIMULATOR define in order to keep
1260 // behavior the same between hardware and simulators.
1261 StackLimitCheck check(isolate);
1262 if (check.JsHasOverflowed()) {
1263 isolate->StackOverflow();
1264 return MaybeHandle<Object>();
Steve Blocka7e24c12009-10-30 11:49:00 +00001265 }
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001266
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001267 return Execution::Call(isolate, getter, receiver, 0, NULL);
Steve Blocka7e24c12009-10-30 11:49:00 +00001268}
1269
1270
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001271Maybe<bool> Object::SetPropertyWithDefinedSetter(Handle<Object> receiver,
1272 Handle<JSReceiver> setter,
1273 Handle<Object> value,
1274 ShouldThrow should_throw) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001275 Isolate* isolate = setter->GetIsolate();
1276
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001277 Handle<Object> argv[] = { value };
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001278 RETURN_ON_EXCEPTION_VALUE(isolate, Execution::Call(isolate, setter, receiver,
1279 arraysize(argv), argv),
1280 Nothing<bool>());
1281 return Just(true);
Steve Blocka7e24c12009-10-30 11:49:00 +00001282}
1283
1284
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001285// static
1286bool Object::IsErrorObject(Isolate* isolate, Handle<Object> object) {
1287 if (!object->IsJSObject()) return false;
1288 // Use stack_trace_symbol as proxy for [[ErrorData]].
1289 Handle<Name> symbol = isolate->factory()->stack_trace_symbol();
1290 Maybe<bool> has_stack_trace =
1291 JSReceiver::HasOwnProperty(Handle<JSReceiver>::cast(object), symbol);
1292 DCHECK(!has_stack_trace.IsNothing());
1293 return has_stack_trace.FromJust();
1294}
1295
1296
1297// static
1298bool JSObject::AllCanRead(LookupIterator* it) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001299 // Skip current iteration, it's in state ACCESS_CHECK or INTERCEPTOR, both of
1300 // which have already been checked.
1301 DCHECK(it->state() == LookupIterator::ACCESS_CHECK ||
1302 it->state() == LookupIterator::INTERCEPTOR);
1303 for (it->Next(); it->IsFound(); it->Next()) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001304 if (it->state() == LookupIterator::ACCESSOR) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001305 auto accessors = it->GetAccessors();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001306 if (accessors->IsAccessorInfo()) {
1307 if (AccessorInfo::cast(*accessors)->all_can_read()) return true;
1308 }
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001309 } else if (it->state() == LookupIterator::INTERCEPTOR) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001310 if (it->GetInterceptor()->all_can_read()) return true;
1311 } else if (it->state() == LookupIterator::JSPROXY) {
1312 // Stop lookupiterating. And no, AllCanNotRead.
1313 return false;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001314 }
1315 }
1316 return false;
1317}
1318
1319
1320MaybeHandle<Object> JSObject::GetPropertyWithFailedAccessCheck(
1321 LookupIterator* it) {
1322 Handle<JSObject> checked = it->GetHolder<JSObject>();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001323 while (AllCanRead(it)) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001324 if (it->state() == LookupIterator::ACCESSOR) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001325 return GetPropertyWithAccessor(it, SLOPPY);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001326 }
1327 DCHECK_EQ(LookupIterator::INTERCEPTOR, it->state());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001328 bool done;
1329 Handle<Object> result;
1330 ASSIGN_RETURN_ON_EXCEPTION(it->isolate(), result,
1331 GetPropertyWithInterceptor(it, &done), Object);
1332 if (done) return result;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001333 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001334
1335 // Cross-Origin [[Get]] of Well-Known Symbols does not throw, and returns
1336 // undefined.
1337 Handle<Name> name = it->GetName();
1338 if (name->IsSymbol() && Symbol::cast(*name)->is_well_known_symbol()) {
1339 return it->factory()->undefined_value();
1340 }
1341
1342 it->isolate()->ReportFailedAccessCheck(checked);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001343 RETURN_EXCEPTION_IF_SCHEDULED_EXCEPTION(it->isolate(), Object);
1344 return it->factory()->undefined_value();
1345}
1346
1347
1348Maybe<PropertyAttributes> JSObject::GetPropertyAttributesWithFailedAccessCheck(
1349 LookupIterator* it) {
1350 Handle<JSObject> checked = it->GetHolder<JSObject>();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001351 while (AllCanRead(it)) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001352 if (it->state() == LookupIterator::ACCESSOR) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001353 return Just(it->property_details().attributes());
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001354 }
1355 DCHECK_EQ(LookupIterator::INTERCEPTOR, it->state());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001356 auto result = GetPropertyAttributesWithInterceptor(it);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001357 if (it->isolate()->has_scheduled_exception()) break;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001358 if (result.IsJust() && result.FromJust() != ABSENT) return result;
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001359 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001360 it->isolate()->ReportFailedAccessCheck(checked);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001361 RETURN_VALUE_IF_SCHEDULED_EXCEPTION(it->isolate(),
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001362 Nothing<PropertyAttributes>());
1363 return Just(ABSENT);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001364}
1365
1366
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001367// static
1368bool JSObject::AllCanWrite(LookupIterator* it) {
1369 for (; it->IsFound() && it->state() != LookupIterator::JSPROXY; it->Next()) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001370 if (it->state() == LookupIterator::ACCESSOR) {
1371 Handle<Object> accessors = it->GetAccessors();
1372 if (accessors->IsAccessorInfo()) {
1373 if (AccessorInfo::cast(*accessors)->all_can_write()) return true;
1374 }
1375 }
1376 }
1377 return false;
1378}
1379
1380
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001381Maybe<bool> JSObject::SetPropertyWithFailedAccessCheck(
1382 LookupIterator* it, Handle<Object> value, ShouldThrow should_throw) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001383 Handle<JSObject> checked = it->GetHolder<JSObject>();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001384 if (AllCanWrite(it)) {
1385 return SetPropertyWithAccessor(it, value, should_throw);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001386 }
1387
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001388 it->isolate()->ReportFailedAccessCheck(checked);
1389 RETURN_VALUE_IF_SCHEDULED_EXCEPTION(it->isolate(), Nothing<bool>());
1390 return Just(true);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001391}
1392
1393
1394void JSObject::SetNormalizedProperty(Handle<JSObject> object,
1395 Handle<Name> name,
1396 Handle<Object> value,
1397 PropertyDetails details) {
1398 DCHECK(!object->HasFastProperties());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001399 if (!name->IsUniqueName()) {
1400 name = object->GetIsolate()->factory()->InternalizeString(
1401 Handle<String>::cast(name));
1402 }
1403
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001404 if (object->IsJSGlobalObject()) {
1405 Handle<GlobalDictionary> property_dictionary(object->global_dictionary());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001406
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001407 int entry = property_dictionary->FindEntry(name);
1408 if (entry == GlobalDictionary::kNotFound) {
1409 auto cell = object->GetIsolate()->factory()->NewPropertyCell();
1410 cell->set_value(*value);
1411 auto cell_type = value->IsUndefined() ? PropertyCellType::kUndefined
1412 : PropertyCellType::kConstant;
1413 details = details.set_cell_type(cell_type);
1414 value = cell;
1415 property_dictionary =
1416 GlobalDictionary::Add(property_dictionary, name, value, details);
1417 object->set_properties(*property_dictionary);
Steve Blocka7e24c12009-10-30 11:49:00 +00001418 } else {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001419 PropertyCell::UpdateCell(property_dictionary, entry, value, details);
1420 }
1421 } else {
1422 Handle<NameDictionary> property_dictionary(object->property_dictionary());
1423
1424 int entry = property_dictionary->FindEntry(name);
1425 if (entry == NameDictionary::kNotFound) {
1426 property_dictionary =
1427 NameDictionary::Add(property_dictionary, name, value, details);
1428 object->set_properties(*property_dictionary);
1429 } else {
1430 PropertyDetails original_details = property_dictionary->DetailsAt(entry);
1431 int enumeration_index = original_details.dictionary_index();
1432 DCHECK(enumeration_index > 0);
1433 details = details.set_index(enumeration_index);
1434 property_dictionary->SetEntry(entry, name, value, details);
Steve Blocka7e24c12009-10-30 11:49:00 +00001435 }
1436 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001437}
1438
1439
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001440Maybe<bool> Object::HasInPrototypeChain(Isolate* isolate, Handle<Object> object,
1441 Handle<Object> proto) {
1442 PrototypeIterator iter(isolate, object, PrototypeIterator::START_AT_RECEIVER);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001443 while (true) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001444 if (!iter.AdvanceFollowingProxies()) return Nothing<bool>();
1445 if (iter.IsAtEnd()) return Just(false);
1446 if (iter.IsAtEnd(proto)) return Just(true);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001447 }
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001448}
1449
1450
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001451Map* Object::GetRootMap(Isolate* isolate) {
1452 DisallowHeapAllocation no_alloc;
Ben Murdoch8b112d22011-06-08 16:22:53 +01001453 if (IsSmi()) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001454 Context* native_context = isolate->context()->native_context();
1455 return native_context->number_function()->initial_map();
Ben Murdoch8b112d22011-06-08 16:22:53 +01001456 }
1457
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001458 // The object is either a number, a string, a symbol, a boolean, a SIMD value,
Ben Murdoch257744e2011-11-30 15:57:28 +00001459 // a real JS object, or a Harmony proxy.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001460 HeapObject* heap_object = HeapObject::cast(this);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001461 if (heap_object->IsJSReceiver()) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001462 return heap_object->map();
Ben Murdoch8b112d22011-06-08 16:22:53 +01001463 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001464 int constructor_function_index =
1465 heap_object->map()->GetConstructorFunctionIndex();
1466 if (constructor_function_index != Map::kNoConstructorFunctionIndex) {
1467 Context* native_context = isolate->context()->native_context();
1468 JSFunction* constructor_function =
1469 JSFunction::cast(native_context->get(constructor_function_index));
1470 return constructor_function->initial_map();
Steve Blocka7e24c12009-10-30 11:49:00 +00001471 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001472 return isolate->heap()->null_value()->map();
Steve Blocka7e24c12009-10-30 11:49:00 +00001473}
1474
1475
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001476Object* Object::GetHash() {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001477 Object* hash = GetSimpleHash();
1478 if (hash->IsSmi()) return hash;
1479
1480 DCHECK(IsJSReceiver());
1481 return JSReceiver::cast(this)->GetIdentityHash();
1482}
1483
1484
1485Object* Object::GetSimpleHash() {
1486 // The object is either a Smi, a HeapNumber, a name, an odd-ball,
1487 // a SIMD value type, a real JS object, or a Harmony proxy.
1488 if (IsSmi()) {
1489 uint32_t hash = ComputeIntegerHash(Smi::cast(this)->value(), kZeroHashSeed);
1490 return Smi::FromInt(hash & Smi::kMaxValue);
1491 }
1492 if (IsHeapNumber()) {
1493 double num = HeapNumber::cast(this)->value();
1494 if (std::isnan(num)) return Smi::FromInt(Smi::kMaxValue);
1495 if (i::IsMinusZero(num)) num = 0;
1496 if (IsSmiDouble(num)) {
1497 return Smi::FromInt(FastD2I(num))->GetHash();
1498 }
1499 uint32_t hash = ComputeLongHash(double_to_uint64(num));
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001500 return Smi::FromInt(hash & Smi::kMaxValue);
1501 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001502 if (IsName()) {
1503 uint32_t hash = Name::cast(this)->Hash();
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001504 return Smi::FromInt(hash);
1505 }
1506 if (IsOddball()) {
1507 uint32_t hash = Oddball::cast(this)->to_string()->Hash();
1508 return Smi::FromInt(hash);
1509 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001510 if (IsSimd128Value()) {
1511 uint32_t hash = Simd128Value::cast(this)->Hash();
1512 return Smi::FromInt(hash & Smi::kMaxValue);
1513 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001514 DCHECK(IsJSReceiver());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001515 JSReceiver* receiver = JSReceiver::cast(this);
1516 return receiver->GetHeap()->undefined_value();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001517}
1518
1519
1520Handle<Smi> Object::GetOrCreateHash(Isolate* isolate, Handle<Object> object) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001521 Handle<Object> hash(object->GetSimpleHash(), isolate);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001522 if (hash->IsSmi()) return Handle<Smi>::cast(hash);
1523
1524 DCHECK(object->IsJSReceiver());
1525 return JSReceiver::GetOrCreateIdentityHash(Handle<JSReceiver>::cast(object));
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001526}
1527
1528
1529bool Object::SameValue(Object* other) {
1530 if (other == this) return true;
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001531
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001532 // The object is either a number, a name, an odd-ball,
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001533 // a real JS object, or a Harmony proxy.
1534 if (IsNumber() && other->IsNumber()) {
1535 double this_value = Number();
1536 double other_value = other->Number();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001537 // SameValue(NaN, NaN) is true.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001538 if (this_value != other_value) {
1539 return std::isnan(this_value) && std::isnan(other_value);
1540 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001541 // SameValue(0.0, -0.0) is false.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001542 return (std::signbit(this_value) == std::signbit(other_value));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001543 }
1544 if (IsString() && other->IsString()) {
1545 return String::cast(this)->Equals(String::cast(other));
1546 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001547 if (IsSimd128Value() && other->IsSimd128Value()) {
1548 if (IsFloat32x4() && other->IsFloat32x4()) {
1549 Float32x4* a = Float32x4::cast(this);
1550 Float32x4* b = Float32x4::cast(other);
1551 for (int i = 0; i < 4; i++) {
1552 float x = a->get_lane(i);
1553 float y = b->get_lane(i);
1554 // Implements the ES5 SameValue operation for floating point types.
1555 // http://www.ecma-international.org/ecma-262/6.0/#sec-samevalue
1556 if (x != y && !(std::isnan(x) && std::isnan(y))) return false;
1557 if (std::signbit(x) != std::signbit(y)) return false;
1558 }
1559 return true;
1560 } else {
1561 Simd128Value* a = Simd128Value::cast(this);
1562 Simd128Value* b = Simd128Value::cast(other);
1563 return a->map()->instance_type() == b->map()->instance_type() &&
1564 a->BitwiseEquals(b);
1565 }
1566 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001567 return false;
1568}
1569
1570
1571bool Object::SameValueZero(Object* other) {
1572 if (other == this) return true;
1573
1574 // The object is either a number, a name, an odd-ball,
1575 // a real JS object, or a Harmony proxy.
1576 if (IsNumber() && other->IsNumber()) {
1577 double this_value = Number();
1578 double other_value = other->Number();
1579 // +0 == -0 is true
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001580 return this_value == other_value ||
1581 (std::isnan(this_value) && std::isnan(other_value));
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001582 }
1583 if (IsString() && other->IsString()) {
1584 return String::cast(this)->Equals(String::cast(other));
1585 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001586 if (IsSimd128Value() && other->IsSimd128Value()) {
1587 if (IsFloat32x4() && other->IsFloat32x4()) {
1588 Float32x4* a = Float32x4::cast(this);
1589 Float32x4* b = Float32x4::cast(other);
1590 for (int i = 0; i < 4; i++) {
1591 float x = a->get_lane(i);
1592 float y = b->get_lane(i);
1593 // Implements the ES6 SameValueZero operation for floating point types.
1594 // http://www.ecma-international.org/ecma-262/6.0/#sec-samevaluezero
1595 if (x != y && !(std::isnan(x) && std::isnan(y))) return false;
1596 // SameValueZero doesn't distinguish between 0 and -0.
1597 }
1598 return true;
1599 } else {
1600 Simd128Value* a = Simd128Value::cast(this);
1601 Simd128Value* b = Simd128Value::cast(other);
1602 return a->map()->instance_type() == b->map()->instance_type() &&
1603 a->BitwiseEquals(b);
1604 }
1605 }
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001606 return false;
1607}
1608
1609
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001610MaybeHandle<Object> Object::ArraySpeciesConstructor(
1611 Isolate* isolate, Handle<Object> original_array) {
1612 Handle<Context> native_context = isolate->native_context();
1613 if (!FLAG_harmony_species) {
1614 return Handle<Object>(native_context->array_function(), isolate);
1615 }
1616 Handle<Object> constructor = isolate->factory()->undefined_value();
1617 Maybe<bool> is_array = Object::IsArray(original_array);
1618 MAYBE_RETURN_NULL(is_array);
1619 if (is_array.FromJust()) {
1620 ASSIGN_RETURN_ON_EXCEPTION(
1621 isolate, constructor,
1622 Object::GetProperty(original_array,
1623 isolate->factory()->constructor_string()),
1624 Object);
1625 if (constructor->IsConstructor()) {
1626 Handle<Context> constructor_context;
1627 ASSIGN_RETURN_ON_EXCEPTION(
1628 isolate, constructor_context,
1629 JSReceiver::GetFunctionRealm(Handle<JSReceiver>::cast(constructor)),
1630 Object);
1631 if (*constructor_context != *native_context &&
1632 *constructor == constructor_context->array_function()) {
1633 constructor = isolate->factory()->undefined_value();
1634 }
1635 }
1636 if (constructor->IsJSReceiver()) {
1637 ASSIGN_RETURN_ON_EXCEPTION(
1638 isolate, constructor,
1639 Object::GetProperty(constructor,
1640 isolate->factory()->species_symbol()),
1641 Object);
1642 if (constructor->IsNull()) {
1643 constructor = isolate->factory()->undefined_value();
1644 }
1645 }
1646 }
1647 if (constructor->IsUndefined()) {
1648 return Handle<Object>(native_context->array_function(), isolate);
1649 } else {
1650 if (!constructor->IsConstructor()) {
1651 THROW_NEW_ERROR(isolate,
1652 NewTypeError(MessageTemplate::kSpeciesNotConstructor),
1653 Object);
1654 }
1655 return constructor;
1656 }
1657}
1658
1659
Ben Murdochb0fe1622011-05-05 13:52:32 +01001660void Object::ShortPrint(FILE* out) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001661 OFStream os(out);
1662 os << Brief(this);
Steve Blocka7e24c12009-10-30 11:49:00 +00001663}
1664
1665
1666void Object::ShortPrint(StringStream* accumulator) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001667 std::ostringstream os;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001668 os << Brief(this);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001669 accumulator->Add(os.str().c_str());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001670}
1671
1672
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001673void Object::ShortPrint(std::ostream& os) { os << Brief(this); }
1674
1675
1676std::ostream& operator<<(std::ostream& os, const Brief& v) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001677 if (v.value->IsSmi()) {
1678 Smi::cast(v.value)->SmiPrint(os);
Steve Blocka7e24c12009-10-30 11:49:00 +00001679 } else {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001680 // TODO(svenpanne) Const-correct HeapObjectShortPrint!
1681 HeapObject* obj = const_cast<HeapObject*>(HeapObject::cast(v.value));
1682 obj->HeapObjectShortPrint(os);
Steve Blocka7e24c12009-10-30 11:49:00 +00001683 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001684 return os;
Steve Blocka7e24c12009-10-30 11:49:00 +00001685}
1686
1687
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001688void Smi::SmiPrint(std::ostream& os) const { // NOLINT
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001689 os << value();
Steve Blocka7e24c12009-10-30 11:49:00 +00001690}
1691
1692
Steve Blocka7e24c12009-10-30 11:49:00 +00001693// Should a word be prefixed by 'a' or 'an' in order to read naturally in
1694// English? Returns false for non-ASCII or words that don't start with
1695// a capital letter. The a/an rule follows pronunciation in English.
1696// We don't use the BBC's overcorrect "an historic occasion" though if
1697// you speak a dialect you may well say "an 'istoric occasion".
1698static bool AnWord(String* str) {
1699 if (str->length() == 0) return false; // A nothing.
1700 int c0 = str->Get(0);
1701 int c1 = str->length() > 1 ? str->Get(1) : 0;
1702 if (c0 == 'U') {
1703 if (c1 > 'Z') {
1704 return true; // An Umpire, but a UTF8String, a U.
1705 }
1706 } else if (c0 == 'A' || c0 == 'E' || c0 == 'I' || c0 == 'O') {
1707 return true; // An Ape, an ABCBook.
1708 } else if ((c1 == 0 || (c1 >= 'A' && c1 <= 'Z')) &&
1709 (c0 == 'F' || c0 == 'H' || c0 == 'M' || c0 == 'N' || c0 == 'R' ||
1710 c0 == 'S' || c0 == 'X')) {
1711 return true; // An MP3File, an M.
1712 }
1713 return false;
1714}
1715
1716
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001717Handle<String> String::SlowFlatten(Handle<ConsString> cons,
1718 PretenureFlag pretenure) {
1719 DCHECK(AllowHeapAllocation::IsAllowed());
1720 DCHECK(cons->second()->length() != 0);
1721 Isolate* isolate = cons->GetIsolate();
1722 int length = cons->length();
1723 PretenureFlag tenure = isolate->heap()->InNewSpace(*cons) ? pretenure
1724 : TENURED;
1725 Handle<SeqString> result;
1726 if (cons->IsOneByteRepresentation()) {
1727 Handle<SeqOneByteString> flat = isolate->factory()->NewRawOneByteString(
1728 length, tenure).ToHandleChecked();
1729 DisallowHeapAllocation no_gc;
1730 WriteToFlat(*cons, flat->GetChars(), 0, length);
1731 result = flat;
1732 } else {
1733 Handle<SeqTwoByteString> flat = isolate->factory()->NewRawTwoByteString(
1734 length, tenure).ToHandleChecked();
1735 DisallowHeapAllocation no_gc;
1736 WriteToFlat(*cons, flat->GetChars(), 0, length);
1737 result = flat;
Steve Blocka7e24c12009-10-30 11:49:00 +00001738 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001739 cons->set_first(*result);
1740 cons->set_second(isolate->heap()->empty_string());
1741 DCHECK(result->IsFlat());
1742 return result;
Steve Blocka7e24c12009-10-30 11:49:00 +00001743}
1744
1745
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001746
Steve Blocka7e24c12009-10-30 11:49:00 +00001747bool String::MakeExternal(v8::String::ExternalStringResource* resource) {
Steve Block8defd9f2010-07-08 12:39:36 +01001748 // Externalizing twice leaks the external resource, so it's
Kristian Monsen9dcf7e22010-06-28 14:14:28 +01001749 // prohibited by the API.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001750 DCHECK(!this->IsExternalString());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001751 DCHECK(!resource->IsCompressible());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001752#ifdef ENABLE_SLOW_DCHECKS
Steve Block3ce2e202009-11-05 08:53:23 +00001753 if (FLAG_enable_slow_asserts) {
Steve Blocka7e24c12009-10-30 11:49:00 +00001754 // Assert that the resource and the string are equivalent.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001755 DCHECK(static_cast<size_t>(this->length()) == resource->length());
Kristian Monsen25f61362010-05-21 11:50:48 +01001756 ScopedVector<uc16> smart_chars(this->length());
1757 String::WriteToFlat(this, smart_chars.start(), 0, this->length());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001758 DCHECK(memcmp(smart_chars.start(),
Steve Blocka7e24c12009-10-30 11:49:00 +00001759 resource->data(),
Kristian Monsen25f61362010-05-21 11:50:48 +01001760 resource->length() * sizeof(smart_chars[0])) == 0);
Steve Blocka7e24c12009-10-30 11:49:00 +00001761 }
1762#endif // DEBUG
Steve Blocka7e24c12009-10-30 11:49:00 +00001763 int size = this->Size(); // Byte size of the original string.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001764 // Abort if size does not allow in-place conversion.
1765 if (size < ExternalString::kShortSize) return false;
1766 Heap* heap = GetHeap();
1767 bool is_one_byte = this->IsOneByteRepresentation();
1768 bool is_internalized = this->IsInternalizedString();
Steve Blocka7e24c12009-10-30 11:49:00 +00001769
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001770 // Morph the string to an external string by replacing the map and
1771 // reinitializing the fields. This won't work if the space the existing
1772 // string occupies is too small for a regular external string.
1773 // Instead, we resort to a short external string instead, omitting
1774 // the field caching the address of the backing store. When we encounter
1775 // short external strings in generated code, we need to bailout to runtime.
1776 Map* new_map;
1777 if (size < ExternalString::kSize) {
1778 new_map = is_internalized
1779 ? (is_one_byte
1780 ? heap->short_external_internalized_string_with_one_byte_data_map()
1781 : heap->short_external_internalized_string_map())
1782 : (is_one_byte ? heap->short_external_string_with_one_byte_data_map()
1783 : heap->short_external_string_map());
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001784 } else {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001785 new_map = is_internalized
1786 ? (is_one_byte
1787 ? heap->external_internalized_string_with_one_byte_data_map()
1788 : heap->external_internalized_string_map())
1789 : (is_one_byte ? heap->external_string_with_one_byte_data_map()
1790 : heap->external_string_map());
Ben Murdoch85b71792012-04-11 18:30:58 +01001791 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001792
1793 // Byte size of the external String object.
1794 int new_size = this->SizeFromMap(new_map);
1795 heap->CreateFillerObjectAt(this->address() + new_size, size - new_size);
1796
1797 // We are storing the new map using release store after creating a filler for
1798 // the left-over space to avoid races with the sweeper thread.
1799 this->synchronized_set_map(new_map);
1800
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001801 ExternalTwoByteString* self = ExternalTwoByteString::cast(this);
1802 self->set_resource(resource);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001803 if (is_internalized) self->Hash(); // Force regeneration of the hash value.
Steve Blocka7e24c12009-10-30 11:49:00 +00001804
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001805 heap->AdjustLiveBytes(this, new_size - size, Heap::CONCURRENT_TO_SWEEPER);
Steve Blocka7e24c12009-10-30 11:49:00 +00001806 return true;
1807}
1808
1809
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001810bool String::MakeExternal(v8::String::ExternalOneByteStringResource* resource) {
1811 // Externalizing twice leaks the external resource, so it's
1812 // prohibited by the API.
1813 DCHECK(!this->IsExternalString());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001814 DCHECK(!resource->IsCompressible());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001815#ifdef ENABLE_SLOW_DCHECKS
Steve Block3ce2e202009-11-05 08:53:23 +00001816 if (FLAG_enable_slow_asserts) {
Steve Blocka7e24c12009-10-30 11:49:00 +00001817 // Assert that the resource and the string are equivalent.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001818 DCHECK(static_cast<size_t>(this->length()) == resource->length());
1819 if (this->IsTwoByteRepresentation()) {
1820 ScopedVector<uint16_t> smart_chars(this->length());
1821 String::WriteToFlat(this, smart_chars.start(), 0, this->length());
1822 DCHECK(String::IsOneByte(smart_chars.start(), this->length()));
1823 }
Kristian Monsen25f61362010-05-21 11:50:48 +01001824 ScopedVector<char> smart_chars(this->length());
1825 String::WriteToFlat(this, smart_chars.start(), 0, this->length());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001826 DCHECK(memcmp(smart_chars.start(),
Steve Blocka7e24c12009-10-30 11:49:00 +00001827 resource->data(),
Kristian Monsen25f61362010-05-21 11:50:48 +01001828 resource->length() * sizeof(smart_chars[0])) == 0);
Steve Blocka7e24c12009-10-30 11:49:00 +00001829 }
1830#endif // DEBUG
Steve Blocka7e24c12009-10-30 11:49:00 +00001831 int size = this->Size(); // Byte size of the original string.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001832 // Abort if size does not allow in-place conversion.
1833 if (size < ExternalString::kShortSize) return false;
1834 Heap* heap = GetHeap();
1835 bool is_internalized = this->IsInternalizedString();
Steve Blocka7e24c12009-10-30 11:49:00 +00001836
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001837 // Morph the string to an external string by replacing the map and
1838 // reinitializing the fields. This won't work if the space the existing
1839 // string occupies is too small for a regular external string.
1840 // Instead, we resort to a short external string instead, omitting
1841 // the field caching the address of the backing store. When we encounter
1842 // short external strings in generated code, we need to bailout to runtime.
1843 Map* new_map;
1844 if (size < ExternalString::kSize) {
1845 new_map = is_internalized
1846 ? heap->short_external_one_byte_internalized_string_map()
1847 : heap->short_external_one_byte_string_map();
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001848 } else {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001849 new_map = is_internalized
1850 ? heap->external_one_byte_internalized_string_map()
1851 : heap->external_one_byte_string_map();
Ben Murdoch85b71792012-04-11 18:30:58 +01001852 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001853
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001854 // Byte size of the external String object.
1855 int new_size = this->SizeFromMap(new_map);
Steve Block44f0eee2011-05-26 01:26:41 +01001856 heap->CreateFillerObjectAt(this->address() + new_size, size - new_size);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001857
1858 // We are storing the new map using release store after creating a filler for
1859 // the left-over space to avoid races with the sweeper thread.
1860 this->synchronized_set_map(new_map);
1861
1862 ExternalOneByteString* self = ExternalOneByteString::cast(this);
1863 self->set_resource(resource);
1864 if (is_internalized) self->Hash(); // Force regeneration of the hash value.
1865
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001866 heap->AdjustLiveBytes(this, new_size - size, Heap::CONCURRENT_TO_SWEEPER);
Steve Blocka7e24c12009-10-30 11:49:00 +00001867 return true;
1868}
1869
1870
1871void String::StringShortPrint(StringStream* accumulator) {
1872 int len = length();
Steve Blockd0582a62009-12-15 09:54:21 +00001873 if (len > kMaxShortPrintLength) {
Steve Blocka7e24c12009-10-30 11:49:00 +00001874 accumulator->Add("<Very long string[%u]>", len);
1875 return;
1876 }
1877
1878 if (!LooksValid()) {
1879 accumulator->Add("<Invalid String>");
1880 return;
1881 }
1882
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001883 StringCharacterStream stream(this);
Steve Blocka7e24c12009-10-30 11:49:00 +00001884
1885 bool truncated = false;
1886 if (len > kMaxShortPrintLength) {
1887 len = kMaxShortPrintLength;
1888 truncated = true;
1889 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001890 bool one_byte = true;
Steve Blocka7e24c12009-10-30 11:49:00 +00001891 for (int i = 0; i < len; i++) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001892 uint16_t c = stream.GetNext();
Steve Blocka7e24c12009-10-30 11:49:00 +00001893
1894 if (c < 32 || c >= 127) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001895 one_byte = false;
Steve Blocka7e24c12009-10-30 11:49:00 +00001896 }
1897 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001898 stream.Reset(this);
1899 if (one_byte) {
Steve Blocka7e24c12009-10-30 11:49:00 +00001900 accumulator->Add("<String[%u]: ", length());
1901 for (int i = 0; i < len; i++) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001902 accumulator->Put(static_cast<char>(stream.GetNext()));
Steve Blocka7e24c12009-10-30 11:49:00 +00001903 }
1904 accumulator->Put('>');
1905 } else {
1906 // Backslash indicates that the string contains control
1907 // characters and that backslashes are therefore escaped.
1908 accumulator->Add("<String[%u]\\: ", length());
1909 for (int i = 0; i < len; i++) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001910 uint16_t c = stream.GetNext();
Steve Blocka7e24c12009-10-30 11:49:00 +00001911 if (c == '\n') {
1912 accumulator->Add("\\n");
1913 } else if (c == '\r') {
1914 accumulator->Add("\\r");
1915 } else if (c == '\\') {
1916 accumulator->Add("\\\\");
1917 } else if (c < 32 || c > 126) {
1918 accumulator->Add("\\x%02x", c);
1919 } else {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001920 accumulator->Put(static_cast<char>(c));
Steve Blocka7e24c12009-10-30 11:49:00 +00001921 }
1922 }
1923 if (truncated) {
1924 accumulator->Put('.');
1925 accumulator->Put('.');
1926 accumulator->Put('.');
1927 }
1928 accumulator->Put('>');
1929 }
1930 return;
1931}
1932
1933
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001934void String::PrintUC16(std::ostream& os, int start, int end) { // NOLINT
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001935 if (end < 0) end = length();
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001936 StringCharacterStream stream(this, start);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001937 for (int i = start; i < end && stream.HasMore(); i++) {
1938 os << AsUC16(stream.GetNext());
1939 }
1940}
1941
1942
Steve Blocka7e24c12009-10-30 11:49:00 +00001943void JSObject::JSObjectShortPrint(StringStream* accumulator) {
1944 switch (map()->instance_type()) {
1945 case JS_ARRAY_TYPE: {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001946 double length = JSArray::cast(this)->length()->IsUndefined()
1947 ? 0
1948 : JSArray::cast(this)->length()->Number();
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001949 accumulator->Add("<JS Array[%u]>", static_cast<uint32_t>(length));
Steve Blocka7e24c12009-10-30 11:49:00 +00001950 break;
1951 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001952 case JS_BOUND_FUNCTION_TYPE: {
1953 JSBoundFunction* bound_function = JSBoundFunction::cast(this);
1954 Object* name = bound_function->name();
1955 accumulator->Add("<JS BoundFunction");
1956 if (name->IsString()) {
1957 String* str = String::cast(name);
1958 if (str->length() > 0) {
1959 accumulator->Add(" ");
1960 accumulator->Put(str);
1961 }
1962 }
1963 accumulator->Add(
1964 " (BoundTargetFunction %p)>",
1965 reinterpret_cast<void*>(bound_function->bound_target_function()));
1966 break;
1967 }
Ben Murdoch69a99ed2011-11-30 16:03:39 +00001968 case JS_WEAK_MAP_TYPE: {
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001969 accumulator->Add("<JS WeakMap>");
Ben Murdoch69a99ed2011-11-30 16:03:39 +00001970 break;
1971 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001972 case JS_WEAK_SET_TYPE: {
1973 accumulator->Add("<JS WeakSet>");
1974 break;
1975 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001976 case JS_REGEXP_TYPE: {
1977 accumulator->Add("<JS RegExp>");
1978 break;
1979 }
1980 case JS_FUNCTION_TYPE: {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001981 JSFunction* function = JSFunction::cast(this);
1982 Object* fun_name = function->shared()->DebugName();
Steve Blocka7e24c12009-10-30 11:49:00 +00001983 bool printed = false;
1984 if (fun_name->IsString()) {
1985 String* str = String::cast(fun_name);
1986 if (str->length() > 0) {
1987 accumulator->Add("<JS Function ");
1988 accumulator->Put(str);
Steve Blocka7e24c12009-10-30 11:49:00 +00001989 printed = true;
1990 }
1991 }
1992 if (!printed) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001993 accumulator->Add("<JS Function");
Steve Blocka7e24c12009-10-30 11:49:00 +00001994 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001995 accumulator->Add(" (SharedFunctionInfo %p)",
1996 reinterpret_cast<void*>(function->shared()));
1997 accumulator->Put('>');
1998 break;
1999 }
2000 case JS_GENERATOR_OBJECT_TYPE: {
2001 accumulator->Add("<JS Generator>");
2002 break;
2003 }
2004 case JS_MODULE_TYPE: {
2005 accumulator->Add("<JS Module>");
Steve Blocka7e24c12009-10-30 11:49:00 +00002006 break;
2007 }
2008 // All other JSObjects are rather similar to each other (JSObject,
2009 // JSGlobalProxy, JSGlobalObject, JSUndetectableObject, JSValue).
2010 default: {
Ben Murdoch8b112d22011-06-08 16:22:53 +01002011 Map* map_of_this = map();
Ben Murdoch3ef787d2012-04-12 10:51:47 +01002012 Heap* heap = GetHeap();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002013 Object* constructor = map_of_this->GetConstructor();
Steve Blocka7e24c12009-10-30 11:49:00 +00002014 bool printed = false;
2015 if (constructor->IsHeapObject() &&
Steve Block44f0eee2011-05-26 01:26:41 +01002016 !heap->Contains(HeapObject::cast(constructor))) {
Steve Blocka7e24c12009-10-30 11:49:00 +00002017 accumulator->Add("!!!INVALID CONSTRUCTOR!!!");
2018 } else {
2019 bool global_object = IsJSGlobalProxy();
2020 if (constructor->IsJSFunction()) {
Steve Block44f0eee2011-05-26 01:26:41 +01002021 if (!heap->Contains(JSFunction::cast(constructor)->shared())) {
Steve Blocka7e24c12009-10-30 11:49:00 +00002022 accumulator->Add("!!!INVALID SHARED ON CONSTRUCTOR!!!");
2023 } else {
2024 Object* constructor_name =
2025 JSFunction::cast(constructor)->shared()->name();
2026 if (constructor_name->IsString()) {
2027 String* str = String::cast(constructor_name);
2028 if (str->length() > 0) {
2029 bool vowel = AnWord(str);
2030 accumulator->Add("<%sa%s ",
2031 global_object ? "Global Object: " : "",
2032 vowel ? "n" : "");
2033 accumulator->Put(str);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002034 accumulator->Add(" with %smap %p",
2035 map_of_this->is_deprecated() ? "deprecated " : "",
2036 map_of_this);
Steve Blocka7e24c12009-10-30 11:49:00 +00002037 printed = true;
2038 }
2039 }
2040 }
2041 }
2042 if (!printed) {
2043 accumulator->Add("<JS %sObject", global_object ? "Global " : "");
2044 }
2045 }
2046 if (IsJSValue()) {
2047 accumulator->Add(" value = ");
2048 JSValue::cast(this)->value()->ShortPrint(accumulator);
2049 }
2050 accumulator->Put('>');
2051 break;
2052 }
2053 }
2054}
2055
2056
Ben Murdoch3ef787d2012-04-12 10:51:47 +01002057void JSObject::PrintElementsTransition(
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002058 FILE* file, Handle<JSObject> object,
2059 ElementsKind from_kind, Handle<FixedArrayBase> from_elements,
2060 ElementsKind to_kind, Handle<FixedArrayBase> to_elements) {
Ben Murdoch3ef787d2012-04-12 10:51:47 +01002061 if (from_kind != to_kind) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002062 OFStream os(file);
2063 os << "elements transition [" << ElementsKindToString(from_kind) << " -> "
2064 << ElementsKindToString(to_kind) << "] in ";
2065 JavaScriptFrame::PrintTop(object->GetIsolate(), file, false, true);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01002066 PrintF(file, " for ");
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002067 object->ShortPrint(file);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01002068 PrintF(file, " from ");
2069 from_elements->ShortPrint(file);
2070 PrintF(file, " to ");
2071 to_elements->ShortPrint(file);
2072 PrintF(file, "\n");
2073 }
2074}
2075
2076
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002077// static
2078MaybeHandle<JSFunction> Map::GetConstructorFunction(
2079 Handle<Map> map, Handle<Context> native_context) {
2080 if (map->IsPrimitiveMap()) {
2081 int const constructor_function_index = map->GetConstructorFunctionIndex();
2082 if (constructor_function_index != kNoConstructorFunctionIndex) {
2083 return handle(
2084 JSFunction::cast(native_context->get(constructor_function_index)));
2085 }
2086 }
2087 return MaybeHandle<JSFunction>();
2088}
2089
2090
2091void Map::PrintReconfiguration(FILE* file, int modify_index, PropertyKind kind,
2092 PropertyAttributes attributes) {
2093 OFStream os(file);
2094 os << "[reconfiguring]";
2095 Name* name = instance_descriptors()->GetKey(modify_index);
2096 if (name->IsString()) {
2097 String::cast(name)->PrintOn(file);
2098 } else {
2099 os << "{symbol " << static_cast<void*>(name) << "}";
2100 }
2101 os << ": " << (kind == kData ? "kData" : "ACCESSORS") << ", attrs: ";
2102 os << attributes << " [";
2103 JavaScriptFrame::PrintTop(GetIsolate(), file, false, true);
2104 os << "]\n";
2105}
2106
2107
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002108void Map::PrintGeneralization(FILE* file,
2109 const char* reason,
2110 int modify_index,
2111 int split,
2112 int descriptors,
2113 bool constant_to_field,
2114 Representation old_representation,
2115 Representation new_representation,
2116 HeapType* old_field_type,
2117 HeapType* new_field_type) {
2118 OFStream os(file);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002119 os << "[generalizing]";
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002120 Name* name = instance_descriptors()->GetKey(modify_index);
2121 if (name->IsString()) {
2122 String::cast(name)->PrintOn(file);
2123 } else {
2124 os << "{symbol " << static_cast<void*>(name) << "}";
2125 }
2126 os << ":";
2127 if (constant_to_field) {
2128 os << "c";
2129 } else {
2130 os << old_representation.Mnemonic() << "{";
2131 old_field_type->PrintTo(os, HeapType::SEMANTIC_DIM);
2132 os << "}";
2133 }
2134 os << "->" << new_representation.Mnemonic() << "{";
2135 new_field_type->PrintTo(os, HeapType::SEMANTIC_DIM);
2136 os << "} (";
2137 if (strlen(reason) > 0) {
2138 os << reason;
2139 } else {
2140 os << "+" << (descriptors - split) << " maps";
2141 }
2142 os << ") [";
2143 JavaScriptFrame::PrintTop(GetIsolate(), file, false, true);
2144 os << "]\n";
2145}
2146
2147
2148void JSObject::PrintInstanceMigration(FILE* file,
2149 Map* original_map,
2150 Map* new_map) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002151 PrintF(file, "[migrating]");
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002152 DescriptorArray* o = original_map->instance_descriptors();
2153 DescriptorArray* n = new_map->instance_descriptors();
2154 for (int i = 0; i < original_map->NumberOfOwnDescriptors(); i++) {
2155 Representation o_r = o->GetDetails(i).representation();
2156 Representation n_r = n->GetDetails(i).representation();
2157 if (!o_r.Equals(n_r)) {
2158 String::cast(o->GetKey(i))->PrintOn(file);
2159 PrintF(file, ":%s->%s ", o_r.Mnemonic(), n_r.Mnemonic());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002160 } else if (o->GetDetails(i).type() == DATA_CONSTANT &&
2161 n->GetDetails(i).type() == DATA) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002162 Name* name = o->GetKey(i);
2163 if (name->IsString()) {
2164 String::cast(name)->PrintOn(file);
2165 } else {
2166 PrintF(file, "{symbol %p}", static_cast<void*>(name));
2167 }
2168 PrintF(file, " ");
2169 }
2170 }
2171 PrintF(file, "\n");
2172}
2173
2174
Emily Bernierd0a1eb72015-03-24 16:35:39 -04002175void HeapObject::HeapObjectShortPrint(std::ostream& os) { // NOLINT
Steve Block44f0eee2011-05-26 01:26:41 +01002176 Heap* heap = GetHeap();
2177 if (!heap->Contains(this)) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002178 os << "!!!INVALID POINTER!!!";
Steve Blocka7e24c12009-10-30 11:49:00 +00002179 return;
2180 }
Steve Block44f0eee2011-05-26 01:26:41 +01002181 if (!heap->Contains(map())) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002182 os << "!!!INVALID MAP!!!";
Steve Blocka7e24c12009-10-30 11:49:00 +00002183 return;
2184 }
2185
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002186 os << this << " ";
Steve Blocka7e24c12009-10-30 11:49:00 +00002187
2188 if (IsString()) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002189 HeapStringAllocator allocator;
2190 StringStream accumulator(&allocator);
2191 String::cast(this)->StringShortPrint(&accumulator);
2192 os << accumulator.ToCString().get();
Steve Blocka7e24c12009-10-30 11:49:00 +00002193 return;
2194 }
2195 if (IsJSObject()) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002196 HeapStringAllocator allocator;
2197 StringStream accumulator(&allocator);
2198 JSObject::cast(this)->JSObjectShortPrint(&accumulator);
2199 os << accumulator.ToCString().get();
Steve Blocka7e24c12009-10-30 11:49:00 +00002200 return;
2201 }
2202 switch (map()->instance_type()) {
2203 case MAP_TYPE:
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002204 os << "<Map(" << ElementsKindToString(Map::cast(this)->elements_kind())
2205 << ")>";
Steve Blocka7e24c12009-10-30 11:49:00 +00002206 break;
2207 case FIXED_ARRAY_TYPE:
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002208 os << "<FixedArray[" << FixedArray::cast(this)->length() << "]>";
Steve Blocka7e24c12009-10-30 11:49:00 +00002209 break;
Ben Murdoch3ef787d2012-04-12 10:51:47 +01002210 case FIXED_DOUBLE_ARRAY_TYPE:
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002211 os << "<FixedDoubleArray[" << FixedDoubleArray::cast(this)->length()
2212 << "]>";
Ben Murdoch3ef787d2012-04-12 10:51:47 +01002213 break;
Steve Blocka7e24c12009-10-30 11:49:00 +00002214 case BYTE_ARRAY_TYPE:
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002215 os << "<ByteArray[" << ByteArray::cast(this)->length() << "]>";
Steve Blocka7e24c12009-10-30 11:49:00 +00002216 break;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002217 case BYTECODE_ARRAY_TYPE:
2218 os << "<BytecodeArray[" << BytecodeArray::cast(this)->length() << "]>";
2219 break;
2220 case TRANSITION_ARRAY_TYPE:
2221 os << "<TransitionArray[" << TransitionArray::cast(this)->length()
2222 << "]>";
2223 break;
Ben Murdoch3ef787d2012-04-12 10:51:47 +01002224 case FREE_SPACE_TYPE:
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002225 os << "<FreeSpace[" << FreeSpace::cast(this)->size() << "]>";
Ben Murdoch3ef787d2012-04-12 10:51:47 +01002226 break;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002227#define TYPED_ARRAY_SHORT_PRINT(Type, type, TYPE, ctype, size) \
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002228 case FIXED_##TYPE##_ARRAY_TYPE: \
2229 os << "<Fixed" #Type "Array[" << Fixed##Type##Array::cast(this)->length() \
2230 << "]>"; \
2231 break;
2232
2233 TYPED_ARRAYS(TYPED_ARRAY_SHORT_PRINT)
2234#undef TYPED_ARRAY_SHORT_PRINT
2235
2236 case SHARED_FUNCTION_INFO_TYPE: {
2237 SharedFunctionInfo* shared = SharedFunctionInfo::cast(this);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002238 base::SmartArrayPointer<char> debug_name =
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002239 shared->DebugName()->ToCString();
2240 if (debug_name[0] != 0) {
2241 os << "<SharedFunctionInfo " << debug_name.get() << ">";
2242 } else {
2243 os << "<SharedFunctionInfo>";
2244 }
Steve Blocka7e24c12009-10-30 11:49:00 +00002245 break;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002246 }
Steve Block1e0659c2011-05-24 12:43:12 +01002247 case JS_MESSAGE_OBJECT_TYPE:
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002248 os << "<JSMessageObject>";
Steve Block1e0659c2011-05-24 12:43:12 +01002249 break;
Steve Blocka7e24c12009-10-30 11:49:00 +00002250#define MAKE_STRUCT_CASE(NAME, Name, name) \
2251 case NAME##_TYPE: \
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002252 os << "<" #Name ">"; \
Steve Blocka7e24c12009-10-30 11:49:00 +00002253 break;
2254 STRUCT_LIST(MAKE_STRUCT_CASE)
2255#undef MAKE_STRUCT_CASE
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002256 case CODE_TYPE: {
2257 Code* code = Code::cast(this);
2258 os << "<Code: " << Code::Kind2String(code->kind()) << ">";
Steve Blocka7e24c12009-10-30 11:49:00 +00002259 break;
2260 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002261 case ODDBALL_TYPE: {
2262 if (IsUndefined()) {
2263 os << "<undefined>";
2264 } else if (IsTheHole()) {
2265 os << "<the hole>";
2266 } else if (IsNull()) {
2267 os << "<null>";
2268 } else if (IsTrue()) {
2269 os << "<true>";
2270 } else if (IsFalse()) {
2271 os << "<false>";
2272 } else {
2273 os << "<Odd Oddball>";
2274 }
Steve Blocka7e24c12009-10-30 11:49:00 +00002275 break;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002276 }
2277 case SYMBOL_TYPE: {
2278 Symbol* symbol = Symbol::cast(this);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04002279 symbol->SymbolShortPrint(os);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002280 break;
2281 }
2282 case HEAP_NUMBER_TYPE: {
2283 os << "<Number: ";
2284 HeapNumber::cast(this)->HeapNumberPrint(os);
2285 os << ">";
2286 break;
2287 }
2288 case MUTABLE_HEAP_NUMBER_TYPE: {
2289 os << "<MutableNumber: ";
2290 HeapNumber::cast(this)->HeapNumberPrint(os);
2291 os << '>';
2292 break;
2293 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002294 case SIMD128_VALUE_TYPE: {
2295#define SIMD128_TYPE(TYPE, Type, type, lane_count, lane_type) \
2296 if (Is##Type()) { \
2297 os << "<" #Type ">"; \
2298 break; \
2299 }
2300 SIMD128_TYPES(SIMD128_TYPE)
2301#undef SIMD128_TYPE
2302 UNREACHABLE();
2303 break;
2304 }
Ben Murdoch589d6972011-11-30 16:04:58 +00002305 case JS_PROXY_TYPE:
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002306 os << "<JSProxy>";
Ben Murdoch589d6972011-11-30 16:04:58 +00002307 break;
Ben Murdoch257744e2011-11-30 15:57:28 +00002308 case FOREIGN_TYPE:
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002309 os << "<Foreign>";
Steve Blocka7e24c12009-10-30 11:49:00 +00002310 break;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002311 case CELL_TYPE: {
2312 os << "Cell for ";
2313 HeapStringAllocator allocator;
2314 StringStream accumulator(&allocator);
2315 Cell::cast(this)->value()->ShortPrint(&accumulator);
2316 os << accumulator.ToCString().get();
Steve Blocka7e24c12009-10-30 11:49:00 +00002317 break;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002318 }
2319 case PROPERTY_CELL_TYPE: {
2320 os << "PropertyCell for ";
2321 HeapStringAllocator allocator;
2322 StringStream accumulator(&allocator);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002323 PropertyCell* cell = PropertyCell::cast(this);
2324 cell->value()->ShortPrint(&accumulator);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002325 os << accumulator.ToCString().get();
2326 break;
2327 }
Emily Bernierd0a1eb72015-03-24 16:35:39 -04002328 case WEAK_CELL_TYPE: {
2329 os << "WeakCell for ";
2330 HeapStringAllocator allocator;
2331 StringStream accumulator(&allocator);
2332 WeakCell::cast(this)->value()->ShortPrint(&accumulator);
2333 os << accumulator.ToCString().get();
2334 break;
2335 }
Steve Blocka7e24c12009-10-30 11:49:00 +00002336 default:
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002337 os << "<Other heap object (" << map()->instance_type() << ")>";
Steve Blocka7e24c12009-10-30 11:49:00 +00002338 break;
2339 }
2340}
2341
2342
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002343void HeapObject::Iterate(ObjectVisitor* v) { IterateFast<ObjectVisitor>(v); }
2344
2345
2346void HeapObject::IterateBody(ObjectVisitor* v) {
Steve Blocka7e24c12009-10-30 11:49:00 +00002347 Map* m = map();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002348 IterateBodyFast<ObjectVisitor>(m->instance_type(), SizeFromMap(m), v);
Steve Blocka7e24c12009-10-30 11:49:00 +00002349}
2350
2351
2352void HeapObject::IterateBody(InstanceType type, int object_size,
2353 ObjectVisitor* v) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002354 IterateBodyFast<ObjectVisitor>(type, object_size, v);
2355}
2356
2357
2358struct CallIsValidSlot {
2359 template <typename BodyDescriptor>
2360 static bool apply(HeapObject* obj, int offset, int) {
2361 return BodyDescriptor::IsValidSlot(obj, offset);
Steve Blocka7e24c12009-10-30 11:49:00 +00002362 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002363};
Steve Blocka7e24c12009-10-30 11:49:00 +00002364
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002365
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002366bool HeapObject::IsValidSlot(int offset) {
2367 DCHECK_NE(0, offset);
2368 return BodyDescriptorApply<CallIsValidSlot, bool>(map()->instance_type(),
2369 this, offset, 0);
Steve Blocka7e24c12009-10-30 11:49:00 +00002370}
2371
2372
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002373bool HeapNumber::HeapNumberBooleanValue() {
2374 return DoubleToBoolean(value());
Steve Blocka7e24c12009-10-30 11:49:00 +00002375}
2376
2377
Emily Bernierd0a1eb72015-03-24 16:35:39 -04002378void HeapNumber::HeapNumberPrint(std::ostream& os) { // NOLINT
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002379 os << value();
Steve Blocka7e24c12009-10-30 11:49:00 +00002380}
2381
2382
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002383#define FIELD_ADDR_CONST(p, offset) \
2384 (reinterpret_cast<const byte*>(p) + offset - kHeapObjectTag)
2385
2386#define READ_INT32_FIELD(p, offset) \
2387 (*reinterpret_cast<const int32_t*>(FIELD_ADDR_CONST(p, offset)))
2388
2389#define READ_INT64_FIELD(p, offset) \
2390 (*reinterpret_cast<const int64_t*>(FIELD_ADDR_CONST(p, offset)))
2391
2392#define READ_BYTE_FIELD(p, offset) \
2393 (*reinterpret_cast<const byte*>(FIELD_ADDR_CONST(p, offset)))
2394
2395
2396// static
2397Handle<String> Simd128Value::ToString(Handle<Simd128Value> input) {
2398#define SIMD128_TYPE(TYPE, Type, type, lane_count, lane_type) \
2399 if (input->Is##Type()) return Type::ToString(Handle<Type>::cast(input));
2400 SIMD128_TYPES(SIMD128_TYPE)
2401#undef SIMD128_TYPE
2402 UNREACHABLE();
2403 return Handle<String>::null();
2404}
2405
2406
2407// static
2408Handle<String> Float32x4::ToString(Handle<Float32x4> input) {
2409 Isolate* const isolate = input->GetIsolate();
2410 char arr[100];
2411 Vector<char> buffer(arr, arraysize(arr));
2412 std::ostringstream os;
2413 os << "SIMD.Float32x4("
2414 << std::string(DoubleToCString(input->get_lane(0), buffer)) << ", "
2415 << std::string(DoubleToCString(input->get_lane(1), buffer)) << ", "
2416 << std::string(DoubleToCString(input->get_lane(2), buffer)) << ", "
2417 << std::string(DoubleToCString(input->get_lane(3), buffer)) << ")";
2418 return isolate->factory()->NewStringFromAsciiChecked(os.str().c_str());
2419}
2420
2421
2422#define SIMD128_BOOL_TO_STRING(Type, lane_count) \
2423 Handle<String> Type::ToString(Handle<Type> input) { \
2424 Isolate* const isolate = input->GetIsolate(); \
2425 std::ostringstream os; \
2426 os << "SIMD." #Type "("; \
2427 os << (input->get_lane(0) ? "true" : "false"); \
2428 for (int i = 1; i < lane_count; i++) { \
2429 os << ", " << (input->get_lane(i) ? "true" : "false"); \
2430 } \
2431 os << ")"; \
2432 return isolate->factory()->NewStringFromAsciiChecked(os.str().c_str()); \
2433 }
2434SIMD128_BOOL_TO_STRING(Bool32x4, 4)
2435SIMD128_BOOL_TO_STRING(Bool16x8, 8)
2436SIMD128_BOOL_TO_STRING(Bool8x16, 16)
2437#undef SIMD128_BOOL_TO_STRING
2438
2439
2440#define SIMD128_INT_TO_STRING(Type, lane_count) \
2441 Handle<String> Type::ToString(Handle<Type> input) { \
2442 Isolate* const isolate = input->GetIsolate(); \
2443 char arr[100]; \
2444 Vector<char> buffer(arr, arraysize(arr)); \
2445 std::ostringstream os; \
2446 os << "SIMD." #Type "("; \
2447 os << IntToCString(input->get_lane(0), buffer); \
2448 for (int i = 1; i < lane_count; i++) { \
2449 os << ", " << IntToCString(input->get_lane(i), buffer); \
2450 } \
2451 os << ")"; \
2452 return isolate->factory()->NewStringFromAsciiChecked(os.str().c_str()); \
2453 }
2454SIMD128_INT_TO_STRING(Int32x4, 4)
2455SIMD128_INT_TO_STRING(Uint32x4, 4)
2456SIMD128_INT_TO_STRING(Int16x8, 8)
2457SIMD128_INT_TO_STRING(Uint16x8, 8)
2458SIMD128_INT_TO_STRING(Int8x16, 16)
2459SIMD128_INT_TO_STRING(Uint8x16, 16)
2460#undef SIMD128_INT_TO_STRING
2461
2462
2463bool Simd128Value::BitwiseEquals(const Simd128Value* other) const {
2464 return READ_INT64_FIELD(this, kValueOffset) ==
2465 READ_INT64_FIELD(other, kValueOffset) &&
2466 READ_INT64_FIELD(this, kValueOffset + kInt64Size) ==
2467 READ_INT64_FIELD(other, kValueOffset + kInt64Size);
2468}
2469
2470
2471uint32_t Simd128Value::Hash() const {
2472 uint32_t seed = v8::internal::kZeroHashSeed;
2473 uint32_t hash;
2474 hash = ComputeIntegerHash(READ_INT32_FIELD(this, kValueOffset), seed);
2475 hash = ComputeIntegerHash(
2476 READ_INT32_FIELD(this, kValueOffset + 1 * kInt32Size), hash * 31);
2477 hash = ComputeIntegerHash(
2478 READ_INT32_FIELD(this, kValueOffset + 2 * kInt32Size), hash * 31);
2479 hash = ComputeIntegerHash(
2480 READ_INT32_FIELD(this, kValueOffset + 3 * kInt32Size), hash * 31);
2481 return hash;
2482}
2483
2484
2485void Simd128Value::CopyBits(void* destination) const {
2486 memcpy(destination, &READ_BYTE_FIELD(this, kValueOffset), kSimd128Size);
2487}
2488
2489
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00002490String* JSReceiver::class_name() {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002491 if (IsFunction()) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002492 return GetHeap()->Function_string();
Steve Blocka7e24c12009-10-30 11:49:00 +00002493 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002494 Object* maybe_constructor = map()->GetConstructor();
2495 if (maybe_constructor->IsJSFunction()) {
2496 JSFunction* constructor = JSFunction::cast(maybe_constructor);
Steve Blocka7e24c12009-10-30 11:49:00 +00002497 return String::cast(constructor->shared()->instance_class_name());
2498 }
2499 // If the constructor is not present, return "Object".
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002500 return GetHeap()->Object_string();
Steve Blocka7e24c12009-10-30 11:49:00 +00002501}
2502
2503
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002504MaybeHandle<String> JSReceiver::BuiltinStringTag(Handle<JSReceiver> object) {
2505 Maybe<bool> is_array = Object::IsArray(object);
2506 MAYBE_RETURN(is_array, MaybeHandle<String>());
2507 Isolate* const isolate = object->GetIsolate();
2508 if (is_array.FromJust()) {
2509 return isolate->factory()->Array_string();
Steve Blocka7e24c12009-10-30 11:49:00 +00002510 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002511 // TODO(adamk): According to ES2015, we should return "Function" when
2512 // object has a [[Call]] internal method (corresponds to IsCallable).
2513 // But this is well cemented in layout tests and might cause webbreakage.
2514 // if (object->IsCallable()) {
2515 // return isolate->factory()->Function_string();
2516 // }
2517 // TODO(adamk): class_name() is expensive, replace with instance type
2518 // checks where possible.
2519 return handle(object->class_name(), isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00002520}
2521
2522
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002523// static
2524Handle<String> JSReceiver::GetConstructorName(Handle<JSReceiver> receiver) {
2525 Isolate* isolate = receiver->GetIsolate();
2526
2527 // If the object was instantiated simply with base == new.target, the
2528 // constructor on the map provides the most accurate name.
2529 // Don't provide the info for prototypes, since their constructors are
2530 // reclaimed and replaced by Object in OptimizeAsPrototype.
2531 if (!receiver->IsJSProxy() && receiver->map()->new_target_is_base() &&
2532 !receiver->map()->is_prototype_map()) {
2533 Object* maybe_constructor = receiver->map()->GetConstructor();
2534 if (maybe_constructor->IsJSFunction()) {
2535 JSFunction* constructor = JSFunction::cast(maybe_constructor);
2536 String* name = String::cast(constructor->shared()->name());
2537 if (name->length() == 0) name = constructor->shared()->inferred_name();
2538 if (name->length() != 0 &&
2539 !name->Equals(isolate->heap()->Object_string())) {
2540 return handle(name, isolate);
2541 }
2542 }
2543 }
2544
2545 if (FLAG_harmony_tostring) {
2546 Handle<Object> maybe_tag = JSReceiver::GetDataProperty(
2547 receiver, isolate->factory()->to_string_tag_symbol());
2548 if (maybe_tag->IsString()) return Handle<String>::cast(maybe_tag);
2549 }
2550
2551 PrototypeIterator iter(isolate, receiver);
2552 if (iter.IsAtEnd()) return handle(receiver->class_name());
2553 Handle<JSReceiver> start = PrototypeIterator::GetCurrent<JSReceiver>(iter);
2554 LookupIterator it(receiver, isolate->factory()->constructor_string(), start,
2555 LookupIterator::PROTOTYPE_CHAIN_SKIP_INTERCEPTOR);
2556 Handle<Object> maybe_constructor = JSReceiver::GetDataProperty(&it);
2557 Handle<String> result = isolate->factory()->Object_string();
2558 if (maybe_constructor->IsJSFunction()) {
2559 JSFunction* constructor = JSFunction::cast(*maybe_constructor);
2560 String* name = String::cast(constructor->shared()->name());
2561 if (name->length() == 0) name = constructor->shared()->inferred_name();
2562 if (name->length() > 0) result = handle(name, isolate);
2563 }
2564
2565 return result.is_identical_to(isolate->factory()->Object_string())
2566 ? handle(receiver->class_name())
2567 : result;
2568}
2569
2570
2571Context* JSReceiver::GetCreationContext() {
2572 if (IsJSBoundFunction()) {
2573 return JSBoundFunction::cast(this)->creation_context();
2574 }
2575 Object* constructor = map()->GetConstructor();
2576 JSFunction* function;
2577 if (constructor->IsJSFunction()) {
2578 function = JSFunction::cast(constructor);
2579 } else {
2580 // Functions have null as a constructor,
2581 // but any JSFunction knows its context immediately.
2582 CHECK(IsJSFunction());
2583 function = JSFunction::cast(this);
2584 }
2585
2586 return function->context()->native_context();
2587}
2588
2589
2590static Handle<Object> WrapType(Handle<HeapType> type) {
2591 if (type->IsClass()) return Map::WeakCellForMap(type->AsClass()->Map());
2592 return type;
Steve Blocka7e24c12009-10-30 11:49:00 +00002593}
2594
2595
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002596MaybeHandle<Map> Map::CopyWithField(Handle<Map> map,
2597 Handle<Name> name,
2598 Handle<HeapType> type,
2599 PropertyAttributes attributes,
2600 Representation representation,
2601 TransitionFlag flag) {
2602 DCHECK(DescriptorArray::kNotFound ==
2603 map->instance_descriptors()->Search(
2604 *name, map->NumberOfOwnDescriptors()));
Ben Murdoch8b112d22011-06-08 16:22:53 +01002605
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002606 // Ensure the descriptor array does not get too big.
2607 if (map->NumberOfOwnDescriptors() >= kMaxNumberOfDescriptors) {
2608 return MaybeHandle<Map>();
Steve Blocka7e24c12009-10-30 11:49:00 +00002609 }
2610
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002611 Isolate* isolate = map->GetIsolate();
2612
Steve Blocka7e24c12009-10-30 11:49:00 +00002613 // Compute the new index for new field.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002614 int index = map->NextFreePropertyIndex();
Steve Blocka7e24c12009-10-30 11:49:00 +00002615
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002616 if (map->instance_type() == JS_CONTEXT_EXTENSION_OBJECT_TYPE) {
2617 representation = Representation::Tagged();
2618 type = HeapType::Any(isolate);
John Reck59135872010-11-02 12:39:01 -07002619 }
Steve Blocka7e24c12009-10-30 11:49:00 +00002620
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002621 Handle<Object> wrapped_type(WrapType(type));
2622
2623 DataDescriptor new_field_desc(name, index, wrapped_type, attributes,
2624 representation);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002625 Handle<Map> new_map = Map::CopyAddDescriptor(map, &new_field_desc, flag);
2626 int unused_property_fields = new_map->unused_property_fields() - 1;
2627 if (unused_property_fields < 0) {
2628 unused_property_fields += JSObject::kFieldsAdded;
John Reck59135872010-11-02 12:39:01 -07002629 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002630 new_map->set_unused_property_fields(unused_property_fields);
2631 return new_map;
Steve Blocka7e24c12009-10-30 11:49:00 +00002632}
2633
2634
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002635MaybeHandle<Map> Map::CopyWithConstant(Handle<Map> map,
2636 Handle<Name> name,
2637 Handle<Object> constant,
2638 PropertyAttributes attributes,
2639 TransitionFlag flag) {
2640 // Ensure the descriptor array does not get too big.
2641 if (map->NumberOfOwnDescriptors() >= kMaxNumberOfDescriptors) {
2642 return MaybeHandle<Map>();
John Reck59135872010-11-02 12:39:01 -07002643 }
Steve Blocka7e24c12009-10-30 11:49:00 +00002644
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002645 // Allocate new instance descriptors with (name, constant) added.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002646 DataConstantDescriptor new_constant_desc(name, constant, attributes);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002647 return Map::CopyAddDescriptor(map, &new_constant_desc, flag);
Steve Blocka7e24c12009-10-30 11:49:00 +00002648}
2649
2650
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002651void JSObject::AddSlowProperty(Handle<JSObject> object,
2652 Handle<Name> name,
2653 Handle<Object> value,
2654 PropertyAttributes attributes) {
2655 DCHECK(!object->HasFastProperties());
2656 Isolate* isolate = object->GetIsolate();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002657 if (object->IsJSGlobalObject()) {
2658 Handle<GlobalDictionary> dict(object->global_dictionary());
2659 PropertyDetails details(attributes, DATA, 0, PropertyCellType::kNoCell);
Steve Blocka7e24c12009-10-30 11:49:00 +00002660 int entry = dict->FindEntry(name);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002661 // If there's a cell there, just invalidate and set the property.
2662 if (entry != GlobalDictionary::kNotFound) {
2663 PropertyCell::UpdateCell(dict, entry, value, details);
2664 // TODO(ishell): move this to UpdateCell.
2665 // Need to adjust the details.
Steve Blocka7e24c12009-10-30 11:49:00 +00002666 int index = dict->NextEnumerationIndex();
Steve Blocka7e24c12009-10-30 11:49:00 +00002667 dict->SetNextEnumerationIndex(index + 1);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002668 PropertyCell* cell = PropertyCell::cast(dict->ValueAt(entry));
2669 details = cell->property_details().set_index(index);
2670 cell->set_property_details(details);
2671
2672 } else {
2673 auto cell = isolate->factory()->NewPropertyCell();
2674 cell->set_value(*value);
2675 auto cell_type = value->IsUndefined() ? PropertyCellType::kUndefined
2676 : PropertyCellType::kConstant;
2677 details = details.set_cell_type(cell_type);
2678 value = cell;
2679
2680 Handle<GlobalDictionary> result =
2681 GlobalDictionary::Add(dict, name, value, details);
2682 if (*dict != *result) object->set_properties(*result);
Steve Blocka7e24c12009-10-30 11:49:00 +00002683 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002684 } else {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002685 Handle<NameDictionary> dict(object->property_dictionary());
2686 PropertyDetails details(attributes, DATA, 0, PropertyCellType::kNoCell);
2687 Handle<NameDictionary> result =
2688 NameDictionary::Add(dict, name, value, details);
2689 if (*dict != *result) object->set_properties(*result);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002690 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002691}
2692
2693
Emily Bernierd0a1eb72015-03-24 16:35:39 -04002694MaybeHandle<Object> JSObject::EnqueueChangeRecord(Handle<JSObject> object,
2695 const char* type_str,
2696 Handle<Name> name,
2697 Handle<Object> old_value) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002698 DCHECK(!object->IsJSGlobalProxy());
2699 DCHECK(!object->IsJSGlobalObject());
2700 Isolate* isolate = object->GetIsolate();
2701 HandleScope scope(isolate);
2702 Handle<String> type = isolate->factory()->InternalizeUtf8String(type_str);
2703 Handle<Object> args[] = { type, object, name, old_value };
2704 int argc = name.is_null() ? 2 : old_value->IsTheHole() ? 3 : 4;
2705
Emily Bernierd0a1eb72015-03-24 16:35:39 -04002706 return Execution::Call(isolate,
2707 Handle<JSFunction>(isolate->observers_notify_change()),
2708 isolate->factory()->undefined_value(), argc, args);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002709}
2710
2711
2712const char* Representation::Mnemonic() const {
2713 switch (kind_) {
2714 case kNone: return "v";
2715 case kTagged: return "t";
2716 case kSmi: return "s";
2717 case kDouble: return "d";
2718 case kInteger32: return "i";
2719 case kHeapObject: return "h";
2720 case kExternal: return "x";
2721 default:
2722 UNREACHABLE();
2723 return NULL;
2724 }
2725}
2726
2727
2728bool Map::InstancesNeedRewriting(Map* target, int target_number_of_fields,
2729 int target_inobject, int target_unused,
2730 int* old_number_of_fields) {
2731 // If fields were added (or removed), rewrite the instance.
2732 *old_number_of_fields = NumberOfFields();
2733 DCHECK(target_number_of_fields >= *old_number_of_fields);
2734 if (target_number_of_fields != *old_number_of_fields) return true;
2735
2736 // If smi descriptors were replaced by double descriptors, rewrite.
2737 DescriptorArray* old_desc = instance_descriptors();
2738 DescriptorArray* new_desc = target->instance_descriptors();
2739 int limit = NumberOfOwnDescriptors();
2740 for (int i = 0; i < limit; i++) {
2741 if (new_desc->GetDetails(i).representation().IsDouble() !=
2742 old_desc->GetDetails(i).representation().IsDouble()) {
2743 return true;
Steve Block44f0eee2011-05-26 01:26:41 +01002744 }
Steve Block8defd9f2010-07-08 12:39:36 +01002745 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002746
2747 // If no fields were added, and no inobject properties were removed, setting
2748 // the map is sufficient.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002749 if (target_inobject == GetInObjectProperties()) return false;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002750 // In-object slack tracking may have reduced the object size of the new map.
2751 // In that case, succeed if all existing fields were inobject, and they still
2752 // fit within the new inobject size.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002753 DCHECK(target_inobject < GetInObjectProperties());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002754 if (target_number_of_fields <= target_inobject) {
2755 DCHECK(target_number_of_fields + target_unused == target_inobject);
2756 return false;
2757 }
2758 // Otherwise, properties will need to be moved to the backing store.
2759 return true;
2760}
2761
2762
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002763// static
2764void JSObject::UpdatePrototypeUserRegistration(Handle<Map> old_map,
2765 Handle<Map> new_map,
2766 Isolate* isolate) {
2767 if (!FLAG_track_prototype_users) return;
2768 if (!old_map->is_prototype_map()) return;
2769 DCHECK(new_map->is_prototype_map());
2770 bool was_registered = JSObject::UnregisterPrototypeUser(old_map, isolate);
2771 new_map->set_prototype_info(old_map->prototype_info());
2772 old_map->set_prototype_info(Smi::FromInt(0));
2773 if (FLAG_trace_prototype_users) {
2774 PrintF("Moving prototype_info %p from map %p to map %p.\n",
2775 reinterpret_cast<void*>(new_map->prototype_info()),
2776 reinterpret_cast<void*>(*old_map),
2777 reinterpret_cast<void*>(*new_map));
2778 }
2779 if (was_registered) {
2780 if (new_map->prototype_info()->IsPrototypeInfo()) {
2781 // The new map isn't registered with its prototype yet; reflect this fact
2782 // in the PrototypeInfo it just inherited from the old map.
2783 PrototypeInfo::cast(new_map->prototype_info())
2784 ->set_registry_slot(PrototypeInfo::UNREGISTERED);
2785 }
2786 JSObject::LazyRegisterPrototypeUser(new_map, isolate);
2787 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002788}
2789
2790
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002791void JSObject::MigrateToMap(Handle<JSObject> object, Handle<Map> new_map,
2792 int expected_additional_properties) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002793 if (object->map() == *new_map) return;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002794 // If this object is a prototype (the callee will check), invalidate any
2795 // prototype chains involving it.
2796 InvalidatePrototypeChains(object->map());
2797 Handle<Map> old_map(object->map());
2798
2799 // If the map was registered with its prototype before, ensure that it
2800 // registers with its new prototype now. This preserves the invariant that
2801 // when a map on a prototype chain is registered with its prototype, then
2802 // all prototypes further up the chain are also registered with their
2803 // respective prototypes.
2804 UpdatePrototypeUserRegistration(old_map, new_map, new_map->GetIsolate());
2805
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002806 if (object->HasFastProperties()) {
2807 if (!new_map->is_dictionary_map()) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002808 MigrateFastToFast(object, new_map);
2809 if (old_map->is_prototype_map()) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002810 DCHECK(!old_map->is_stable());
2811 DCHECK(new_map->is_stable());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002812 // Clear out the old descriptor array to avoid problems to sharing
2813 // the descriptor array without using an explicit.
2814 old_map->InitializeDescriptors(
Emily Bernierd0a1eb72015-03-24 16:35:39 -04002815 old_map->GetHeap()->empty_descriptor_array(),
2816 LayoutDescriptor::FastPointerLayout());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002817 // Ensure that no transition was inserted for prototype migrations.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002818 DCHECK_EQ(0, TransitionArray::NumberOfTransitions(
2819 old_map->raw_transitions()));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002820 DCHECK(new_map->GetBackPointer()->IsUndefined());
Steve Blocka7e24c12009-10-30 11:49:00 +00002821 }
2822 } else {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002823 MigrateFastToSlow(object, new_map, expected_additional_properties);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002824 }
2825 } else {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002826 // For slow-to-fast migrations JSObject::MigrateSlowToFast()
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002827 // must be used instead.
2828 CHECK(new_map->is_dictionary_map());
2829
2830 // Slow-to-slow migration is trivial.
2831 object->set_map(*new_map);
2832 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002833
2834 // Careful: Don't allocate here!
2835 // For some callers of this method, |object| might be in an inconsistent
2836 // state now: the new map might have a new elements_kind, but the object's
2837 // elements pointer hasn't been updated yet. Callers will fix this, but in
2838 // the meantime, (indirectly) calling JSObjectVerify() must be avoided.
2839 // When adding code here, add a DisallowHeapAllocation too.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002840}
2841
2842
2843// To migrate a fast instance to a fast map:
2844// - First check whether the instance needs to be rewritten. If not, simply
2845// change the map.
2846// - Otherwise, allocate a fixed array large enough to hold all fields, in
2847// addition to unused space.
2848// - Copy all existing properties in, in the following order: backing store
2849// properties, unused fields, inobject properties.
2850// - If all allocation succeeded, commit the state atomically:
2851// * Copy inobject properties from the backing store back into the object.
2852// * Trim the difference in instance size of the object. This also cleanly
2853// frees inobject properties that moved to the backing store.
2854// * If there are properties left in the backing store, trim of the space used
2855// to temporarily store the inobject properties.
2856// * If there are properties left in the backing store, install the backing
2857// store.
2858void JSObject::MigrateFastToFast(Handle<JSObject> object, Handle<Map> new_map) {
2859 Isolate* isolate = object->GetIsolate();
2860 Handle<Map> old_map(object->map());
2861 int old_number_of_fields;
2862 int number_of_fields = new_map->NumberOfFields();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002863 int inobject = new_map->GetInObjectProperties();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002864 int unused = new_map->unused_property_fields();
2865
2866 // Nothing to do if no functions were converted to fields and no smis were
2867 // converted to doubles.
2868 if (!old_map->InstancesNeedRewriting(*new_map, number_of_fields, inobject,
2869 unused, &old_number_of_fields)) {
2870 object->synchronized_set_map(*new_map);
2871 return;
2872 }
2873
2874 int total_size = number_of_fields + unused;
2875 int external = total_size - inobject;
2876
2877 if (number_of_fields != old_number_of_fields &&
2878 new_map->GetBackPointer() == *old_map) {
2879 PropertyDetails details = new_map->GetLastDescriptorDetails();
2880
2881 if (old_map->unused_property_fields() > 0) {
2882 if (details.representation().IsDouble()) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002883 FieldIndex index =
2884 FieldIndex::ForDescriptor(*new_map, new_map->LastAdded());
Emily Bernierd0a1eb72015-03-24 16:35:39 -04002885 if (new_map->IsUnboxedDoubleField(index)) {
2886 object->RawFastDoublePropertyAtPut(index, 0);
2887 } else {
2888 Handle<Object> value = isolate->factory()->NewHeapNumber(0, MUTABLE);
2889 object->RawFastPropertyAtPut(index, *value);
2890 }
John Reck59135872010-11-02 12:39:01 -07002891 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002892 object->synchronized_set_map(*new_map);
2893 return;
Steve Blocka7e24c12009-10-30 11:49:00 +00002894 }
Steve Blocka7e24c12009-10-30 11:49:00 +00002895
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002896 DCHECK(number_of_fields == old_number_of_fields + 1);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04002897 // This migration is a transition from a map that has run out of property
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002898 // space. Therefore it could be done by extending the backing store.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002899 int grow_by = external - object->properties()->length();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002900 Handle<FixedArray> old_storage = handle(object->properties(), isolate);
2901 Handle<FixedArray> new_storage =
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002902 isolate->factory()->CopyFixedArrayAndGrow(old_storage, grow_by);
Steve Blocka7e24c12009-10-30 11:49:00 +00002903
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002904 // Properly initialize newly added property.
2905 Handle<Object> value;
2906 if (details.representation().IsDouble()) {
2907 value = isolate->factory()->NewHeapNumber(0, MUTABLE);
2908 } else {
2909 value = isolate->factory()->uninitialized_value();
John Reck59135872010-11-02 12:39:01 -07002910 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002911 DCHECK(details.type() == DATA);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002912 int target_index = details.field_index() - inobject;
2913 DCHECK(target_index >= 0); // Must be a backing store index.
2914 new_storage->set(target_index, *value);
2915
2916 // From here on we cannot fail and we shouldn't GC anymore.
2917 DisallowHeapAllocation no_allocation;
2918
2919 // Set the new property value and do the map transition.
2920 object->set_properties(*new_storage);
2921 object->synchronized_set_map(*new_map);
2922 return;
John Reck59135872010-11-02 12:39:01 -07002923 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002924 Handle<FixedArray> array = isolate->factory()->NewFixedArray(total_size);
2925
2926 Handle<DescriptorArray> old_descriptors(old_map->instance_descriptors());
2927 Handle<DescriptorArray> new_descriptors(new_map->instance_descriptors());
2928 int old_nof = old_map->NumberOfOwnDescriptors();
2929 int new_nof = new_map->NumberOfOwnDescriptors();
2930
2931 // This method only supports generalizing instances to at least the same
2932 // number of properties.
2933 DCHECK(old_nof <= new_nof);
2934
2935 for (int i = 0; i < old_nof; i++) {
2936 PropertyDetails details = new_descriptors->GetDetails(i);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002937 if (details.type() != DATA) continue;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002938 PropertyDetails old_details = old_descriptors->GetDetails(i);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04002939 Representation old_representation = old_details.representation();
2940 Representation representation = details.representation();
Emily Bernierd0a1eb72015-03-24 16:35:39 -04002941 Handle<Object> value;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002942 if (old_details.type() == ACCESSOR_CONSTANT) {
2943 // In case of kAccessor -> kData property reconfiguration, the property
2944 // must already be prepared for data or certain type.
2945 DCHECK(!details.representation().IsNone());
2946 if (details.representation().IsDouble()) {
2947 value = isolate->factory()->NewHeapNumber(0, MUTABLE);
2948 } else {
2949 value = isolate->factory()->uninitialized_value();
2950 }
2951 } else if (old_details.type() == DATA_CONSTANT) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -04002952 value = handle(old_descriptors->GetValue(i), isolate);
2953 DCHECK(!old_representation.IsDouble() && !representation.IsDouble());
2954 } else {
2955 FieldIndex index = FieldIndex::ForDescriptor(*old_map, i);
2956 if (object->IsUnboxedDoubleField(index)) {
2957 double old = object->RawFastDoublePropertyAt(index);
2958 value = isolate->factory()->NewHeapNumber(
2959 old, representation.IsDouble() ? MUTABLE : IMMUTABLE);
2960
2961 } else {
2962 value = handle(object->RawFastPropertyAt(index), isolate);
2963 if (!old_representation.IsDouble() && representation.IsDouble()) {
2964 if (old_representation.IsNone()) {
2965 value = handle(Smi::FromInt(0), isolate);
2966 }
2967 value = Object::NewStorageFor(isolate, value, representation);
2968 } else if (old_representation.IsDouble() &&
2969 !representation.IsDouble()) {
2970 value = Object::WrapForRead(isolate, value, old_representation);
2971 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002972 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002973 }
Emily Bernierd0a1eb72015-03-24 16:35:39 -04002974 DCHECK(!(representation.IsDouble() && value->IsSmi()));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002975 int target_index = new_descriptors->GetFieldIndex(i) - inobject;
2976 if (target_index < 0) target_index += total_size;
2977 array->set(target_index, *value);
2978 }
2979
2980 for (int i = old_nof; i < new_nof; i++) {
2981 PropertyDetails details = new_descriptors->GetDetails(i);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002982 if (details.type() != DATA) continue;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002983 Handle<Object> value;
2984 if (details.representation().IsDouble()) {
2985 value = isolate->factory()->NewHeapNumber(0, MUTABLE);
2986 } else {
2987 value = isolate->factory()->uninitialized_value();
2988 }
2989 int target_index = new_descriptors->GetFieldIndex(i) - inobject;
2990 if (target_index < 0) target_index += total_size;
2991 array->set(target_index, *value);
2992 }
2993
2994 // From here on we cannot fail and we shouldn't GC anymore.
2995 DisallowHeapAllocation no_allocation;
2996
2997 // Copy (real) inobject properties. If necessary, stop at number_of_fields to
2998 // avoid overwriting |one_pointer_filler_map|.
2999 int limit = Min(inobject, number_of_fields);
3000 for (int i = 0; i < limit; i++) {
3001 FieldIndex index = FieldIndex::ForPropertyIndex(*new_map, i);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04003002 Object* value = array->get(external + i);
3003 // Can't use JSObject::FastPropertyAtPut() because proper map was not set
3004 // yet.
3005 if (new_map->IsUnboxedDoubleField(index)) {
3006 DCHECK(value->IsMutableHeapNumber());
3007 object->RawFastDoublePropertyAtPut(index,
3008 HeapNumber::cast(value)->value());
3009 } else {
3010 object->RawFastPropertyAtPut(index, value);
3011 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003012 }
3013
3014 Heap* heap = isolate->heap();
3015
3016 // If there are properties in the new backing store, trim it to the correct
3017 // size and install the backing store into the object.
3018 if (external > 0) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003019 heap->RightTrimFixedArray<Heap::CONCURRENT_TO_SWEEPER>(*array, inobject);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003020 object->set_properties(*array);
3021 }
3022
3023 // Create filler object past the new instance size.
3024 int new_instance_size = new_map->instance_size();
3025 int instance_size_delta = old_map->instance_size() - new_instance_size;
3026 DCHECK(instance_size_delta >= 0);
3027
3028 if (instance_size_delta > 0) {
3029 Address address = object->address();
3030 heap->CreateFillerObjectAt(
3031 address + new_instance_size, instance_size_delta);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003032 heap->AdjustLiveBytes(*object, -instance_size_delta,
3033 Heap::CONCURRENT_TO_SWEEPER);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003034 }
3035
3036 // We are storing the new map using release store after creating a filler for
3037 // the left-over space to avoid races with the sweeper thread.
3038 object->synchronized_set_map(*new_map);
3039}
3040
3041
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003042int Map::NumberOfFields() {
3043 DescriptorArray* descriptors = instance_descriptors();
3044 int result = 0;
3045 for (int i = 0; i < NumberOfOwnDescriptors(); i++) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003046 if (descriptors->GetDetails(i).location() == kField) result++;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003047 }
Steve Blocka7e24c12009-10-30 11:49:00 +00003048 return result;
3049}
3050
3051
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003052Handle<Map> Map::CopyGeneralizeAllRepresentations(
3053 Handle<Map> map, int modify_index, StoreMode store_mode, PropertyKind kind,
3054 PropertyAttributes attributes, const char* reason) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003055 Isolate* isolate = map->GetIsolate();
Emily Bernierd0a1eb72015-03-24 16:35:39 -04003056 Handle<DescriptorArray> old_descriptors(map->instance_descriptors(), isolate);
3057 int number_of_own_descriptors = map->NumberOfOwnDescriptors();
3058 Handle<DescriptorArray> descriptors =
3059 DescriptorArray::CopyUpTo(old_descriptors, number_of_own_descriptors);
Steve Blocka7e24c12009-10-30 11:49:00 +00003060
Emily Bernierd0a1eb72015-03-24 16:35:39 -04003061 for (int i = 0; i < number_of_own_descriptors; i++) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003062 descriptors->SetRepresentation(i, Representation::Tagged());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003063 if (descriptors->GetDetails(i).type() == DATA) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003064 descriptors->SetValue(i, HeapType::Any());
John Reck59135872010-11-02 12:39:01 -07003065 }
3066 }
Steve Blocka7e24c12009-10-30 11:49:00 +00003067
Emily Bernierd0a1eb72015-03-24 16:35:39 -04003068 Handle<LayoutDescriptor> new_layout_descriptor(
3069 LayoutDescriptor::FastPointerLayout(), isolate);
3070 Handle<Map> new_map = CopyReplaceDescriptors(
3071 map, descriptors, new_layout_descriptor, OMIT_TRANSITION,
3072 MaybeHandle<Name>(), reason, SPECIAL_TRANSITION);
3073
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003074 // Unless the instance is being migrated, ensure that modify_index is a field.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003075 if (modify_index >= 0) {
3076 PropertyDetails details = descriptors->GetDetails(modify_index);
3077 if (store_mode == FORCE_FIELD &&
3078 (details.type() != DATA || details.attributes() != attributes)) {
3079 int field_index = details.type() == DATA ? details.field_index()
3080 : new_map->NumberOfFields();
3081 DataDescriptor d(handle(descriptors->GetKey(modify_index), isolate),
3082 field_index, attributes, Representation::Tagged());
3083 descriptors->Replace(modify_index, &d);
3084 if (details.type() != DATA) {
3085 int unused_property_fields = new_map->unused_property_fields() - 1;
3086 if (unused_property_fields < 0) {
3087 unused_property_fields += JSObject::kFieldsAdded;
3088 }
3089 new_map->set_unused_property_fields(unused_property_fields);
John Reck59135872010-11-02 12:39:01 -07003090 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003091 } else {
3092 DCHECK(details.attributes() == attributes);
John Reck59135872010-11-02 12:39:01 -07003093 }
Steve Blocka7e24c12009-10-30 11:49:00 +00003094
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003095 if (FLAG_trace_generalization) {
3096 HeapType* field_type =
3097 (details.type() == DATA)
3098 ? map->instance_descriptors()->GetFieldType(modify_index)
3099 : NULL;
3100 map->PrintGeneralization(
3101 stdout, reason, modify_index, new_map->NumberOfOwnDescriptors(),
3102 new_map->NumberOfOwnDescriptors(),
3103 details.type() == DATA_CONSTANT && store_mode == FORCE_FIELD,
3104 details.representation(), Representation::Tagged(), field_type,
3105 HeapType::Any());
3106 }
Steve Blocka7e24c12009-10-30 11:49:00 +00003107 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003108 return new_map;
Steve Blocka7e24c12009-10-30 11:49:00 +00003109}
3110
3111
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003112void Map::DeprecateTransitionTree() {
3113 if (is_deprecated()) return;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003114 Object* transitions = raw_transitions();
3115 int num_transitions = TransitionArray::NumberOfTransitions(transitions);
3116 for (int i = 0; i < num_transitions; ++i) {
3117 TransitionArray::GetTarget(transitions, i)->DeprecateTransitionTree();
Steve Blocka7e24c12009-10-30 11:49:00 +00003118 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003119 deprecate();
3120 dependent_code()->DeoptimizeDependentCodeGroup(
3121 GetIsolate(), DependentCode::kTransitionGroup);
3122 NotifyLeafMapLayoutChange();
Steve Blocka7e24c12009-10-30 11:49:00 +00003123}
3124
3125
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003126static inline bool EqualImmutableValues(Object* obj1, Object* obj2) {
3127 if (obj1 == obj2) return true; // Valid for both kData and kAccessor kinds.
3128 // TODO(ishell): compare AccessorPairs.
3129 return false;
3130}
Steve Blocka7e24c12009-10-30 11:49:00 +00003131
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003132
3133// Installs |new_descriptors| over the current instance_descriptors to ensure
3134// proper sharing of descriptor arrays.
3135void Map::ReplaceDescriptors(DescriptorArray* new_descriptors,
3136 LayoutDescriptor* new_layout_descriptor) {
3137 // Don't overwrite the empty descriptor array or initial map's descriptors.
3138 if (NumberOfOwnDescriptors() == 0 || GetBackPointer()->IsUndefined()) {
3139 return;
3140 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003141
3142 DescriptorArray* to_replace = instance_descriptors();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003143 GetHeap()->incremental_marking()->RecordWrites(to_replace);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003144 Map* current = this;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003145 while (current->instance_descriptors() == to_replace) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003146 Object* next = current->GetBackPointer();
3147 if (next->IsUndefined()) break; // Stop overwriting at initial map.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003148 current->SetEnumLength(kInvalidEnumCacheSentinel);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04003149 current->UpdateDescriptors(new_descriptors, new_layout_descriptor);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003150 current = Map::cast(next);
3151 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003152 set_owns_descriptors(false);
3153}
3154
3155
3156Map* Map::FindRootMap() {
3157 Map* result = this;
3158 while (true) {
3159 Object* back = result->GetBackPointer();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003160 if (back->IsUndefined()) {
3161 // Initial map always owns descriptors and doesn't have unused entries
3162 // in the descriptor array.
3163 DCHECK(result->owns_descriptors());
3164 DCHECK_EQ(result->NumberOfOwnDescriptors(),
3165 result->instance_descriptors()->number_of_descriptors());
3166 return result;
3167 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003168 result = Map::cast(back);
3169 }
3170}
3171
3172
3173Map* Map::FindLastMatchMap(int verbatim,
3174 int length,
3175 DescriptorArray* descriptors) {
3176 DisallowHeapAllocation no_allocation;
3177
3178 // This can only be called on roots of transition trees.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003179 DCHECK_EQ(verbatim, NumberOfOwnDescriptors());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003180
3181 Map* current = this;
3182
3183 for (int i = verbatim; i < length; i++) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003184 Name* name = descriptors->GetKey(i);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04003185 PropertyDetails details = descriptors->GetDetails(i);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003186 Map* next = TransitionArray::SearchTransition(current, details.kind(), name,
3187 details.attributes());
3188 if (next == NULL) break;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003189 DescriptorArray* next_descriptors = next->instance_descriptors();
3190
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003191 PropertyDetails next_details = next_descriptors->GetDetails(i);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003192 DCHECK_EQ(details.kind(), next_details.kind());
3193 DCHECK_EQ(details.attributes(), next_details.attributes());
3194 if (details.location() != next_details.location()) break;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003195 if (!details.representation().Equals(next_details.representation())) break;
Steve Blocka7e24c12009-10-30 11:49:00 +00003196
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003197 if (next_details.location() == kField) {
3198 HeapType* next_field_type = next_descriptors->GetFieldType(i);
3199 if (!descriptors->GetFieldType(i)->NowIs(next_field_type)) {
3200 break;
3201 }
3202 } else {
3203 if (!EqualImmutableValues(descriptors->GetValue(i),
3204 next_descriptors->GetValue(i))) {
3205 break;
3206 }
3207 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003208 current = next;
3209 }
3210 return current;
Steve Blocka7e24c12009-10-30 11:49:00 +00003211}
3212
3213
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003214Map* Map::FindFieldOwner(int descriptor) {
3215 DisallowHeapAllocation no_allocation;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003216 DCHECK_EQ(DATA, instance_descriptors()->GetDetails(descriptor).type());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003217 Map* result = this;
3218 while (true) {
3219 Object* back = result->GetBackPointer();
3220 if (back->IsUndefined()) break;
3221 Map* parent = Map::cast(back);
3222 if (parent->NumberOfOwnDescriptors() <= descriptor) break;
3223 result = parent;
Steve Blocka7e24c12009-10-30 11:49:00 +00003224 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003225 return result;
Steve Blocka7e24c12009-10-30 11:49:00 +00003226}
3227
3228
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003229void Map::UpdateFieldType(int descriptor, Handle<Name> name,
Emily Bernierd0a1eb72015-03-24 16:35:39 -04003230 Representation new_representation,
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003231 Handle<Object> new_wrapped_type) {
3232 DCHECK(new_wrapped_type->IsSmi() || new_wrapped_type->IsWeakCell());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003233 DisallowHeapAllocation no_allocation;
3234 PropertyDetails details = instance_descriptors()->GetDetails(descriptor);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003235 if (details.type() != DATA) return;
3236 Object* transitions = raw_transitions();
3237 int num_transitions = TransitionArray::NumberOfTransitions(transitions);
3238 for (int i = 0; i < num_transitions; ++i) {
3239 Map* target = TransitionArray::GetTarget(transitions, i);
3240 target->UpdateFieldType(descriptor, name, new_representation,
3241 new_wrapped_type);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003242 }
Emily Bernierd0a1eb72015-03-24 16:35:39 -04003243 // It is allowed to change representation here only from None to something.
3244 DCHECK(details.representation().Equals(new_representation) ||
3245 details.representation().IsNone());
3246
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003247 // Skip if already updated the shared descriptor.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003248 if (instance_descriptors()->GetValue(descriptor) == *new_wrapped_type) return;
3249 DataDescriptor d(name, instance_descriptors()->GetFieldIndex(descriptor),
3250 new_wrapped_type, details.attributes(), new_representation);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003251 instance_descriptors()->Replace(descriptor, &d);
3252}
3253
3254
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003255bool FieldTypeIsCleared(Representation rep, HeapType* type) {
3256 return type->Is(HeapType::None()) && rep.IsHeapObject();
3257}
3258
3259
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003260// static
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003261Handle<HeapType> Map::GeneralizeFieldType(Representation rep1,
3262 Handle<HeapType> type1,
3263 Representation rep2,
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003264 Handle<HeapType> type2,
3265 Isolate* isolate) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003266 // Cleared field types need special treatment. They represent lost knowledge,
3267 // so we must be conservative, so their generalization with any other type
3268 // is "Any".
3269 if (FieldTypeIsCleared(rep1, *type1) || FieldTypeIsCleared(rep2, *type2)) {
3270 return HeapType::Any(isolate);
3271 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003272 if (type1->NowIs(type2)) return type2;
3273 if (type2->NowIs(type1)) return type1;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003274 return HeapType::Any(isolate);
3275}
3276
3277
3278// static
Emily Bernierd0a1eb72015-03-24 16:35:39 -04003279void Map::GeneralizeFieldType(Handle<Map> map, int modify_index,
3280 Representation new_representation,
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003281 Handle<HeapType> new_field_type) {
3282 Isolate* isolate = map->GetIsolate();
3283
3284 // Check if we actually need to generalize the field type at all.
Emily Bernierd0a1eb72015-03-24 16:35:39 -04003285 Handle<DescriptorArray> old_descriptors(map->instance_descriptors(), isolate);
3286 Representation old_representation =
3287 old_descriptors->GetDetails(modify_index).representation();
3288 Handle<HeapType> old_field_type(old_descriptors->GetFieldType(modify_index),
3289 isolate);
3290
3291 if (old_representation.Equals(new_representation) &&
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003292 !FieldTypeIsCleared(new_representation, *new_field_type) &&
3293 // Checking old_field_type for being cleared is not necessary because
3294 // the NowIs check below would fail anyway in that case.
Emily Bernierd0a1eb72015-03-24 16:35:39 -04003295 new_field_type->NowIs(old_field_type)) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003296 DCHECK(Map::GeneralizeFieldType(old_representation, old_field_type,
3297 new_representation, new_field_type, isolate)
3298 ->NowIs(old_field_type));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003299 return;
3300 }
3301
3302 // Determine the field owner.
3303 Handle<Map> field_owner(map->FindFieldOwner(modify_index), isolate);
3304 Handle<DescriptorArray> descriptors(
3305 field_owner->instance_descriptors(), isolate);
3306 DCHECK_EQ(*old_field_type, descriptors->GetFieldType(modify_index));
3307
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003308 new_field_type =
3309 Map::GeneralizeFieldType(old_representation, old_field_type,
3310 new_representation, new_field_type, isolate);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003311
3312 PropertyDetails details = descriptors->GetDetails(modify_index);
3313 Handle<Name> name(descriptors->GetKey(modify_index));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003314
3315 Handle<Object> wrapped_type(WrapType(new_field_type));
Emily Bernierd0a1eb72015-03-24 16:35:39 -04003316 field_owner->UpdateFieldType(modify_index, name, new_representation,
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003317 wrapped_type);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003318 field_owner->dependent_code()->DeoptimizeDependentCodeGroup(
3319 isolate, DependentCode::kFieldTypeGroup);
3320
3321 if (FLAG_trace_generalization) {
3322 map->PrintGeneralization(
3323 stdout, "field type generalization",
3324 modify_index, map->NumberOfOwnDescriptors(),
3325 map->NumberOfOwnDescriptors(), false,
3326 details.representation(), details.representation(),
3327 *old_field_type, *new_field_type);
3328 }
3329}
3330
3331
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003332static inline Handle<HeapType> GetFieldType(Isolate* isolate,
3333 Handle<DescriptorArray> descriptors,
3334 int descriptor,
3335 PropertyLocation location,
3336 Representation representation) {
3337#ifdef DEBUG
3338 PropertyDetails details = descriptors->GetDetails(descriptor);
3339 DCHECK_EQ(kData, details.kind());
3340 DCHECK_EQ(details.location(), location);
3341#endif
3342 if (location == kField) {
3343 return handle(descriptors->GetFieldType(descriptor), isolate);
3344 } else {
3345 return descriptors->GetValue(descriptor)
3346 ->OptimalType(isolate, representation);
3347 }
3348}
3349
3350
3351// Reconfigures property at |modify_index| with |new_kind|, |new_attributes|,
3352// |store_mode| and/or |new_representation|/|new_field_type|.
3353// If |modify_index| is negative then no properties are reconfigured but the
3354// map is migrated to the up-to-date non-deprecated state.
3355//
3356// This method rewrites or completes the transition tree to reflect the new
3357// change. To avoid high degrees over polymorphism, and to stabilize quickly,
3358// on every rewrite the new type is deduced by merging the current type with
3359// any potential new (partial) version of the type in the transition tree.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003360// To do this, on each rewrite:
3361// - Search the root of the transition tree using FindRootMap.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003362// - Find |target_map|, the newest matching version of this map using the
3363// virtually "enhanced" |old_map|'s descriptor array (i.e. whose entry at
3364// |modify_index| is considered to be of |new_kind| and having
3365// |new_attributes|) to walk the transition tree.
3366// - Merge/generalize the "enhanced" descriptor array of the |old_map| and
3367// descriptor array of the |target_map|.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003368// - Generalize the |modify_index| descriptor using |new_representation| and
3369// |new_field_type|.
3370// - Walk the tree again starting from the root towards |target_map|. Stop at
3371// |split_map|, the first map who's descriptor array does not match the merged
3372// descriptor array.
3373// - If |target_map| == |split_map|, |target_map| is in the expected state.
3374// Return it.
3375// - Otherwise, invalidate the outdated transition target from |target_map|, and
3376// replace its transition tree with a new branch for the updated descriptors.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003377Handle<Map> Map::ReconfigureProperty(Handle<Map> old_map, int modify_index,
3378 PropertyKind new_kind,
3379 PropertyAttributes new_attributes,
3380 Representation new_representation,
3381 Handle<HeapType> new_field_type,
3382 StoreMode store_mode) {
3383 DCHECK_NE(kAccessor, new_kind); // TODO(ishell): not supported yet.
3384 DCHECK(store_mode != FORCE_FIELD || modify_index >= 0);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003385 Isolate* isolate = old_map->GetIsolate();
3386
3387 Handle<DescriptorArray> old_descriptors(
3388 old_map->instance_descriptors(), isolate);
3389 int old_nof = old_map->NumberOfOwnDescriptors();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003390
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003391 // If it's just a representation generalization case (i.e. property kind and
3392 // attributes stays unchanged) it's fine to transition from None to anything
3393 // but double without any modification to the object, because the default
3394 // uninitialized value for representation None can be overwritten by both
3395 // smi and tagged values. Doubles, however, would require a box allocation.
3396 if (modify_index >= 0 && !new_representation.IsNone() &&
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003397 !new_representation.IsDouble()) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003398 PropertyDetails old_details = old_descriptors->GetDetails(modify_index);
3399 Representation old_representation = old_details.representation();
Emily Bernierd0a1eb72015-03-24 16:35:39 -04003400
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003401 if (old_representation.IsNone()) {
3402 DCHECK_EQ(new_kind, old_details.kind());
3403 DCHECK_EQ(new_attributes, old_details.attributes());
3404 DCHECK_EQ(DATA, old_details.type());
3405 if (FLAG_trace_generalization) {
3406 old_map->PrintGeneralization(
3407 stdout, "uninitialized field", modify_index,
3408 old_map->NumberOfOwnDescriptors(),
3409 old_map->NumberOfOwnDescriptors(), false, old_representation,
3410 new_representation, old_descriptors->GetFieldType(modify_index),
3411 *new_field_type);
3412 }
3413 Handle<Map> field_owner(old_map->FindFieldOwner(modify_index), isolate);
3414
3415 GeneralizeFieldType(field_owner, modify_index, new_representation,
3416 new_field_type);
3417 DCHECK(old_descriptors->GetDetails(modify_index)
3418 .representation()
3419 .Equals(new_representation));
3420 DCHECK(
3421 old_descriptors->GetFieldType(modify_index)->NowIs(new_field_type));
3422 return old_map;
3423 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003424 }
3425
3426 // Check the state of the root map.
3427 Handle<Map> root_map(old_map->FindRootMap(), isolate);
3428 if (!old_map->EquivalentToForTransition(*root_map)) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -04003429 return CopyGeneralizeAllRepresentations(old_map, modify_index, store_mode,
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003430 new_kind, new_attributes,
Emily Bernierd0a1eb72015-03-24 16:35:39 -04003431 "GenAll_NotEquivalent");
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003432 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003433
3434 ElementsKind from_kind = root_map->elements_kind();
3435 ElementsKind to_kind = old_map->elements_kind();
3436 // TODO(ishell): Add a test for SLOW_SLOPPY_ARGUMENTS_ELEMENTS.
3437 if (from_kind != to_kind && to_kind != DICTIONARY_ELEMENTS &&
3438 to_kind != SLOW_SLOPPY_ARGUMENTS_ELEMENTS &&
3439 !(IsTransitionableFastElementsKind(from_kind) &&
3440 IsMoreGeneralElementsKindTransition(from_kind, to_kind))) {
3441 return CopyGeneralizeAllRepresentations(old_map, modify_index, store_mode,
3442 new_kind, new_attributes,
3443 "GenAll_InvalidElementsTransition");
3444 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003445 int root_nof = root_map->NumberOfOwnDescriptors();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003446 if (modify_index >= 0 && modify_index < root_nof) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003447 PropertyDetails old_details = old_descriptors->GetDetails(modify_index);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003448 if (old_details.kind() != new_kind ||
3449 old_details.attributes() != new_attributes) {
3450 return CopyGeneralizeAllRepresentations(old_map, modify_index, store_mode,
3451 new_kind, new_attributes,
3452 "GenAll_RootModification1");
3453 }
3454 if ((old_details.type() != DATA && store_mode == FORCE_FIELD) ||
3455 (old_details.type() == DATA &&
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003456 (!new_field_type->NowIs(old_descriptors->GetFieldType(modify_index)) ||
3457 !new_representation.fits_into(old_details.representation())))) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -04003458 return CopyGeneralizeAllRepresentations(old_map, modify_index, store_mode,
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003459 new_kind, new_attributes,
3460 "GenAll_RootModification2");
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003461 }
3462 }
3463
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003464 // From here on, use the map with correct elements kind as root map.
3465 if (from_kind != to_kind) {
3466 root_map = Map::AsElementsKind(root_map, to_kind);
3467 }
3468
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003469 Handle<Map> target_map = root_map;
3470 for (int i = root_nof; i < old_nof; ++i) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -04003471 PropertyDetails old_details = old_descriptors->GetDetails(i);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003472 PropertyKind next_kind;
3473 PropertyLocation next_location;
3474 PropertyAttributes next_attributes;
3475 Representation next_representation;
3476 bool property_kind_reconfiguration = false;
3477
3478 if (modify_index == i) {
3479 DCHECK_EQ(FORCE_FIELD, store_mode);
3480 property_kind_reconfiguration = old_details.kind() != new_kind;
3481
3482 next_kind = new_kind;
3483 next_location = kField;
3484 next_attributes = new_attributes;
3485 // If property kind is not reconfigured merge the result with
3486 // representation/field type from the old descriptor.
3487 next_representation = new_representation;
3488 if (!property_kind_reconfiguration) {
3489 next_representation =
3490 next_representation.generalize(old_details.representation());
3491 }
3492
3493 } else {
3494 next_kind = old_details.kind();
3495 next_location = old_details.location();
3496 next_attributes = old_details.attributes();
3497 next_representation = old_details.representation();
3498 }
3499 Map* transition = TransitionArray::SearchTransition(
3500 *target_map, next_kind, old_descriptors->GetKey(i), next_attributes);
3501 if (transition == NULL) break;
3502 Handle<Map> tmp_map(transition, isolate);
3503
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003504 Handle<DescriptorArray> tmp_descriptors = handle(
3505 tmp_map->instance_descriptors(), isolate);
3506
3507 // Check if target map is incompatible.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003508 PropertyDetails tmp_details = tmp_descriptors->GetDetails(i);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003509 DCHECK_EQ(next_kind, tmp_details.kind());
3510 DCHECK_EQ(next_attributes, tmp_details.attributes());
3511 if (next_kind == kAccessor &&
3512 !EqualImmutableValues(old_descriptors->GetValue(i),
3513 tmp_descriptors->GetValue(i))) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -04003514 return CopyGeneralizeAllRepresentations(old_map, modify_index, store_mode,
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003515 new_kind, new_attributes,
Emily Bernierd0a1eb72015-03-24 16:35:39 -04003516 "GenAll_Incompatible");
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003517 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003518 if (next_location == kField && tmp_details.location() == kDescriptor) break;
3519
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003520 Representation tmp_representation = tmp_details.representation();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003521 if (!next_representation.fits_into(tmp_representation)) break;
3522
3523 PropertyLocation old_location = old_details.location();
3524 PropertyLocation tmp_location = tmp_details.location();
3525 if (tmp_location == kField) {
3526 if (next_kind == kData) {
3527 Handle<HeapType> next_field_type;
3528 if (modify_index == i) {
3529 next_field_type = new_field_type;
3530 if (!property_kind_reconfiguration) {
3531 Handle<HeapType> old_field_type =
3532 GetFieldType(isolate, old_descriptors, i,
3533 old_details.location(), tmp_representation);
3534 Representation old_representation = old_details.representation();
3535 next_field_type = GeneralizeFieldType(
3536 old_representation, old_field_type, new_representation,
3537 next_field_type, isolate);
3538 }
3539 } else {
3540 Handle<HeapType> old_field_type =
3541 GetFieldType(isolate, old_descriptors, i, old_details.location(),
3542 tmp_representation);
3543 next_field_type = old_field_type;
3544 }
3545 GeneralizeFieldType(tmp_map, i, tmp_representation, next_field_type);
3546 }
3547 } else if (old_location == kField ||
3548 !EqualImmutableValues(old_descriptors->GetValue(i),
3549 tmp_descriptors->GetValue(i))) {
Ben Murdoch7d3e7fc2011-07-12 16:37:06 +01003550 break;
Steve Blocka7e24c12009-10-30 11:49:00 +00003551 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003552 DCHECK(!tmp_map->is_deprecated());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003553 target_map = tmp_map;
Steve Blocka7e24c12009-10-30 11:49:00 +00003554 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003555
3556 // Directly change the map if the target map is more general.
3557 Handle<DescriptorArray> target_descriptors(
3558 target_map->instance_descriptors(), isolate);
3559 int target_nof = target_map->NumberOfOwnDescriptors();
3560 if (target_nof == old_nof &&
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003561 (store_mode != FORCE_FIELD ||
3562 (modify_index >= 0 &&
3563 target_descriptors->GetDetails(modify_index).location() == kField))) {
3564#ifdef DEBUG
3565 if (modify_index >= 0) {
3566 PropertyDetails details = target_descriptors->GetDetails(modify_index);
3567 DCHECK_EQ(new_kind, details.kind());
3568 DCHECK_EQ(new_attributes, details.attributes());
3569 DCHECK(new_representation.fits_into(details.representation()));
3570 DCHECK(details.location() != kField ||
3571 new_field_type->NowIs(
3572 target_descriptors->GetFieldType(modify_index)));
3573 }
3574#endif
3575 if (*target_map != *old_map) {
3576 old_map->NotifyLeafMapLayoutChange();
3577 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003578 return target_map;
3579 }
3580
3581 // Find the last compatible target map in the transition tree.
3582 for (int i = target_nof; i < old_nof; ++i) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -04003583 PropertyDetails old_details = old_descriptors->GetDetails(i);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003584 PropertyKind next_kind;
3585 PropertyAttributes next_attributes;
3586 if (modify_index == i) {
3587 next_kind = new_kind;
3588 next_attributes = new_attributes;
3589 } else {
3590 next_kind = old_details.kind();
3591 next_attributes = old_details.attributes();
3592 }
3593 Map* transition = TransitionArray::SearchTransition(
3594 *target_map, next_kind, old_descriptors->GetKey(i), next_attributes);
3595 if (transition == NULL) break;
3596 Handle<Map> tmp_map(transition, isolate);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003597 Handle<DescriptorArray> tmp_descriptors(
3598 tmp_map->instance_descriptors(), isolate);
3599
3600 // Check if target map is compatible.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003601#ifdef DEBUG
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003602 PropertyDetails tmp_details = tmp_descriptors->GetDetails(i);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003603 DCHECK_EQ(next_kind, tmp_details.kind());
3604 DCHECK_EQ(next_attributes, tmp_details.attributes());
3605#endif
3606 if (next_kind == kAccessor &&
3607 !EqualImmutableValues(old_descriptors->GetValue(i),
3608 tmp_descriptors->GetValue(i))) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -04003609 return CopyGeneralizeAllRepresentations(old_map, modify_index, store_mode,
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003610 new_kind, new_attributes,
Emily Bernierd0a1eb72015-03-24 16:35:39 -04003611 "GenAll_Incompatible");
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003612 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003613 DCHECK(!tmp_map->is_deprecated());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003614 target_map = tmp_map;
3615 }
3616 target_nof = target_map->NumberOfOwnDescriptors();
3617 target_descriptors = handle(target_map->instance_descriptors(), isolate);
3618
3619 // Allocate a new descriptor array large enough to hold the required
3620 // descriptors, with minimally the exact same size as the old descriptor
3621 // array.
3622 int new_slack = Max(
3623 old_nof, old_descriptors->number_of_descriptors()) - old_nof;
3624 Handle<DescriptorArray> new_descriptors = DescriptorArray::Allocate(
3625 isolate, old_nof, new_slack);
3626 DCHECK(new_descriptors->length() > target_descriptors->length() ||
3627 new_descriptors->NumberOfSlackDescriptors() > 0 ||
3628 new_descriptors->number_of_descriptors() ==
3629 old_descriptors->number_of_descriptors());
3630 DCHECK(new_descriptors->number_of_descriptors() == old_nof);
3631
3632 // 0 -> |root_nof|
3633 int current_offset = 0;
3634 for (int i = 0; i < root_nof; ++i) {
3635 PropertyDetails old_details = old_descriptors->GetDetails(i);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003636 if (old_details.location() == kField) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -04003637 current_offset += old_details.field_width_in_words();
3638 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003639 Descriptor d(handle(old_descriptors->GetKey(i), isolate),
3640 handle(old_descriptors->GetValue(i), isolate),
3641 old_details);
3642 new_descriptors->Set(i, &d);
3643 }
3644
3645 // |root_nof| -> |target_nof|
3646 for (int i = root_nof; i < target_nof; ++i) {
3647 Handle<Name> target_key(target_descriptors->GetKey(i), isolate);
3648 PropertyDetails old_details = old_descriptors->GetDetails(i);
3649 PropertyDetails target_details = target_descriptors->GetDetails(i);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003650
3651 PropertyKind next_kind;
3652 PropertyAttributes next_attributes;
3653 PropertyLocation next_location;
3654 Representation next_representation;
3655 bool property_kind_reconfiguration = false;
3656
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003657 if (modify_index == i) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003658 DCHECK_EQ(FORCE_FIELD, store_mode);
3659 property_kind_reconfiguration = old_details.kind() != new_kind;
3660
3661 next_kind = new_kind;
3662 next_attributes = new_attributes;
3663 next_location = kField;
3664
3665 // Merge new representation/field type with ones from the target
3666 // descriptor. If property kind is not reconfigured merge the result with
3667 // representation/field type from the old descriptor.
3668 next_representation =
3669 new_representation.generalize(target_details.representation());
3670 if (!property_kind_reconfiguration) {
3671 next_representation =
3672 next_representation.generalize(old_details.representation());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003673 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003674 } else {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003675 // Merge old_descriptor and target_descriptor entries.
3676 DCHECK_EQ(target_details.kind(), old_details.kind());
3677 next_kind = target_details.kind();
3678 next_attributes = target_details.attributes();
3679 next_location =
3680 old_details.location() == kField ||
3681 target_details.location() == kField ||
3682 !EqualImmutableValues(target_descriptors->GetValue(i),
3683 old_descriptors->GetValue(i))
3684 ? kField
3685 : kDescriptor;
3686
3687 next_representation = old_details.representation().generalize(
3688 target_details.representation());
3689 }
3690 DCHECK_EQ(next_kind, target_details.kind());
3691 DCHECK_EQ(next_attributes, target_details.attributes());
3692
3693 if (next_location == kField) {
3694 if (next_kind == kData) {
3695 Handle<HeapType> target_field_type =
3696 GetFieldType(isolate, target_descriptors, i,
3697 target_details.location(), next_representation);
3698
3699 Handle<HeapType> next_field_type;
3700 if (modify_index == i) {
3701 next_field_type = GeneralizeFieldType(
3702 target_details.representation(), target_field_type,
3703 new_representation, new_field_type, isolate);
3704 if (!property_kind_reconfiguration) {
3705 Handle<HeapType> old_field_type =
3706 GetFieldType(isolate, old_descriptors, i,
3707 old_details.location(), next_representation);
3708 next_field_type = GeneralizeFieldType(
3709 old_details.representation(), old_field_type,
3710 next_representation, next_field_type, isolate);
3711 }
3712 } else {
3713 Handle<HeapType> old_field_type =
3714 GetFieldType(isolate, old_descriptors, i, old_details.location(),
3715 next_representation);
3716 next_field_type = GeneralizeFieldType(
3717 old_details.representation(), old_field_type, next_representation,
3718 target_field_type, isolate);
3719 }
3720 Handle<Object> wrapped_type(WrapType(next_field_type));
3721 DataDescriptor d(target_key, current_offset, wrapped_type,
3722 next_attributes, next_representation);
3723 current_offset += d.GetDetails().field_width_in_words();
3724 new_descriptors->Set(i, &d);
3725 } else {
3726 UNIMPLEMENTED(); // TODO(ishell): implement.
3727 }
3728 } else {
3729 PropertyDetails details(next_attributes, next_kind, next_location,
3730 next_representation);
3731 Descriptor d(target_key, handle(target_descriptors->GetValue(i), isolate),
3732 details);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003733 new_descriptors->Set(i, &d);
3734 }
3735 }
3736
3737 // |target_nof| -> |old_nof|
3738 for (int i = target_nof; i < old_nof; ++i) {
3739 PropertyDetails old_details = old_descriptors->GetDetails(i);
3740 Handle<Name> old_key(old_descriptors->GetKey(i), isolate);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003741
3742 // Merge old_descriptor entry and modified details together.
3743 PropertyKind next_kind;
3744 PropertyAttributes next_attributes;
3745 PropertyLocation next_location;
3746 Representation next_representation;
3747 bool property_kind_reconfiguration = false;
3748
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003749 if (modify_index == i) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003750 DCHECK_EQ(FORCE_FIELD, store_mode);
3751 // In case of property kind reconfiguration it is not necessary to
3752 // take into account representation/field type of the old descriptor.
3753 property_kind_reconfiguration = old_details.kind() != new_kind;
3754
3755 next_kind = new_kind;
3756 next_attributes = new_attributes;
3757 next_location = kField;
3758 next_representation = new_representation;
3759 if (!property_kind_reconfiguration) {
3760 next_representation =
3761 next_representation.generalize(old_details.representation());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003762 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003763 } else {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003764 next_kind = old_details.kind();
3765 next_attributes = old_details.attributes();
3766 next_location = old_details.location();
3767 next_representation = old_details.representation();
3768 }
3769
3770 if (next_location == kField) {
3771 if (next_kind == kData) {
3772 Handle<HeapType> next_field_type;
3773 if (modify_index == i) {
3774 next_field_type = new_field_type;
3775 if (!property_kind_reconfiguration) {
3776 Handle<HeapType> old_field_type =
3777 GetFieldType(isolate, old_descriptors, i,
3778 old_details.location(), next_representation);
3779 next_field_type = GeneralizeFieldType(
3780 old_details.representation(), old_field_type,
3781 next_representation, next_field_type, isolate);
3782 }
3783 } else {
3784 Handle<HeapType> old_field_type =
3785 GetFieldType(isolate, old_descriptors, i, old_details.location(),
3786 next_representation);
3787 next_field_type = old_field_type;
3788 }
3789
3790 Handle<Object> wrapped_type(WrapType(next_field_type));
3791
3792 DataDescriptor d(old_key, current_offset, wrapped_type, next_attributes,
3793 next_representation);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04003794 current_offset += d.GetDetails().field_width_in_words();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003795 new_descriptors->Set(i, &d);
3796 } else {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003797 UNIMPLEMENTED(); // TODO(ishell): implement.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003798 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003799 } else {
3800 PropertyDetails details(next_attributes, next_kind, next_location,
3801 next_representation);
3802 Descriptor d(old_key, handle(old_descriptors->GetValue(i), isolate),
3803 details);
3804 new_descriptors->Set(i, &d);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003805 }
3806 }
3807
3808 new_descriptors->Sort();
3809
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003810 DCHECK(store_mode != FORCE_FIELD ||
3811 new_descriptors->GetDetails(modify_index).location() == kField);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003812
3813 Handle<Map> split_map(root_map->FindLastMatchMap(
3814 root_nof, old_nof, *new_descriptors), isolate);
3815 int split_nof = split_map->NumberOfOwnDescriptors();
3816 DCHECK_NE(old_nof, split_nof);
3817
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003818 PropertyKind split_kind;
3819 PropertyAttributes split_attributes;
3820 if (modify_index == split_nof) {
3821 split_kind = new_kind;
3822 split_attributes = new_attributes;
3823 } else {
3824 PropertyDetails split_prop_details = old_descriptors->GetDetails(split_nof);
3825 split_kind = split_prop_details.kind();
3826 split_attributes = split_prop_details.attributes();
3827 }
Emily Bernierd0a1eb72015-03-24 16:35:39 -04003828
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003829 // Invalidate a transition target at |key|.
3830 Map* maybe_transition = TransitionArray::SearchTransition(
3831 *split_map, split_kind, old_descriptors->GetKey(split_nof),
3832 split_attributes);
3833 if (maybe_transition != NULL) {
3834 maybe_transition->DeprecateTransitionTree();
3835 }
3836
3837 // If |maybe_transition| is not NULL then the transition array already
3838 // contains entry for given descriptor. This means that the transition
Emily Bernierd0a1eb72015-03-24 16:35:39 -04003839 // could be inserted regardless of whether transitions array is full or not.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003840 if (maybe_transition == NULL &&
3841 !TransitionArray::CanHaveMoreTransitions(split_map)) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -04003842 return CopyGeneralizeAllRepresentations(old_map, modify_index, store_mode,
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003843 new_kind, new_attributes,
Emily Bernierd0a1eb72015-03-24 16:35:39 -04003844 "GenAll_CantHaveMoreTransitions");
3845 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003846
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003847 old_map->NotifyLeafMapLayoutChange();
3848
3849 if (FLAG_trace_generalization && modify_index >= 0) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003850 PropertyDetails old_details = old_descriptors->GetDetails(modify_index);
3851 PropertyDetails new_details = new_descriptors->GetDetails(modify_index);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003852 Handle<HeapType> old_field_type =
3853 (old_details.type() == DATA)
3854 ? handle(old_descriptors->GetFieldType(modify_index), isolate)
3855 : HeapType::Constant(
3856 handle(old_descriptors->GetValue(modify_index), isolate),
3857 isolate);
3858 Handle<HeapType> new_field_type =
3859 (new_details.type() == DATA)
3860 ? handle(new_descriptors->GetFieldType(modify_index), isolate)
3861 : HeapType::Constant(
3862 handle(new_descriptors->GetValue(modify_index), isolate),
3863 isolate);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003864 old_map->PrintGeneralization(
3865 stdout, "", modify_index, split_nof, old_nof,
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003866 old_details.location() == kDescriptor && store_mode == FORCE_FIELD,
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003867 old_details.representation(), new_details.representation(),
3868 *old_field_type, *new_field_type);
3869 }
3870
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003871 Handle<LayoutDescriptor> new_layout_descriptor =
3872 LayoutDescriptor::New(split_map, new_descriptors, old_nof);
3873
3874 Handle<Map> new_map =
3875 AddMissingTransitions(split_map, new_descriptors, new_layout_descriptor);
3876
3877 // Deprecated part of the transition tree is no longer reachable, so replace
3878 // current instance descriptors in the "survived" part of the tree with
3879 // the new descriptors to maintain descriptors sharing invariant.
3880 split_map->ReplaceDescriptors(*new_descriptors, *new_layout_descriptor);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003881 return new_map;
Steve Blocka7e24c12009-10-30 11:49:00 +00003882}
3883
3884
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003885// Generalize the representation of all DATA descriptors.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003886Handle<Map> Map::GeneralizeAllFieldRepresentations(
3887 Handle<Map> map) {
3888 Handle<DescriptorArray> descriptors(map->instance_descriptors());
3889 for (int i = 0; i < map->NumberOfOwnDescriptors(); ++i) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003890 PropertyDetails details = descriptors->GetDetails(i);
3891 if (details.type() == DATA) {
3892 map = ReconfigureProperty(map, i, kData, details.attributes(),
3893 Representation::Tagged(),
3894 HeapType::Any(map->GetIsolate()), FORCE_FIELD);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01003895 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003896 }
3897 return map;
3898}
3899
3900
3901// static
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003902MaybeHandle<Map> Map::TryUpdate(Handle<Map> old_map) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003903 DisallowHeapAllocation no_allocation;
3904 DisallowDeoptimization no_deoptimization(old_map->GetIsolate());
3905
3906 if (!old_map->is_deprecated()) return old_map;
3907
3908 // Check the state of the root map.
3909 Map* root_map = old_map->FindRootMap();
3910 if (!old_map->EquivalentToForTransition(root_map)) return MaybeHandle<Map>();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003911
3912 ElementsKind from_kind = root_map->elements_kind();
3913 ElementsKind to_kind = old_map->elements_kind();
3914 if (from_kind != to_kind) {
3915 // Try to follow existing elements kind transitions.
3916 root_map = root_map->LookupElementsTransitionMap(to_kind);
3917 if (root_map == NULL) return MaybeHandle<Map>();
3918 // From here on, use the map with correct elements kind as root map.
3919 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003920 int root_nof = root_map->NumberOfOwnDescriptors();
3921
3922 int old_nof = old_map->NumberOfOwnDescriptors();
3923 DescriptorArray* old_descriptors = old_map->instance_descriptors();
3924
3925 Map* new_map = root_map;
3926 for (int i = root_nof; i < old_nof; ++i) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -04003927 PropertyDetails old_details = old_descriptors->GetDetails(i);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003928 Map* transition = TransitionArray::SearchTransition(
3929 new_map, old_details.kind(), old_descriptors->GetKey(i),
3930 old_details.attributes());
3931 if (transition == NULL) return MaybeHandle<Map>();
3932 new_map = transition;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003933 DescriptorArray* new_descriptors = new_map->instance_descriptors();
3934
3935 PropertyDetails new_details = new_descriptors->GetDetails(i);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04003936 DCHECK_EQ(old_details.kind(), new_details.kind());
3937 DCHECK_EQ(old_details.attributes(), new_details.attributes());
3938 if (!old_details.representation().fits_into(new_details.representation())) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003939 return MaybeHandle<Map>();
3940 }
Emily Bernierd0a1eb72015-03-24 16:35:39 -04003941 switch (new_details.type()) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003942 case DATA: {
3943 HeapType* new_type = new_descriptors->GetFieldType(i);
3944 // Cleared field types need special treatment. They represent lost
3945 // knowledge, so we must first generalize the new_type to "Any".
3946 if (FieldTypeIsCleared(new_details.representation(), new_type)) {
3947 return MaybeHandle<Map>();
3948 }
3949 PropertyType old_property_type = old_details.type();
3950 if (old_property_type == DATA) {
3951 HeapType* old_type = old_descriptors->GetFieldType(i);
3952 if (FieldTypeIsCleared(old_details.representation(), old_type) ||
3953 !old_type->NowIs(new_type)) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -04003954 return MaybeHandle<Map>();
3955 }
3956 } else {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003957 DCHECK(old_property_type == DATA_CONSTANT);
3958 Object* old_value = old_descriptors->GetValue(i);
3959 if (!new_type->NowContains(old_value)) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -04003960 return MaybeHandle<Map>();
3961 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003962 }
3963 break;
Emily Bernierd0a1eb72015-03-24 16:35:39 -04003964 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003965 case ACCESSOR: {
3966#ifdef DEBUG
3967 HeapType* new_type = new_descriptors->GetFieldType(i);
3968 DCHECK(HeapType::Any()->Is(new_type));
3969#endif
Emily Bernierd0a1eb72015-03-24 16:35:39 -04003970 break;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003971 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003972
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003973 case DATA_CONSTANT:
3974 case ACCESSOR_CONSTANT: {
3975 Object* old_value = old_descriptors->GetValue(i);
3976 Object* new_value = new_descriptors->GetValue(i);
3977 if (old_details.location() == kField || old_value != new_value) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003978 return MaybeHandle<Map>();
3979 }
3980 break;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003981 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003982 }
3983 }
3984 if (new_map->NumberOfOwnDescriptors() != old_nof) return MaybeHandle<Map>();
3985 return handle(new_map);
3986}
3987
3988
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003989// static
3990Handle<Map> Map::Update(Handle<Map> map) {
3991 if (!map->is_deprecated()) return map;
3992 return ReconfigureProperty(map, -1, kData, NONE, Representation::None(),
3993 HeapType::None(map->GetIsolate()),
3994 ALLOW_IN_DESCRIPTOR);
3995}
3996
3997
3998Maybe<bool> JSObject::SetPropertyWithInterceptor(LookupIterator* it,
3999 Handle<Object> value) {
4000 Isolate* isolate = it->isolate();
4001 // Make sure that the top context does not change when doing callbacks or
4002 // interceptor calls.
4003 AssertNoContextChange ncc(isolate);
4004
4005 DCHECK_EQ(LookupIterator::INTERCEPTOR, it->state());
4006 Handle<InterceptorInfo> interceptor(it->GetInterceptor());
4007 if (interceptor->setter()->IsUndefined()) return Just(false);
4008
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004009 Handle<JSObject> holder = it->GetHolder<JSObject>();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004010 v8::Local<v8::Value> result;
4011 PropertyCallbackArguments args(isolate, interceptor->data(),
4012 *it->GetReceiver(), *holder);
4013
4014 if (it->IsElement()) {
4015 uint32_t index = it->index();
4016 v8::IndexedPropertySetterCallback setter =
4017 v8::ToCData<v8::IndexedPropertySetterCallback>(interceptor->setter());
4018 LOG(isolate,
4019 ApiIndexedPropertyAccess("interceptor-indexed-set", *holder, index));
4020 result = args.Call(setter, index, v8::Utils::ToLocal(value));
4021 } else {
4022 Handle<Name> name = it->name();
4023 DCHECK(!name->IsPrivate());
4024
4025 if (name->IsSymbol() && !interceptor->can_intercept_symbols()) {
4026 return Just(false);
4027 }
4028
4029 v8::GenericNamedPropertySetterCallback setter =
4030 v8::ToCData<v8::GenericNamedPropertySetterCallback>(
4031 interceptor->setter());
4032 LOG(it->isolate(),
4033 ApiNamedPropertyAccess("interceptor-named-set", *holder, *name));
4034 result =
4035 args.Call(setter, v8::Utils::ToLocal(name), v8::Utils::ToLocal(value));
Emily Bernierd0a1eb72015-03-24 16:35:39 -04004036 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004037
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004038 RETURN_VALUE_IF_SCHEDULED_EXCEPTION(it->isolate(), Nothing<bool>());
4039 if (result.IsEmpty()) return Just(false);
4040#ifdef DEBUG
4041 Handle<Object> result_internal = v8::Utils::OpenHandle(*result);
4042 result_internal->VerifyApiCallResultType();
4043#endif
4044 return Just(true);
4045 // TODO(neis): In the future, we may want to actually return the interceptor's
4046 // result, which then should be a boolean.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004047}
4048
4049
4050MaybeHandle<Object> Object::SetProperty(Handle<Object> object,
4051 Handle<Name> name, Handle<Object> value,
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004052 LanguageMode language_mode,
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004053 StoreFromKeyed store_mode) {
4054 LookupIterator it(object, name);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004055 MAYBE_RETURN_NULL(SetProperty(&it, value, language_mode, store_mode));
4056 return value;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004057}
4058
4059
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004060Maybe<bool> Object::SetPropertyInternal(LookupIterator* it,
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004061 Handle<Object> value,
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004062 LanguageMode language_mode,
Emily Bernierd0a1eb72015-03-24 16:35:39 -04004063 StoreFromKeyed store_mode,
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004064 bool* found) {
4065 ShouldThrow should_throw =
4066 is_sloppy(language_mode) ? DONT_THROW : THROW_ON_ERROR;
4067
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004068 // Make sure that the top context does not change when doing callbacks or
4069 // interceptor calls.
4070 AssertNoContextChange ncc(it->isolate());
4071
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004072 *found = true;
4073
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004074 bool done = false;
4075 for (; it->IsFound(); it->Next()) {
4076 switch (it->state()) {
4077 case LookupIterator::NOT_FOUND:
4078 UNREACHABLE();
4079
4080 case LookupIterator::ACCESS_CHECK:
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004081 if (it->HasAccess()) break;
4082 // Check whether it makes sense to reuse the lookup iterator. Here it
4083 // might still call into setters up the prototype chain.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004084 return JSObject::SetPropertyWithFailedAccessCheck(it, value,
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004085 should_throw);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004086
4087 case LookupIterator::JSPROXY:
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004088 return JSProxy::SetProperty(it->GetHolder<JSProxy>(), it->GetName(),
4089 value, it->GetReceiver(), language_mode);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004090
4091 case LookupIterator::INTERCEPTOR:
4092 if (it->HolderIsReceiverOrHiddenPrototype()) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004093 Maybe<bool> result = JSObject::SetPropertyWithInterceptor(it, value);
4094 if (result.IsNothing() || result.FromJust()) return result;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004095 } else {
4096 Maybe<PropertyAttributes> maybe_attributes =
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004097 JSObject::GetPropertyAttributesWithInterceptor(it);
4098 if (!maybe_attributes.IsJust()) return Nothing<bool>();
4099 done = maybe_attributes.FromJust() != ABSENT;
4100 if (done && (maybe_attributes.FromJust() & READ_ONLY) != 0) {
4101 return WriteToReadOnlyProperty(it, value, should_throw);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004102 }
4103 }
4104 break;
4105
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004106 case LookupIterator::ACCESSOR: {
4107 if (it->IsReadOnly()) {
4108 return WriteToReadOnlyProperty(it, value, should_throw);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004109 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004110 Handle<Object> accessors = it->GetAccessors();
4111 if (accessors->IsAccessorInfo() &&
4112 !it->HolderIsReceiverOrHiddenPrototype() &&
4113 AccessorInfo::cast(*accessors)->is_special_data_property()) {
4114 done = true;
4115 break;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004116 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004117 return SetPropertyWithAccessor(it, value, should_throw);
4118 }
4119 case LookupIterator::INTEGER_INDEXED_EXOTIC:
4120 // TODO(verwaest): We should throw an exception.
4121 return Just(true);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004122
4123 case LookupIterator::DATA:
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004124 if (it->IsReadOnly()) {
4125 return WriteToReadOnlyProperty(it, value, should_throw);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004126 }
4127 if (it->HolderIsReceiverOrHiddenPrototype()) {
4128 return SetDataProperty(it, value);
4129 }
4130 done = true;
4131 break;
4132
4133 case LookupIterator::TRANSITION:
4134 done = true;
4135 break;
4136 }
4137
4138 if (done) break;
4139 }
4140
4141 // If the receiver is the JSGlobalObject, the store was contextual. In case
4142 // the property did not exist yet on the global object itself, we have to
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004143 // throw a reference error in strict mode. In sloppy mode, we continue.
4144 if (it->GetReceiver()->IsJSGlobalObject() && is_strict(language_mode)) {
4145 it->isolate()->Throw(*it->isolate()->factory()->NewReferenceError(
4146 MessageTemplate::kNotDefined, it->name()));
4147 return Nothing<bool>();
4148 }
4149
4150 *found = false;
4151 return Nothing<bool>();
4152}
4153
4154
4155Maybe<bool> Object::SetProperty(LookupIterator* it, Handle<Object> value,
4156 LanguageMode language_mode,
4157 StoreFromKeyed store_mode) {
4158 ShouldThrow should_throw =
4159 is_sloppy(language_mode) ? DONT_THROW : THROW_ON_ERROR;
4160 if (it->GetReceiver()->IsJSProxy() && it->GetName()->IsPrivate()) {
4161 RETURN_FAILURE(it->isolate(), should_throw,
4162 NewTypeError(MessageTemplate::kProxyPrivate));
4163 }
4164 bool found = false;
4165 Maybe<bool> result =
4166 SetPropertyInternal(it, value, language_mode, store_mode, &found);
4167 if (found) return result;
4168 return AddDataProperty(it, value, NONE, should_throw, store_mode);
4169}
4170
4171
4172Maybe<bool> Object::SetSuperProperty(LookupIterator* it, Handle<Object> value,
4173 LanguageMode language_mode,
4174 StoreFromKeyed store_mode) {
4175 ShouldThrow should_throw =
4176 is_sloppy(language_mode) ? DONT_THROW : THROW_ON_ERROR;
4177 Isolate* isolate = it->isolate();
4178 if (it->GetReceiver()->IsJSProxy() && it->GetName()->IsPrivate()) {
4179 RETURN_FAILURE(isolate, should_throw,
4180 NewTypeError(MessageTemplate::kProxyPrivate));
4181 }
4182
4183 bool found = false;
4184 Maybe<bool> result =
4185 SetPropertyInternal(it, value, language_mode, store_mode, &found);
4186 if (found) return result;
4187
4188 // The property either doesn't exist on the holder or exists there as a data
4189 // property.
4190
4191 if (!it->GetReceiver()->IsJSReceiver()) {
4192 return WriteToReadOnlyProperty(it, value, should_throw);
4193 }
4194 Handle<JSReceiver> receiver = Handle<JSReceiver>::cast(it->GetReceiver());
4195
4196 LookupIterator::Configuration c = LookupIterator::OWN;
4197 LookupIterator own_lookup =
4198 it->IsElement() ? LookupIterator(isolate, receiver, it->index(), c)
4199 : LookupIterator(receiver, it->name(), c);
4200
4201 for (; own_lookup.IsFound(); own_lookup.Next()) {
4202 switch (own_lookup.state()) {
4203 case LookupIterator::ACCESS_CHECK:
4204 if (!own_lookup.HasAccess()) {
4205 return JSObject::SetPropertyWithFailedAccessCheck(&own_lookup, value,
4206 should_throw);
4207 }
4208 break;
4209
4210 case LookupIterator::INTEGER_INDEXED_EXOTIC:
4211 case LookupIterator::ACCESSOR:
4212 return RedefineIncompatibleProperty(isolate, it->GetName(), value,
4213 should_throw);
4214
4215 case LookupIterator::DATA: {
4216 PropertyDetails details = own_lookup.property_details();
4217 if (details.IsReadOnly()) {
4218 return WriteToReadOnlyProperty(&own_lookup, value, should_throw);
4219 }
4220 return SetDataProperty(&own_lookup, value);
4221 }
4222
4223 case LookupIterator::INTERCEPTOR:
4224 case LookupIterator::JSPROXY: {
4225 PropertyDescriptor desc;
4226 Maybe<bool> owned =
4227 JSReceiver::GetOwnPropertyDescriptor(&own_lookup, &desc);
4228 MAYBE_RETURN(owned, Nothing<bool>());
4229 if (!owned.FromJust()) {
4230 return JSReceiver::CreateDataProperty(&own_lookup, value,
4231 should_throw);
4232 }
4233 if (PropertyDescriptor::IsAccessorDescriptor(&desc) ||
4234 !desc.writable()) {
4235 return RedefineIncompatibleProperty(isolate, it->GetName(), value,
4236 should_throw);
4237 }
4238
4239 PropertyDescriptor value_desc;
4240 value_desc.set_value(value);
4241 return JSReceiver::DefineOwnProperty(isolate, receiver, it->GetName(),
4242 &value_desc, should_throw);
4243 }
4244
4245 case LookupIterator::NOT_FOUND:
4246 case LookupIterator::TRANSITION:
4247 UNREACHABLE();
4248 }
4249 }
4250
4251 return JSObject::AddDataProperty(&own_lookup, value, NONE, should_throw,
4252 store_mode);
4253}
4254
4255
4256MaybeHandle<Object> Object::ReadAbsentProperty(LookupIterator* it,
4257 LanguageMode language_mode) {
4258 if (is_strong(language_mode)) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004259 THROW_NEW_ERROR(it->isolate(),
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004260 NewTypeError(MessageTemplate::kStrongPropertyAccess,
4261 it->GetName(), it->GetReceiver()),
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004262 Object);
4263 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004264 return it->isolate()->factory()->undefined_value();
4265}
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004266
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004267MaybeHandle<Object> Object::ReadAbsentProperty(Isolate* isolate,
4268 Handle<Object> receiver,
4269 Handle<Object> name,
4270 LanguageMode language_mode) {
4271 if (is_strong(language_mode)) {
4272 THROW_NEW_ERROR(
4273 isolate,
4274 NewTypeError(MessageTemplate::kStrongPropertyAccess, name, receiver),
4275 Object);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04004276 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004277 return isolate->factory()->undefined_value();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004278}
4279
4280
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004281Maybe<bool> Object::CannotCreateProperty(Isolate* isolate,
4282 Handle<Object> receiver,
4283 Handle<Object> name,
4284 Handle<Object> value,
4285 ShouldThrow should_throw) {
4286 RETURN_FAILURE(
4287 isolate, should_throw,
4288 NewTypeError(MessageTemplate::kStrictCannotCreateProperty, name,
4289 Object::TypeOf(isolate, receiver), receiver));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004290}
4291
4292
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004293Maybe<bool> Object::WriteToReadOnlyProperty(LookupIterator* it,
4294 Handle<Object> value,
4295 ShouldThrow should_throw) {
4296 return WriteToReadOnlyProperty(it->isolate(), it->GetReceiver(),
4297 it->GetName(), value, should_throw);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04004298}
4299
4300
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004301Maybe<bool> Object::WriteToReadOnlyProperty(Isolate* isolate,
4302 Handle<Object> receiver,
4303 Handle<Object> name,
4304 Handle<Object> value,
4305 ShouldThrow should_throw) {
4306 RETURN_FAILURE(isolate, should_throw,
4307 NewTypeError(MessageTemplate::kStrictReadOnlyProperty, name,
4308 Object::TypeOf(isolate, receiver), receiver));
4309}
4310
4311
4312Maybe<bool> Object::RedefineIncompatibleProperty(Isolate* isolate,
4313 Handle<Object> name,
4314 Handle<Object> value,
4315 ShouldThrow should_throw) {
4316 RETURN_FAILURE(isolate, should_throw,
4317 NewTypeError(MessageTemplate::kRedefineDisallowed, name));
4318}
4319
4320
4321Maybe<bool> Object::SetDataProperty(LookupIterator* it, Handle<Object> value) {
4322 // Proxies are handled elsewhere. Other non-JSObjects cannot have own
4323 // properties.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004324 Handle<JSObject> receiver = Handle<JSObject>::cast(it->GetReceiver());
4325
4326 // Store on the holder which may be hidden behind the receiver.
4327 DCHECK(it->HolderIsReceiverOrHiddenPrototype());
4328
4329 // Old value for the observation change record.
4330 // Fetch before transforming the object since the encoding may become
4331 // incompatible with what's cached in |it|.
Emily Bernierd0a1eb72015-03-24 16:35:39 -04004332 bool is_observed = receiver->map()->is_observed() &&
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004333 (it->IsElement() ||
4334 !it->isolate()->IsInternallyUsedPropertyName(it->name()));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004335 MaybeHandle<Object> maybe_old;
4336 if (is_observed) maybe_old = it->GetDataValue();
4337
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004338 Handle<Object> to_assign = value;
4339 // Convert the incoming value to a number for storing into typed arrays.
4340 if (it->IsElement() && receiver->HasFixedTypedArrayElements()) {
4341 if (!value->IsNumber() && !value->IsUndefined()) {
4342 ASSIGN_RETURN_ON_EXCEPTION_VALUE(
4343 it->isolate(), to_assign, Object::ToNumber(value), Nothing<bool>());
4344 // ToNumber above might modify the receiver, causing the cached
4345 // holder_map to mismatch the actual holder->map() after this point.
4346 // Reload the map to be in consistent state. Other cached state cannot
4347 // have been invalidated since typed array elements cannot be reconfigured
4348 // in any way.
4349 it->ReloadHolderMap();
4350
4351 // We have to recheck the length. However, it can only change if the
4352 // underlying buffer was neutered, so just check that.
4353 if (Handle<JSArrayBufferView>::cast(receiver)->WasNeutered()) {
4354 return Just(true);
4355 // TODO(neis): According to the spec, this should throw a TypeError.
4356 }
4357 }
4358 }
4359
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004360 // Possibly migrate to the most up-to-date map that will be able to store
4361 // |value| under it->name().
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004362 it->PrepareForDataProperty(to_assign);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004363
4364 // Write the property value.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004365 it->WriteDataValue(to_assign);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004366
4367 // Send the change record if there are observers.
4368 if (is_observed && !value->SameValue(*maybe_old.ToHandleChecked())) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004369 RETURN_ON_EXCEPTION_VALUE(
4370 it->isolate(),
4371 JSObject::EnqueueChangeRecord(receiver, "update", it->GetName(),
4372 maybe_old.ToHandleChecked()),
4373 Nothing<bool>());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004374 }
4375
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004376#if VERIFY_HEAP
4377 if (FLAG_verify_heap) {
4378 receiver->JSObjectVerify();
4379 }
4380#endif
4381 return Just(true);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004382}
4383
4384
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004385MUST_USE_RESULT static MaybeHandle<Object> BeginPerformSplice(
4386 Handle<JSArray> object) {
4387 Isolate* isolate = object->GetIsolate();
4388 HandleScope scope(isolate);
4389 Handle<Object> args[] = {object};
4390
4391 return Execution::Call(
4392 isolate, Handle<JSFunction>(isolate->observers_begin_perform_splice()),
4393 isolate->factory()->undefined_value(), arraysize(args), args);
4394}
4395
4396
4397MUST_USE_RESULT static MaybeHandle<Object> EndPerformSplice(
4398 Handle<JSArray> object) {
4399 Isolate* isolate = object->GetIsolate();
4400 HandleScope scope(isolate);
4401 Handle<Object> args[] = {object};
4402
4403 return Execution::Call(
4404 isolate, Handle<JSFunction>(isolate->observers_end_perform_splice()),
4405 isolate->factory()->undefined_value(), arraysize(args), args);
4406}
4407
4408
4409MUST_USE_RESULT static MaybeHandle<Object> EnqueueSpliceRecord(
4410 Handle<JSArray> object, uint32_t index, Handle<JSArray> deleted,
4411 uint32_t add_count) {
4412 Isolate* isolate = object->GetIsolate();
4413 HandleScope scope(isolate);
4414 Handle<Object> index_object = isolate->factory()->NewNumberFromUint(index);
4415 Handle<Object> add_count_object =
4416 isolate->factory()->NewNumberFromUint(add_count);
4417
4418 Handle<Object> args[] = {object, index_object, deleted, add_count_object};
4419
4420 return Execution::Call(
4421 isolate, Handle<JSFunction>(isolate->observers_enqueue_splice()),
4422 isolate->factory()->undefined_value(), arraysize(args), args);
4423}
4424
4425
4426Maybe<bool> Object::AddDataProperty(LookupIterator* it, Handle<Object> value,
4427 PropertyAttributes attributes,
4428 ShouldThrow should_throw,
4429 StoreFromKeyed store_mode) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004430 DCHECK(!it->GetReceiver()->IsJSProxy());
4431 if (!it->GetReceiver()->IsJSObject()) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004432 return CannotCreateProperty(it->isolate(), it->GetReceiver(), it->GetName(),
4433 value, should_throw);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004434 }
4435
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004436 DCHECK_NE(LookupIterator::INTEGER_INDEXED_EXOTIC, it->state());
4437
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004438 Handle<JSObject> receiver = it->GetStoreTarget();
4439
4440 // If the receiver is a JSGlobalProxy, store on the prototype (JSGlobalObject)
4441 // instead. If the prototype is Null, the proxy is detached.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004442 if (receiver->IsJSGlobalProxy()) return Just(true);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004443
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004444 Isolate* isolate = it->isolate();
Emily Bernierd0a1eb72015-03-24 16:35:39 -04004445
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004446 if (!receiver->map()->is_extensible() &&
4447 (it->IsElement() || !isolate->IsInternallyUsedPropertyName(it->name()))) {
4448 RETURN_FAILURE(
4449 isolate, should_throw,
4450 NewTypeError(MessageTemplate::kObjectNotExtensible, it->GetName()));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004451 }
4452
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004453 if (it->IsElement()) {
4454 if (receiver->IsJSArray()) {
4455 Handle<JSArray> array = Handle<JSArray>::cast(receiver);
4456 if (JSArray::WouldChangeReadOnlyLength(array, it->index())) {
4457 RETURN_FAILURE(array->GetIsolate(), should_throw,
4458 NewTypeError(MessageTemplate::kStrictReadOnlyProperty,
4459 isolate->factory()->length_string(),
4460 Object::TypeOf(isolate, array), array));
4461 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004462
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004463 if (FLAG_trace_external_array_abuse &&
4464 array->HasFixedTypedArrayElements()) {
4465 CheckArrayAbuse(array, "typed elements write", it->index(), true);
4466 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004467
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004468 if (FLAG_trace_js_array_abuse && !array->HasFixedTypedArrayElements()) {
4469 CheckArrayAbuse(array, "elements write", it->index(), false);
Steve Blocka7e24c12009-10-30 11:49:00 +00004470 }
4471 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004472
4473 Maybe<bool> result = JSObject::AddDataElement(receiver, it->index(), value,
4474 attributes, should_throw);
4475 JSObject::ValidateElements(receiver);
4476 return result;
4477 } else {
4478 // Migrate to the most up-to-date map that will be able to store |value|
4479 // under it->name() with |attributes|.
4480 it->PrepareTransitionToDataProperty(value, attributes, store_mode);
4481 DCHECK_EQ(LookupIterator::TRANSITION, it->state());
4482 it->ApplyTransitionToDataProperty();
4483
4484 // TODO(verwaest): Encapsulate dictionary handling better.
4485 if (receiver->map()->is_dictionary_map()) {
4486 // TODO(verwaest): Probably should ensure this is done beforehand.
4487 it->InternalizeName();
4488 // TODO(dcarney): just populate TransitionPropertyCell here?
4489 JSObject::AddSlowProperty(receiver, it->name(), value, attributes);
4490 } else {
4491 // Write the property value.
4492 it->WriteDataValue(value);
4493 }
4494
4495 // Send the change record if there are observers.
4496 if (receiver->map()->is_observed() &&
4497 !isolate->IsInternallyUsedPropertyName(it->name())) {
4498 RETURN_ON_EXCEPTION_VALUE(isolate, JSObject::EnqueueChangeRecord(
4499 receiver, "add", it->name(),
4500 it->factory()->the_hole_value()),
4501 Nothing<bool>());
4502 }
4503#if VERIFY_HEAP
4504 if (FLAG_verify_heap) {
4505 receiver->JSObjectVerify();
4506 }
4507#endif
Steve Blocka7e24c12009-10-30 11:49:00 +00004508 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004509
4510 return Just(true);
Steve Blocka7e24c12009-10-30 11:49:00 +00004511}
4512
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004513
4514void Map::EnsureDescriptorSlack(Handle<Map> map, int slack) {
4515 // Only supports adding slack to owned descriptors.
4516 DCHECK(map->owns_descriptors());
4517
4518 Handle<DescriptorArray> descriptors(map->instance_descriptors());
4519 int old_size = map->NumberOfOwnDescriptors();
4520 if (slack <= descriptors->NumberOfSlackDescriptors()) return;
4521
4522 Handle<DescriptorArray> new_descriptors = DescriptorArray::CopyUpTo(
4523 descriptors, old_size, slack);
4524
Emily Bernierd0a1eb72015-03-24 16:35:39 -04004525 DisallowHeapAllocation no_allocation;
4526 // The descriptors are still the same, so keep the layout descriptor.
4527 LayoutDescriptor* layout_descriptor = map->GetLayoutDescriptor();
4528
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004529 if (old_size == 0) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -04004530 map->UpdateDescriptors(*new_descriptors, layout_descriptor);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004531 return;
4532 }
4533
4534 // If the source descriptors had an enum cache we copy it. This ensures
4535 // that the maps to which we push the new descriptor array back can rely
4536 // on a cache always being available once it is set. If the map has more
4537 // enumerated descriptors than available in the original cache, the cache
4538 // will be lazily replaced by the extended cache when needed.
4539 if (descriptors->HasEnumCache()) {
4540 new_descriptors->CopyEnumCacheFrom(*descriptors);
4541 }
4542
4543 // Replace descriptors by new_descriptors in all maps that share it.
4544 map->GetHeap()->incremental_marking()->RecordWrites(*descriptors);
4545
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004546 Map* current = *map;
4547 while (current->instance_descriptors() == *descriptors) {
4548 Object* next = current->GetBackPointer();
4549 if (next->IsUndefined()) break; // Stop overwriting at initial map.
4550 current->UpdateDescriptors(*new_descriptors, layout_descriptor);
4551 current = Map::cast(next);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004552 }
Emily Bernierd0a1eb72015-03-24 16:35:39 -04004553 map->UpdateDescriptors(*new_descriptors, layout_descriptor);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004554}
4555
4556
4557template<class T>
4558static int AppendUniqueCallbacks(NeanderArray* callbacks,
4559 Handle<typename T::Array> array,
4560 int valid_descriptors) {
4561 int nof_callbacks = callbacks->length();
4562
4563 Isolate* isolate = array->GetIsolate();
4564 // Ensure the keys are unique names before writing them into the
4565 // instance descriptor. Since it may cause a GC, it has to be done before we
4566 // temporarily put the heap in an invalid state while appending descriptors.
4567 for (int i = 0; i < nof_callbacks; ++i) {
4568 Handle<AccessorInfo> entry(AccessorInfo::cast(callbacks->get(i)));
4569 if (entry->name()->IsUniqueName()) continue;
4570 Handle<String> key =
4571 isolate->factory()->InternalizeString(
4572 Handle<String>(String::cast(entry->name())));
4573 entry->set_name(*key);
4574 }
4575
4576 // Fill in new callback descriptors. Process the callbacks from
4577 // back to front so that the last callback with a given name takes
4578 // precedence over previously added callbacks with that name.
4579 for (int i = nof_callbacks - 1; i >= 0; i--) {
4580 Handle<AccessorInfo> entry(AccessorInfo::cast(callbacks->get(i)));
4581 Handle<Name> key(Name::cast(entry->name()));
4582 // Check if a descriptor with this name already exists before writing.
4583 if (!T::Contains(key, entry, valid_descriptors, array)) {
4584 T::Insert(key, entry, valid_descriptors, array);
4585 valid_descriptors++;
Ben Murdoch3ef787d2012-04-12 10:51:47 +01004586 }
4587 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004588
4589 return valid_descriptors;
4590}
4591
4592struct DescriptorArrayAppender {
4593 typedef DescriptorArray Array;
4594 static bool Contains(Handle<Name> key,
4595 Handle<AccessorInfo> entry,
4596 int valid_descriptors,
4597 Handle<DescriptorArray> array) {
4598 DisallowHeapAllocation no_gc;
4599 return array->Search(*key, valid_descriptors) != DescriptorArray::kNotFound;
4600 }
4601 static void Insert(Handle<Name> key,
4602 Handle<AccessorInfo> entry,
4603 int valid_descriptors,
4604 Handle<DescriptorArray> array) {
4605 DisallowHeapAllocation no_gc;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004606 AccessorConstantDescriptor desc(key, entry, entry->property_attributes());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004607 array->Append(&desc);
4608 }
4609};
4610
4611
4612struct FixedArrayAppender {
4613 typedef FixedArray Array;
4614 static bool Contains(Handle<Name> key,
4615 Handle<AccessorInfo> entry,
4616 int valid_descriptors,
4617 Handle<FixedArray> array) {
4618 for (int i = 0; i < valid_descriptors; i++) {
4619 if (*key == AccessorInfo::cast(array->get(i))->name()) return true;
4620 }
4621 return false;
4622 }
4623 static void Insert(Handle<Name> key,
4624 Handle<AccessorInfo> entry,
4625 int valid_descriptors,
4626 Handle<FixedArray> array) {
4627 DisallowHeapAllocation no_gc;
4628 array->set(valid_descriptors, *entry);
4629 }
4630};
4631
4632
4633void Map::AppendCallbackDescriptors(Handle<Map> map,
4634 Handle<Object> descriptors) {
4635 int nof = map->NumberOfOwnDescriptors();
4636 Handle<DescriptorArray> array(map->instance_descriptors());
4637 NeanderArray callbacks(descriptors);
4638 DCHECK(array->NumberOfSlackDescriptors() >= callbacks.length());
4639 nof = AppendUniqueCallbacks<DescriptorArrayAppender>(&callbacks, array, nof);
4640 map->SetNumberOfOwnDescriptors(nof);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01004641}
4642
Steve Blocka7e24c12009-10-30 11:49:00 +00004643
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004644int AccessorInfo::AppendUnique(Handle<Object> descriptors,
4645 Handle<FixedArray> array,
4646 int valid_descriptors) {
4647 NeanderArray callbacks(descriptors);
4648 DCHECK(array->length() >= callbacks.length() + valid_descriptors);
4649 return AppendUniqueCallbacks<FixedArrayAppender>(&callbacks,
4650 array,
4651 valid_descriptors);
Ben Murdochb0fe1622011-05-05 13:52:32 +01004652}
4653
4654
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004655static bool ContainsMap(MapHandleList* maps, Map* map) {
4656 DCHECK_NOT_NULL(map);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01004657 for (int i = 0; i < maps->length(); ++i) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004658 if (!maps->at(i).is_null() && *maps->at(i) == map) return true;
Ben Murdoch3ef787d2012-04-12 10:51:47 +01004659 }
4660 return false;
4661}
Ben Murdoch592a9fc2012-03-05 11:04:45 +00004662
Ben Murdoch85b71792012-04-11 18:30:58 +01004663
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004664Handle<Map> Map::FindTransitionedMap(Handle<Map> map,
4665 MapHandleList* candidates) {
4666 ElementsKind kind = map->elements_kind();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004667 bool packed = IsFastPackedElementsKind(kind);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004668
4669 Map* transition = nullptr;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004670 if (IsTransitionableFastElementsKind(kind)) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004671 for (Map* current = map->ElementsTransitionMap();
4672 current != nullptr && current->has_fast_elements();
4673 current = current->ElementsTransitionMap()) {
4674 if (ContainsMap(candidates, current) &&
4675 (packed || !IsFastPackedElementsKind(current->elements_kind()))) {
4676 transition = current;
4677 packed = packed && IsFastPackedElementsKind(current->elements_kind());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004678 }
Ben Murdoch85b71792012-04-11 18:30:58 +01004679 }
Ben Murdoch3ef787d2012-04-12 10:51:47 +01004680 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004681 return transition == nullptr ? Handle<Map>() : handle(transition);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01004682}
Ben Murdoch85b71792012-04-11 18:30:58 +01004683
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004684
4685static Map* FindClosestElementsTransition(Map* map, ElementsKind to_kind) {
4686 Map* current_map = map;
Ben Murdoch3ef787d2012-04-12 10:51:47 +01004687
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004688 ElementsKind kind = map->elements_kind();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004689 while (kind != to_kind) {
4690 Map* next_map = current_map->ElementsTransitionMap();
4691 if (next_map == nullptr) return current_map;
4692 kind = next_map->elements_kind();
4693 current_map = next_map;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004694 }
4695
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004696 DCHECK_EQ(to_kind, current_map->elements_kind());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004697 return current_map;
4698}
4699
4700
4701Map* Map::LookupElementsTransitionMap(ElementsKind to_kind) {
4702 Map* to_map = FindClosestElementsTransition(this, to_kind);
4703 if (to_map->elements_kind() == to_kind) return to_map;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004704 return nullptr;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004705}
4706
4707
4708bool Map::IsMapInArrayPrototypeChain() {
4709 Isolate* isolate = GetIsolate();
4710 if (isolate->initial_array_prototype()->map() == this) {
4711 return true;
4712 }
4713
4714 if (isolate->initial_object_prototype()->map() == this) {
4715 return true;
4716 }
4717
4718 return false;
4719}
4720
4721
Emily Bernierd0a1eb72015-03-24 16:35:39 -04004722Handle<WeakCell> Map::WeakCellForMap(Handle<Map> map) {
4723 Isolate* isolate = map->GetIsolate();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004724 if (map->weak_cell_cache()->IsWeakCell()) {
4725 return Handle<WeakCell>(WeakCell::cast(map->weak_cell_cache()));
Emily Bernierd0a1eb72015-03-24 16:35:39 -04004726 }
4727 Handle<WeakCell> weak_cell = isolate->factory()->NewWeakCell(map);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004728 map->set_weak_cell_cache(*weak_cell);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04004729 return weak_cell;
4730}
4731
4732
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004733static Handle<Map> AddMissingElementsTransitions(Handle<Map> map,
4734 ElementsKind to_kind) {
4735 DCHECK(IsTransitionElementsKind(map->elements_kind()));
4736
4737 Handle<Map> current_map = map;
4738
4739 ElementsKind kind = map->elements_kind();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004740 TransitionFlag flag;
4741 if (map->is_prototype_map()) {
4742 flag = OMIT_TRANSITION;
4743 } else {
4744 flag = INSERT_TRANSITION;
4745 if (IsFastElementsKind(kind)) {
4746 while (kind != to_kind && !IsTerminalElementsKind(kind)) {
4747 kind = GetNextTransitionElementsKind(kind);
4748 current_map = Map::CopyAsElementsKind(current_map, kind, flag);
4749 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004750 }
4751 }
4752
4753 // In case we are exiting the fast elements kind system, just add the map in
4754 // the end.
4755 if (kind != to_kind) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004756 current_map = Map::CopyAsElementsKind(current_map, to_kind, flag);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004757 }
4758
4759 DCHECK(current_map->elements_kind() == to_kind);
4760 return current_map;
4761}
4762
4763
4764Handle<Map> Map::TransitionElementsTo(Handle<Map> map,
4765 ElementsKind to_kind) {
4766 ElementsKind from_kind = map->elements_kind();
4767 if (from_kind == to_kind) return map;
4768
4769 Isolate* isolate = map->GetIsolate();
4770 Context* native_context = isolate->context()->native_context();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004771 if (from_kind == FAST_SLOPPY_ARGUMENTS_ELEMENTS) {
4772 if (*map == native_context->fast_aliased_arguments_map()) {
4773 DCHECK_EQ(SLOW_SLOPPY_ARGUMENTS_ELEMENTS, to_kind);
4774 return handle(native_context->slow_aliased_arguments_map());
4775 }
4776 } else if (from_kind == SLOW_SLOPPY_ARGUMENTS_ELEMENTS) {
4777 if (*map == native_context->slow_aliased_arguments_map()) {
4778 DCHECK_EQ(FAST_SLOPPY_ARGUMENTS_ELEMENTS, to_kind);
4779 return handle(native_context->fast_aliased_arguments_map());
4780 }
4781 } else if (IsFastElementsKind(from_kind) && IsFastElementsKind(to_kind)) {
4782 // Reuse map transitions for JSArrays.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004783 DisallowHeapAllocation no_gc;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004784 Strength strength = map->is_strong() ? Strength::STRONG : Strength::WEAK;
4785 if (native_context->get(Context::ArrayMapIndex(from_kind, strength)) ==
4786 *map) {
4787 Object* maybe_transitioned_map =
4788 native_context->get(Context::ArrayMapIndex(to_kind, strength));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004789 if (maybe_transitioned_map->IsMap()) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004790 return handle(Map::cast(maybe_transitioned_map), isolate);
Ben Murdoch85b71792012-04-11 18:30:58 +01004791 }
Ben Murdoch592a9fc2012-03-05 11:04:45 +00004792 }
4793 }
4794
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004795 DCHECK(!map->IsUndefined());
4796 // Check if we can go back in the elements kind transition chain.
4797 if (IsHoleyElementsKind(from_kind) &&
4798 to_kind == GetPackedElementsKind(from_kind) &&
4799 map->GetBackPointer()->IsMap() &&
4800 Map::cast(map->GetBackPointer())->elements_kind() == to_kind) {
4801 return handle(Map::cast(map->GetBackPointer()));
Ben Murdoch3ef787d2012-04-12 10:51:47 +01004802 }
4803
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004804 bool allow_store_transition = IsTransitionElementsKind(from_kind);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004805 // Only store fast element maps in ascending generality.
4806 if (IsFastElementsKind(to_kind)) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004807 allow_store_transition =
4808 allow_store_transition && IsTransitionableFastElementsKind(from_kind) &&
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004809 IsMoreGeneralElementsKindTransition(from_kind, to_kind);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01004810 }
4811
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004812 if (!allow_store_transition) {
4813 return Map::CopyAsElementsKind(map, to_kind, OMIT_TRANSITION);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01004814 }
4815
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004816 return Map::AsElementsKind(map, to_kind);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01004817}
4818
4819
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004820// static
4821Handle<Map> Map::AsElementsKind(Handle<Map> map, ElementsKind kind) {
4822 Handle<Map> closest_map(FindClosestElementsTransition(*map, kind));
Ben Murdoch3ef787d2012-04-12 10:51:47 +01004823
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004824 if (closest_map->elements_kind() == kind) {
4825 return closest_map;
Ben Murdoch3ef787d2012-04-12 10:51:47 +01004826 }
4827
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004828 return AddMissingElementsTransitions(closest_map, kind);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01004829}
4830
4831
4832Handle<Map> JSObject::GetElementsTransitionMap(Handle<JSObject> object,
4833 ElementsKind to_kind) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004834 Handle<Map> map(object->map());
4835 return Map::TransitionElementsTo(map, to_kind);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01004836}
4837
4838
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004839void JSProxy::Revoke(Handle<JSProxy> proxy) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004840 Isolate* isolate = proxy->GetIsolate();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004841 if (!proxy->IsRevoked()) proxy->set_handler(isolate->heap()->null_value());
4842 DCHECK(proxy->IsRevoked());
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00004843}
4844
4845
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004846Maybe<bool> JSProxy::HasProperty(Isolate* isolate, Handle<JSProxy> proxy,
4847 Handle<Name> name) {
4848 DCHECK(!name->IsPrivate());
4849 STACK_CHECK(Nothing<bool>());
4850 // 1. (Assert)
4851 // 2. Let handler be the value of the [[ProxyHandler]] internal slot of O.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004852 Handle<Object> handler(proxy->handler(), isolate);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004853 // 3. If handler is null, throw a TypeError exception.
4854 // 4. Assert: Type(handler) is Object.
4855 if (proxy->IsRevoked()) {
4856 isolate->Throw(*isolate->factory()->NewTypeError(
4857 MessageTemplate::kProxyRevoked, isolate->factory()->has_string()));
4858 return Nothing<bool>();
4859 }
4860 // 5. Let target be the value of the [[ProxyTarget]] internal slot of O.
4861 Handle<JSReceiver> target(proxy->target(), isolate);
4862 // 6. Let trap be ? GetMethod(handler, "has").
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004863 Handle<Object> trap;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004864 ASSIGN_RETURN_ON_EXCEPTION_VALUE(
4865 isolate, trap, Object::GetMethod(Handle<JSReceiver>::cast(handler),
4866 isolate->factory()->has_string()),
4867 Nothing<bool>());
4868 // 7. If trap is undefined, then
Ben Murdoch3ef787d2012-04-12 10:51:47 +01004869 if (trap->IsUndefined()) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004870 // 7a. Return target.[[HasProperty]](P).
4871 return JSReceiver::HasProperty(target, name);
4872 }
4873 // 8. Let booleanTrapResult be ToBoolean(? Call(trap, handler, «target, P»)).
4874 Handle<Object> trap_result_obj;
4875 Handle<Object> args[] = {target, name};
4876 ASSIGN_RETURN_ON_EXCEPTION_VALUE(
4877 isolate, trap_result_obj,
4878 Execution::Call(isolate, trap, handler, arraysize(args), args),
4879 Nothing<bool>());
4880 bool boolean_trap_result = trap_result_obj->BooleanValue();
4881 // 9. If booleanTrapResult is false, then:
4882 if (!boolean_trap_result) {
4883 // 9a. Let targetDesc be ? target.[[GetOwnProperty]](P).
4884 PropertyDescriptor target_desc;
4885 Maybe<bool> target_found = JSReceiver::GetOwnPropertyDescriptor(
4886 isolate, target, name, &target_desc);
4887 MAYBE_RETURN(target_found, Nothing<bool>());
4888 // 9b. If targetDesc is not undefined, then:
4889 if (target_found.FromJust()) {
4890 // 9b i. If targetDesc.[[Configurable]] is false, throw a TypeError
4891 // exception.
4892 if (!target_desc.configurable()) {
4893 isolate->Throw(*isolate->factory()->NewTypeError(
4894 MessageTemplate::kProxyHasNonConfigurable, name));
4895 return Nothing<bool>();
4896 }
4897 // 9b ii. Let extensibleTarget be ? IsExtensible(target).
4898 Maybe<bool> extensible_target = JSReceiver::IsExtensible(target);
4899 MAYBE_RETURN(extensible_target, Nothing<bool>());
4900 // 9b iii. If extensibleTarget is false, throw a TypeError exception.
4901 if (!extensible_target.FromJust()) {
4902 isolate->Throw(*isolate->factory()->NewTypeError(
4903 MessageTemplate::kProxyHasNonExtensible, name));
4904 return Nothing<bool>();
4905 }
Ben Murdoch3ef787d2012-04-12 10:51:47 +01004906 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004907 }
4908 // 10. Return booleanTrapResult.
4909 return Just(boolean_trap_result);
4910}
4911
4912
4913Maybe<bool> JSProxy::SetProperty(Handle<JSProxy> proxy, Handle<Name> name,
4914 Handle<Object> value, Handle<Object> receiver,
4915 LanguageMode language_mode) {
4916 DCHECK(!name->IsPrivate());
4917 Isolate* isolate = proxy->GetIsolate();
4918 STACK_CHECK(Nothing<bool>());
4919 Factory* factory = isolate->factory();
4920 Handle<String> trap_name = factory->set_string();
4921 ShouldThrow should_throw =
4922 is_sloppy(language_mode) ? DONT_THROW : THROW_ON_ERROR;
4923
4924 if (proxy->IsRevoked()) {
4925 isolate->Throw(
4926 *factory->NewTypeError(MessageTemplate::kProxyRevoked, trap_name));
4927 return Nothing<bool>();
4928 }
4929 Handle<JSReceiver> target(proxy->target(), isolate);
4930 Handle<JSReceiver> handler(JSReceiver::cast(proxy->handler()), isolate);
4931
4932 Handle<Object> trap;
4933 ASSIGN_RETURN_ON_EXCEPTION_VALUE(
4934 isolate, trap, Object::GetMethod(handler, trap_name), Nothing<bool>());
4935 if (trap->IsUndefined()) {
4936 LookupIterator it =
4937 LookupIterator::PropertyOrElement(isolate, receiver, name, target);
4938 return Object::SetSuperProperty(&it, value, language_mode,
4939 Object::MAY_BE_STORE_FROM_KEYED);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01004940 }
4941
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004942 Handle<Object> trap_result;
4943 Handle<Object> args[] = {target, name, value, receiver};
4944 ASSIGN_RETURN_ON_EXCEPTION_VALUE(
4945 isolate, trap_result,
4946 Execution::Call(isolate, trap, handler, arraysize(args), args),
4947 Nothing<bool>());
4948 if (!trap_result->BooleanValue()) {
4949 RETURN_FAILURE(isolate, should_throw,
4950 NewTypeError(MessageTemplate::kProxyTrapReturnedFalsishFor,
4951 trap_name, name));
4952 }
4953
4954 // Enforce the invariant.
4955 PropertyDescriptor target_desc;
4956 Maybe<bool> owned =
4957 JSReceiver::GetOwnPropertyDescriptor(isolate, target, name, &target_desc);
4958 MAYBE_RETURN(owned, Nothing<bool>());
4959 if (owned.FromJust()) {
4960 bool inconsistent = PropertyDescriptor::IsDataDescriptor(&target_desc) &&
4961 !target_desc.configurable() &&
4962 !target_desc.writable() &&
4963 !value->SameValue(*target_desc.value());
4964 if (inconsistent) {
4965 isolate->Throw(*isolate->factory()->NewTypeError(
4966 MessageTemplate::kProxySetFrozenData, name));
4967 return Nothing<bool>();
4968 }
4969 inconsistent = PropertyDescriptor::IsAccessorDescriptor(&target_desc) &&
4970 !target_desc.configurable() &&
4971 target_desc.set()->IsUndefined();
4972 if (inconsistent) {
4973 isolate->Throw(*isolate->factory()->NewTypeError(
4974 MessageTemplate::kProxySetFrozenAccessor, name));
4975 return Nothing<bool>();
4976 }
4977 }
4978 return Just(true);
4979}
4980
4981
4982Maybe<bool> JSProxy::DeletePropertyOrElement(Handle<JSProxy> proxy,
4983 Handle<Name> name,
4984 LanguageMode language_mode) {
4985 DCHECK(!name->IsPrivate());
4986 ShouldThrow should_throw =
4987 is_sloppy(language_mode) ? DONT_THROW : THROW_ON_ERROR;
4988 Isolate* isolate = proxy->GetIsolate();
4989 STACK_CHECK(Nothing<bool>());
4990 Factory* factory = isolate->factory();
4991 Handle<String> trap_name = factory->deleteProperty_string();
4992
4993 if (proxy->IsRevoked()) {
4994 isolate->Throw(
4995 *factory->NewTypeError(MessageTemplate::kProxyRevoked, trap_name));
4996 return Nothing<bool>();
4997 }
4998 Handle<JSReceiver> target(proxy->target(), isolate);
4999 Handle<JSReceiver> handler(JSReceiver::cast(proxy->handler()), isolate);
5000
5001 Handle<Object> trap;
5002 ASSIGN_RETURN_ON_EXCEPTION_VALUE(
5003 isolate, trap, Object::GetMethod(handler, trap_name), Nothing<bool>());
5004 if (trap->IsUndefined()) {
5005 return JSReceiver::DeletePropertyOrElement(target, name, language_mode);
5006 }
5007
5008 Handle<Object> trap_result;
5009 Handle<Object> args[] = {target, name};
5010 ASSIGN_RETURN_ON_EXCEPTION_VALUE(
5011 isolate, trap_result,
5012 Execution::Call(isolate, trap, handler, arraysize(args), args),
5013 Nothing<bool>());
5014 if (!trap_result->BooleanValue()) {
5015 RETURN_FAILURE(isolate, should_throw,
5016 NewTypeError(MessageTemplate::kProxyTrapReturnedFalsishFor,
5017 trap_name, name));
5018 }
5019
5020 // Enforce the invariant.
5021 PropertyDescriptor target_desc;
5022 Maybe<bool> owned =
5023 JSReceiver::GetOwnPropertyDescriptor(isolate, target, name, &target_desc);
5024 MAYBE_RETURN(owned, Nothing<bool>());
5025 if (owned.FromJust() && !target_desc.configurable()) {
5026 isolate->Throw(*factory->NewTypeError(
5027 MessageTemplate::kProxyDeletePropertyNonConfigurable, name));
5028 return Nothing<bool>();
5029 }
5030 return Just(true);
5031}
5032
5033
5034// static
5035MaybeHandle<JSProxy> JSProxy::New(Isolate* isolate, Handle<Object> target,
5036 Handle<Object> handler) {
5037 if (!target->IsJSReceiver()) {
5038 THROW_NEW_ERROR(isolate, NewTypeError(MessageTemplate::kProxyNonObject),
5039 JSProxy);
5040 }
5041 if (target->IsJSProxy() && JSProxy::cast(*target)->IsRevoked()) {
5042 THROW_NEW_ERROR(isolate,
5043 NewTypeError(MessageTemplate::kProxyHandlerOrTargetRevoked),
5044 JSProxy);
5045 }
5046 if (!handler->IsJSReceiver()) {
5047 THROW_NEW_ERROR(isolate, NewTypeError(MessageTemplate::kProxyNonObject),
5048 JSProxy);
5049 }
5050 if (handler->IsJSProxy() && JSProxy::cast(*handler)->IsRevoked()) {
5051 THROW_NEW_ERROR(isolate,
5052 NewTypeError(MessageTemplate::kProxyHandlerOrTargetRevoked),
5053 JSProxy);
5054 }
5055 return isolate->factory()->NewJSProxy(Handle<JSReceiver>::cast(target),
5056 Handle<JSReceiver>::cast(handler));
5057}
5058
5059
5060// static
5061MaybeHandle<Context> JSProxy::GetFunctionRealm(Handle<JSProxy> proxy) {
5062 DCHECK(proxy->map()->is_constructor());
5063 if (proxy->IsRevoked()) {
5064 THROW_NEW_ERROR(proxy->GetIsolate(),
5065 NewTypeError(MessageTemplate::kProxyRevoked), Context);
5066 }
5067 Handle<JSReceiver> target(JSReceiver::cast(proxy->target()));
5068 return JSReceiver::GetFunctionRealm(target);
5069}
5070
5071
5072// static
5073MaybeHandle<Context> JSBoundFunction::GetFunctionRealm(
5074 Handle<JSBoundFunction> function) {
5075 DCHECK(function->map()->is_constructor());
5076 return JSReceiver::GetFunctionRealm(
5077 handle(function->bound_target_function()));
5078}
5079
5080
5081// static
5082Handle<Context> JSFunction::GetFunctionRealm(Handle<JSFunction> function) {
5083 DCHECK(function->map()->is_constructor());
5084 return handle(function->context()->native_context());
5085}
5086
5087
5088// static
5089MaybeHandle<Context> JSObject::GetFunctionRealm(Handle<JSObject> object) {
5090 DCHECK(object->map()->is_constructor());
5091 DCHECK(!object->IsJSFunction());
5092 return handle(object->GetCreationContext());
5093}
5094
5095
5096// static
5097MaybeHandle<Context> JSReceiver::GetFunctionRealm(Handle<JSReceiver> receiver) {
5098 if (receiver->IsJSProxy()) {
5099 return JSProxy::GetFunctionRealm(Handle<JSProxy>::cast(receiver));
5100 }
5101
5102 if (receiver->IsJSFunction()) {
5103 return JSFunction::GetFunctionRealm(Handle<JSFunction>::cast(receiver));
5104 }
5105
5106 if (receiver->IsJSBoundFunction()) {
5107 return JSBoundFunction::GetFunctionRealm(
5108 Handle<JSBoundFunction>::cast(receiver));
5109 }
5110
5111 return JSObject::GetFunctionRealm(Handle<JSObject>::cast(receiver));
5112}
5113
5114
5115Maybe<PropertyAttributes> JSProxy::GetPropertyAttributes(LookupIterator* it) {
5116 Isolate* isolate = it->isolate();
5117 HandleScope scope(isolate);
5118 PropertyDescriptor desc;
5119 Maybe<bool> found = JSProxy::GetOwnPropertyDescriptor(
5120 isolate, it->GetHolder<JSProxy>(), it->GetName(), &desc);
5121 MAYBE_RETURN(found, Nothing<PropertyAttributes>());
5122 if (!found.FromJust()) return Just(ABSENT);
5123 return Just(desc.ToAttributes());
Ben Murdoch3ef787d2012-04-12 10:51:47 +01005124}
5125
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00005126
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005127void JSObject::AllocateStorageForMap(Handle<JSObject> object, Handle<Map> map) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00005128 DCHECK(object->map()->GetInObjectProperties() ==
5129 map->GetInObjectProperties());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005130 ElementsKind obj_kind = object->map()->elements_kind();
5131 ElementsKind map_kind = map->elements_kind();
5132 if (map_kind != obj_kind) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00005133 ElementsKind to_kind = GetMoreGeneralElementsKind(map_kind, obj_kind);
5134 if (IsDictionaryElementsKind(obj_kind)) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005135 to_kind = obj_kind;
John Reck59135872010-11-02 12:39:01 -07005136 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005137 if (IsDictionaryElementsKind(to_kind)) {
5138 NormalizeElements(object);
Ben Murdoche0cee9b2011-05-25 10:26:03 +01005139 } else {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005140 TransitionElementsKind(object, to_kind);
Ben Murdoche0cee9b2011-05-25 10:26:03 +01005141 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005142 map = Map::AsElementsKind(map, to_kind);
Ben Murdoche0cee9b2011-05-25 10:26:03 +01005143 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005144 JSObject::MigrateToMap(object, map);
5145}
5146
5147
5148void JSObject::MigrateInstance(Handle<JSObject> object) {
5149 Handle<Map> original_map(object->map());
5150 Handle<Map> map = Map::Update(original_map);
5151 map->set_migration_target(true);
5152 MigrateToMap(object, map);
5153 if (FLAG_trace_migration) {
5154 object->PrintInstanceMigration(stdout, *original_map, *map);
5155 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00005156#if VERIFY_HEAP
5157 if (FLAG_verify_heap) {
5158 object->JSObjectVerify();
5159 }
5160#endif
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005161}
5162
5163
5164// static
5165bool JSObject::TryMigrateInstance(Handle<JSObject> object) {
5166 Isolate* isolate = object->GetIsolate();
5167 DisallowDeoptimization no_deoptimization(isolate);
5168 Handle<Map> original_map(object->map(), isolate);
5169 Handle<Map> new_map;
5170 if (!Map::TryUpdate(original_map).ToHandle(&new_map)) {
5171 return false;
5172 }
5173 JSObject::MigrateToMap(object, new_map);
5174 if (FLAG_trace_migration) {
5175 object->PrintInstanceMigration(stdout, *original_map, object->map());
5176 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00005177#if VERIFY_HEAP
5178 if (FLAG_verify_heap) {
5179 object->JSObjectVerify();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005180 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00005181#endif
5182 return true;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005183}
5184
5185
5186void JSObject::AddProperty(Handle<JSObject> object, Handle<Name> name,
5187 Handle<Object> value,
5188 PropertyAttributes attributes) {
5189 LookupIterator it(object, name, LookupIterator::OWN_SKIP_INTERCEPTOR);
5190 CHECK_NE(LookupIterator::ACCESS_CHECK, it.state());
5191#ifdef DEBUG
5192 uint32_t index;
5193 DCHECK(!object->IsJSProxy());
5194 DCHECK(!name->AsArrayIndex(&index));
5195 Maybe<PropertyAttributes> maybe = GetPropertyAttributes(&it);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00005196 DCHECK(maybe.IsJust());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005197 DCHECK(!it.IsFound());
5198 DCHECK(object->map()->is_extensible() ||
Emily Bernierd0a1eb72015-03-24 16:35:39 -04005199 it.isolate()->IsInternallyUsedPropertyName(name));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005200#endif
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00005201 CHECK(AddDataProperty(&it, value, attributes, THROW_ON_ERROR,
5202 CERTAINLY_NOT_STORE_FROM_KEYED)
5203 .IsJust());
5204}
5205
5206
5207// static
5208void ExecutableAccessorInfo::ClearSetter(Handle<ExecutableAccessorInfo> info) {
5209 Handle<Object> object = v8::FromCData(info->GetIsolate(), nullptr);
5210 info->set_setter(*object);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005211}
5212
5213
5214// Reconfigures a property to a data property with attributes, even if it is not
5215// reconfigurable.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00005216// Requires a LookupIterator that does not look at the prototype chain beyond
5217// hidden prototypes.
5218MaybeHandle<Object> JSObject::DefineOwnPropertyIgnoreAttributes(
5219 LookupIterator* it, Handle<Object> value, PropertyAttributes attributes,
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005220 ExecutableAccessorInfoHandling handling) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00005221 MAYBE_RETURN_NULL(DefineOwnPropertyIgnoreAttributes(
5222 it, value, attributes, THROW_ON_ERROR, handling));
5223 return value;
5224}
5225
5226
5227Maybe<bool> JSObject::DefineOwnPropertyIgnoreAttributes(
5228 LookupIterator* it, Handle<Object> value, PropertyAttributes attributes,
5229 ShouldThrow should_throw, ExecutableAccessorInfoHandling handling) {
5230 Handle<JSObject> object = Handle<JSObject>::cast(it->GetReceiver());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005231 bool is_observed = object->map()->is_observed() &&
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00005232 (it->IsElement() ||
5233 !it->isolate()->IsInternallyUsedPropertyName(it->name()));
5234
5235 for (; it->IsFound(); it->Next()) {
5236 switch (it->state()) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005237 case LookupIterator::JSPROXY:
5238 case LookupIterator::NOT_FOUND:
5239 case LookupIterator::TRANSITION:
5240 UNREACHABLE();
5241
5242 case LookupIterator::ACCESS_CHECK:
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00005243 if (!it->HasAccess()) {
5244 it->isolate()->ReportFailedAccessCheck(it->GetHolder<JSObject>());
5245 RETURN_VALUE_IF_SCHEDULED_EXCEPTION(it->isolate(), Nothing<bool>());
5246 return Just(true);
5247 }
5248 break;
5249
5250 // If there's an interceptor, try to store the property with the
5251 // interceptor.
5252 // In case of success, the attributes will have been reset to the default
5253 // attributes of the interceptor, rather than the incoming attributes.
5254 //
5255 // TODO(verwaest): JSProxy afterwards verify the attributes that the
5256 // JSProxy claims it has, and verifies that they are compatible. If not,
5257 // they throw. Here we should do the same.
5258 case LookupIterator::INTERCEPTOR:
5259 if (handling == DONT_FORCE_FIELD) {
5260 Maybe<bool> result = JSObject::SetPropertyWithInterceptor(it, value);
5261 if (result.IsNothing() || result.FromJust()) return result;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005262 }
5263 break;
5264
5265 case LookupIterator::ACCESSOR: {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00005266 Handle<Object> accessors = it->GetAccessors();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005267
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005268 // Special handling for ExecutableAccessorInfo, which behaves like a
5269 // data property.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00005270 if (accessors->IsExecutableAccessorInfo() &&
5271 handling == DONT_FORCE_FIELD) {
5272 PropertyDetails details = it->property_details();
5273 // Ensure the context isn't changed after calling into accessors.
5274 AssertNoContextChange ncc(it->isolate());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005275
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00005276 Maybe<bool> result =
5277 JSObject::SetPropertyWithAccessor(it, value, should_throw);
5278 if (result.IsNothing() || !result.FromJust()) return result;
5279
5280 if (details.attributes() == attributes) return Just(true);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005281
5282 // Reconfigure the accessor if attributes mismatch.
5283 Handle<ExecutableAccessorInfo> new_data = Accessors::CloneAccessor(
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00005284 it->isolate(), Handle<ExecutableAccessorInfo>::cast(accessors));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005285 new_data->set_property_attributes(attributes);
5286 // By clearing the setter we don't have to introduce a lookup to
5287 // the setter, simply make it unavailable to reflect the
5288 // attributes.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00005289 if (attributes & READ_ONLY) {
5290 ExecutableAccessorInfo::ClearSetter(new_data);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005291 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005292
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00005293 it->TransitionToAccessorPair(new_data, attributes);
5294 } else {
5295 it->ReconfigureDataProperty(value, attributes);
5296 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005297
5298 if (is_observed) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00005299 RETURN_ON_EXCEPTION_VALUE(
5300 it->isolate(),
5301 EnqueueChangeRecord(object, "reconfigure", it->GetName(),
5302 it->factory()->the_hole_value()),
5303 Nothing<bool>());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005304 }
5305
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00005306 return Just(true);
Iain Merrick75681382010-08-19 15:07:18 +01005307 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00005308 case LookupIterator::INTEGER_INDEXED_EXOTIC:
5309 return RedefineIncompatibleProperty(it->isolate(), it->GetName(), value,
5310 should_throw);
Steve Blocka7e24c12009-10-30 11:49:00 +00005311
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005312 case LookupIterator::DATA: {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00005313 PropertyDetails details = it->property_details();
5314 Handle<Object> old_value = it->factory()->the_hole_value();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005315 // Regular property update if the attributes match.
5316 if (details.attributes() == attributes) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00005317 return SetDataProperty(it, value);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005318 }
Steve Blocka7e24c12009-10-30 11:49:00 +00005319
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00005320 // Special case: properties of typed arrays cannot be reconfigured to
5321 // non-writable nor to non-enumerable.
5322 if (it->IsElement() && object->HasFixedTypedArrayElements()) {
5323 return RedefineIncompatibleProperty(it->isolate(), it->GetName(),
5324 value, should_throw);
5325 }
5326
5327 // Reconfigure the data property if the attributes mismatch.
5328 if (is_observed) old_value = it->GetDataValue();
5329
5330 it->ReconfigureDataProperty(value, attributes);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01005331
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005332 if (is_observed) {
5333 if (old_value->SameValue(*value)) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00005334 old_value = it->factory()->the_hole_value();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005335 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00005336 RETURN_ON_EXCEPTION_VALUE(
5337 it->isolate(), EnqueueChangeRecord(object, "reconfigure",
5338 it->GetName(), old_value),
5339 Nothing<bool>());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005340 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00005341 return Just(true);
Steve Blocka7e24c12009-10-30 11:49:00 +00005342 }
Steve Blocka7e24c12009-10-30 11:49:00 +00005343 }
5344 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005345
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00005346 return AddDataProperty(it, value, attributes, should_throw,
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005347 CERTAINLY_NOT_STORE_FROM_KEYED);
Steve Blocka7e24c12009-10-30 11:49:00 +00005348}
5349
5350
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00005351MaybeHandle<Object> JSObject::SetOwnPropertyIgnoreAttributes(
5352 Handle<JSObject> object, Handle<Name> name, Handle<Object> value,
5353 PropertyAttributes attributes, ExecutableAccessorInfoHandling handling) {
5354 DCHECK(!value->IsTheHole());
5355 LookupIterator it(object, name, LookupIterator::OWN);
5356 return DefineOwnPropertyIgnoreAttributes(&it, value, attributes, handling);
Steve Blocka7e24c12009-10-30 11:49:00 +00005357}
5358
5359
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00005360MaybeHandle<Object> JSObject::SetOwnElementIgnoreAttributes(
5361 Handle<JSObject> object, uint32_t index, Handle<Object> value,
5362 PropertyAttributes attributes, ExecutableAccessorInfoHandling handling) {
5363 Isolate* isolate = object->GetIsolate();
5364 LookupIterator it(isolate, object, index, LookupIterator::OWN);
5365 return DefineOwnPropertyIgnoreAttributes(&it, value, attributes, handling);
5366}
5367
5368
5369MaybeHandle<Object> JSObject::DefinePropertyOrElementIgnoreAttributes(
5370 Handle<JSObject> object, Handle<Name> name, Handle<Object> value,
5371 PropertyAttributes attributes, ExecutableAccessorInfoHandling handling) {
5372 Isolate* isolate = object->GetIsolate();
5373 LookupIterator it = LookupIterator::PropertyOrElement(isolate, object, name,
5374 LookupIterator::OWN);
5375 return DefineOwnPropertyIgnoreAttributes(&it, value, attributes, handling);
5376}
5377
5378
5379Maybe<PropertyAttributes> JSObject::GetPropertyAttributesWithInterceptor(
5380 LookupIterator* it) {
5381 Isolate* isolate = it->isolate();
5382 // Make sure that the top context does not change when doing
5383 // callbacks or interceptor calls.
5384 AssertNoContextChange ncc(isolate);
5385 HandleScope scope(isolate);
5386
5387 Handle<JSObject> holder = it->GetHolder<JSObject>();
5388 Handle<InterceptorInfo> interceptor(it->GetInterceptor());
5389 if (!it->IsElement() && it->name()->IsSymbol() &&
5390 !interceptor->can_intercept_symbols()) {
5391 return Just(ABSENT);
Steve Blocka7e24c12009-10-30 11:49:00 +00005392 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00005393 PropertyCallbackArguments args(isolate, interceptor->data(),
5394 *it->GetReceiver(), *holder);
5395 if (!interceptor->query()->IsUndefined()) {
5396 v8::Local<v8::Integer> result;
5397 if (it->IsElement()) {
5398 uint32_t index = it->index();
5399 v8::IndexedPropertyQueryCallback query =
5400 v8::ToCData<v8::IndexedPropertyQueryCallback>(interceptor->query());
5401 LOG(isolate,
5402 ApiIndexedPropertyAccess("interceptor-indexed-has", *holder, index));
5403 result = args.Call(query, index);
5404 } else {
5405 Handle<Name> name = it->name();
5406 DCHECK(!name->IsPrivate());
5407 v8::GenericNamedPropertyQueryCallback query =
5408 v8::ToCData<v8::GenericNamedPropertyQueryCallback>(
5409 interceptor->query());
5410 LOG(isolate,
5411 ApiNamedPropertyAccess("interceptor-named-has", *holder, *name));
5412 result = args.Call(query, v8::Utils::ToLocal(name));
5413 }
5414 if (!result.IsEmpty()) {
5415 DCHECK(result->IsInt32());
5416 return Just(static_cast<PropertyAttributes>(
5417 result->Int32Value(reinterpret_cast<v8::Isolate*>(isolate)
5418 ->GetCurrentContext()).FromJust()));
5419 }
5420 } else if (!interceptor->getter()->IsUndefined()) {
5421 // TODO(verwaest): Use GetPropertyWithInterceptor?
5422 v8::Local<v8::Value> result;
5423 if (it->IsElement()) {
5424 uint32_t index = it->index();
5425 v8::IndexedPropertyGetterCallback getter =
5426 v8::ToCData<v8::IndexedPropertyGetterCallback>(interceptor->getter());
5427 LOG(isolate, ApiIndexedPropertyAccess("interceptor-indexed-get-has",
5428 *holder, index));
5429 result = args.Call(getter, index);
5430 } else {
5431 Handle<Name> name = it->name();
5432 DCHECK(!name->IsPrivate());
5433 v8::GenericNamedPropertyGetterCallback getter =
5434 v8::ToCData<v8::GenericNamedPropertyGetterCallback>(
5435 interceptor->getter());
5436 LOG(isolate,
5437 ApiNamedPropertyAccess("interceptor-named-get-has", *holder, *name));
5438 result = args.Call(getter, v8::Utils::ToLocal(name));
5439 }
5440 if (!result.IsEmpty()) return Just(DONT_ENUM);
5441 }
5442
5443 RETURN_VALUE_IF_SCHEDULED_EXCEPTION(isolate, Nothing<PropertyAttributes>());
5444 return Just(ABSENT);
Steve Blocka7e24c12009-10-30 11:49:00 +00005445}
5446
5447
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005448Maybe<PropertyAttributes> JSReceiver::GetPropertyAttributes(
5449 LookupIterator* it) {
5450 for (; it->IsFound(); it->Next()) {
5451 switch (it->state()) {
5452 case LookupIterator::NOT_FOUND:
5453 case LookupIterator::TRANSITION:
5454 UNREACHABLE();
5455 case LookupIterator::JSPROXY:
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00005456 return JSProxy::GetPropertyAttributes(it);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005457 case LookupIterator::INTERCEPTOR: {
5458 Maybe<PropertyAttributes> result =
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00005459 JSObject::GetPropertyAttributesWithInterceptor(it);
5460 if (!result.IsJust()) return result;
5461 if (result.FromJust() != ABSENT) return result;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005462 break;
Kristian Monsen80d68ea2010-09-08 11:05:35 +01005463 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005464 case LookupIterator::ACCESS_CHECK:
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00005465 if (it->HasAccess()) break;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005466 return JSObject::GetPropertyAttributesWithFailedAccessCheck(it);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00005467 case LookupIterator::INTEGER_INDEXED_EXOTIC:
5468 return Just(ABSENT);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005469 case LookupIterator::ACCESSOR:
5470 case LookupIterator::DATA:
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00005471 return Just(it->property_details().attributes());
Kristian Monsen80d68ea2010-09-08 11:05:35 +01005472 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005473 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00005474 return Just(ABSENT);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005475}
5476
5477
5478Handle<NormalizedMapCache> NormalizedMapCache::New(Isolate* isolate) {
5479 Handle<FixedArray> array(
5480 isolate->factory()->NewFixedArray(kEntries, TENURED));
5481 return Handle<NormalizedMapCache>::cast(array);
5482}
5483
5484
5485MaybeHandle<Map> NormalizedMapCache::Get(Handle<Map> fast_map,
5486 PropertyNormalizationMode mode) {
5487 DisallowHeapAllocation no_gc;
5488 Object* value = FixedArray::get(GetIndex(fast_map));
5489 if (!value->IsMap() ||
5490 !Map::cast(value)->EquivalentToForNormalization(*fast_map, mode)) {
5491 return MaybeHandle<Map>();
5492 }
5493 return handle(Map::cast(value));
5494}
5495
5496
5497void NormalizedMapCache::Set(Handle<Map> fast_map,
5498 Handle<Map> normalized_map) {
5499 DisallowHeapAllocation no_gc;
5500 DCHECK(normalized_map->is_dictionary_map());
5501 FixedArray::set(GetIndex(fast_map), *normalized_map);
Kristian Monsen80d68ea2010-09-08 11:05:35 +01005502}
5503
5504
Kristian Monsen80d68ea2010-09-08 11:05:35 +01005505void NormalizedMapCache::Clear() {
5506 int entries = length();
5507 for (int i = 0; i != entries; i++) {
5508 set_undefined(i);
5509 }
5510}
5511
5512
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005513void HeapObject::UpdateMapCodeCache(Handle<HeapObject> object,
5514 Handle<Name> name,
5515 Handle<Code> code) {
5516 Handle<Map> map(object->map());
5517 Map::UpdateCodeCache(map, name, code);
Kristian Monsen80d68ea2010-09-08 11:05:35 +01005518}
5519
5520
Ben Murdoch3ef787d2012-04-12 10:51:47 +01005521void JSObject::NormalizeProperties(Handle<JSObject> object,
5522 PropertyNormalizationMode mode,
Emily Bernierd0a1eb72015-03-24 16:35:39 -04005523 int expected_additional_properties,
5524 const char* reason) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005525 if (!object->HasFastProperties()) return;
5526
5527 Handle<Map> map(object->map());
Emily Bernierd0a1eb72015-03-24 16:35:39 -04005528 Handle<Map> new_map = Map::Normalize(map, mode, reason);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005529
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00005530 MigrateToMap(object, new_map, expected_additional_properties);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01005531}
5532
5533
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005534void JSObject::MigrateFastToSlow(Handle<JSObject> object,
5535 Handle<Map> new_map,
5536 int expected_additional_properties) {
Steve Blocka7e24c12009-10-30 11:49:00 +00005537 // The global object is always normalized.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00005538 DCHECK(!object->IsJSGlobalObject());
Steve Block1e0659c2011-05-24 12:43:12 +01005539 // JSGlobalProxy must never be normalized
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005540 DCHECK(!object->IsJSGlobalProxy());
Steve Block1e0659c2011-05-24 12:43:12 +01005541
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005542 Isolate* isolate = object->GetIsolate();
5543 HandleScope scope(isolate);
5544 Handle<Map> map(object->map());
Steve Block44f0eee2011-05-26 01:26:41 +01005545
Steve Blocka7e24c12009-10-30 11:49:00 +00005546 // Allocate new content.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005547 int real_size = map->NumberOfOwnDescriptors();
5548 int property_count = real_size;
Steve Blocka7e24c12009-10-30 11:49:00 +00005549 if (expected_additional_properties > 0) {
5550 property_count += expected_additional_properties;
5551 } else {
5552 property_count += 2; // Make space for two more properties.
5553 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005554 Handle<NameDictionary> dictionary =
5555 NameDictionary::New(isolate, property_count);
Steve Blocka7e24c12009-10-30 11:49:00 +00005556
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005557 Handle<DescriptorArray> descs(map->instance_descriptors());
5558 for (int i = 0; i < real_size; i++) {
5559 PropertyDetails details = descs->GetDetails(i);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04005560 Handle<Name> key(descs->GetKey(i));
Steve Blocka7e24c12009-10-30 11:49:00 +00005561 switch (details.type()) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00005562 case DATA_CONSTANT: {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005563 Handle<Object> value(descs->GetConstant(i), isolate);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00005564 PropertyDetails d(details.attributes(), DATA, i + 1,
5565 PropertyCellType::kNoCell);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005566 dictionary = NameDictionary::Add(dictionary, key, value, d);
Steve Blocka7e24c12009-10-30 11:49:00 +00005567 break;
5568 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00005569 case DATA: {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005570 FieldIndex index = FieldIndex::ForDescriptor(*map, i);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04005571 Handle<Object> value;
5572 if (object->IsUnboxedDoubleField(index)) {
5573 double old_value = object->RawFastDoublePropertyAt(index);
5574 value = isolate->factory()->NewHeapNumber(old_value);
5575 } else {
5576 value = handle(object->RawFastPropertyAt(index), isolate);
5577 if (details.representation().IsDouble()) {
5578 DCHECK(value->IsMutableHeapNumber());
5579 Handle<HeapNumber> old = Handle<HeapNumber>::cast(value);
5580 value = isolate->factory()->NewHeapNumber(old->value());
5581 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005582 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00005583 PropertyDetails d(details.attributes(), DATA, i + 1,
5584 PropertyCellType::kNoCell);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04005585 dictionary = NameDictionary::Add(dictionary, key, value, d);
5586 break;
5587 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00005588 case ACCESSOR: {
Emily Bernierd0a1eb72015-03-24 16:35:39 -04005589 FieldIndex index = FieldIndex::ForDescriptor(*map, i);
5590 Handle<Object> value(object->RawFastPropertyAt(index), isolate);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00005591 PropertyDetails d(details.attributes(), ACCESSOR_CONSTANT, i + 1,
5592 PropertyCellType::kNoCell);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005593 dictionary = NameDictionary::Add(dictionary, key, value, d);
Steve Blocka7e24c12009-10-30 11:49:00 +00005594 break;
5595 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00005596 case ACCESSOR_CONSTANT: {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005597 Handle<Object> value(descs->GetCallbacksObject(i), isolate);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00005598 PropertyDetails d(details.attributes(), ACCESSOR_CONSTANT, i + 1,
5599 PropertyCellType::kNoCell);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005600 dictionary = NameDictionary::Add(dictionary, key, value, d);
Steve Blocka7e24c12009-10-30 11:49:00 +00005601 break;
5602 }
Steve Blocka7e24c12009-10-30 11:49:00 +00005603 }
5604 }
5605
5606 // Copy the next enumeration index from instance descriptor.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005607 dictionary->SetNextEnumerationIndex(real_size + 1);
Steve Blocka7e24c12009-10-30 11:49:00 +00005608
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005609 // From here on we cannot fail and we shouldn't GC anymore.
5610 DisallowHeapAllocation no_allocation;
Kristian Monsen80d68ea2010-09-08 11:05:35 +01005611
5612 // Resize the object in the heap if necessary.
5613 int new_instance_size = new_map->instance_size();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005614 int instance_size_delta = map->instance_size() - new_instance_size;
5615 DCHECK(instance_size_delta >= 0);
5616
5617 if (instance_size_delta > 0) {
5618 Heap* heap = isolate->heap();
5619 heap->CreateFillerObjectAt(object->address() + new_instance_size,
5620 instance_size_delta);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00005621 heap->AdjustLiveBytes(*object, -instance_size_delta,
5622 Heap::CONCURRENT_TO_SWEEPER);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01005623 }
5624
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005625 // We are storing the new map using release store after creating a filler for
5626 // the left-over space to avoid races with the sweeper thread.
5627 object->synchronized_set_map(*new_map);
Kristian Monsen80d68ea2010-09-08 11:05:35 +01005628
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005629 object->set_properties(*dictionary);
Steve Blocka7e24c12009-10-30 11:49:00 +00005630
Emily Bernierd0a1eb72015-03-24 16:35:39 -04005631 // Ensure that in-object space of slow-mode object does not contain random
5632 // garbage.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00005633 int inobject_properties = new_map->GetInObjectProperties();
Emily Bernierd0a1eb72015-03-24 16:35:39 -04005634 for (int i = 0; i < inobject_properties; i++) {
5635 FieldIndex index = FieldIndex::ForPropertyIndex(*new_map, i);
5636 object->RawFastPropertyAtPut(index, Smi::FromInt(0));
5637 }
5638
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005639 isolate->counters()->props_to_dictionary()->Increment();
Steve Blocka7e24c12009-10-30 11:49:00 +00005640
5641#ifdef DEBUG
5642 if (FLAG_trace_normalization) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005643 OFStream os(stdout);
5644 os << "Object properties have been normalized:\n";
5645 object->Print(os);
Steve Blocka7e24c12009-10-30 11:49:00 +00005646 }
5647#endif
Steve Blocka7e24c12009-10-30 11:49:00 +00005648}
5649
5650
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005651void JSObject::MigrateSlowToFast(Handle<JSObject> object,
Emily Bernierd0a1eb72015-03-24 16:35:39 -04005652 int unused_property_fields,
5653 const char* reason) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005654 if (object->HasFastProperties()) return;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00005655 DCHECK(!object->IsJSGlobalObject());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005656 Isolate* isolate = object->GetIsolate();
5657 Factory* factory = isolate->factory();
5658 Handle<NameDictionary> dictionary(object->property_dictionary());
5659
5660 // Make sure we preserve dictionary representation if there are too many
5661 // descriptors.
5662 int number_of_elements = dictionary->NumberOfElements();
5663 if (number_of_elements > kMaxNumberOfDescriptors) return;
5664
Emily Bernierd0a1eb72015-03-24 16:35:39 -04005665 Handle<FixedArray> iteration_order;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005666 if (number_of_elements != dictionary->NextEnumerationIndex()) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -04005667 iteration_order =
5668 NameDictionary::DoGenerateNewEnumerationIndices(dictionary);
5669 } else {
5670 iteration_order = NameDictionary::BuildIterationIndicesArray(dictionary);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005671 }
5672
Emily Bernierd0a1eb72015-03-24 16:35:39 -04005673 int instance_descriptor_length = iteration_order->length();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005674 int number_of_fields = 0;
5675
5676 // Compute the length of the instance descriptor.
Emily Bernierd0a1eb72015-03-24 16:35:39 -04005677 for (int i = 0; i < instance_descriptor_length; i++) {
5678 int index = Smi::cast(iteration_order->get(i))->value();
5679 DCHECK(dictionary->IsKey(dictionary->KeyAt(index)));
5680
5681 Object* value = dictionary->ValueAt(index);
5682 PropertyType type = dictionary->DetailsAt(index).type();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00005683 if (type == DATA && !value->IsJSFunction()) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -04005684 number_of_fields += 1;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005685 }
5686 }
5687
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00005688 Handle<Map> old_map(object->map(), isolate);
5689
5690 int inobject_props = old_map->GetInObjectProperties();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005691
5692 // Allocate new map.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00005693 Handle<Map> new_map = Map::CopyDropDescriptors(old_map);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005694 new_map->set_dictionary_map(false);
5695
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00005696 UpdatePrototypeUserRegistration(old_map, new_map, isolate);
5697
Emily Bernierd0a1eb72015-03-24 16:35:39 -04005698#if TRACE_MAPS
5699 if (FLAG_trace_maps) {
5700 PrintF("[TraceMaps: SlowToFast from= %p to= %p reason= %s ]\n",
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00005701 reinterpret_cast<void*>(*old_map), reinterpret_cast<void*>(*new_map),
5702 reason);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04005703 }
5704#endif
5705
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005706 if (instance_descriptor_length == 0) {
5707 DisallowHeapAllocation no_gc;
5708 DCHECK_LE(unused_property_fields, inobject_props);
5709 // Transform the object.
5710 new_map->set_unused_property_fields(inobject_props);
5711 object->synchronized_set_map(*new_map);
5712 object->set_properties(isolate->heap()->empty_fixed_array());
5713 // Check that it really works.
5714 DCHECK(object->HasFastProperties());
5715 return;
5716 }
5717
5718 // Allocate the instance descriptor.
5719 Handle<DescriptorArray> descriptors = DescriptorArray::Allocate(
5720 isolate, instance_descriptor_length);
5721
5722 int number_of_allocated_fields =
5723 number_of_fields + unused_property_fields - inobject_props;
5724 if (number_of_allocated_fields < 0) {
5725 // There is enough inobject space for all fields (including unused).
5726 number_of_allocated_fields = 0;
5727 unused_property_fields = inobject_props - number_of_fields;
5728 }
5729
5730 // Allocate the fixed array for the fields.
5731 Handle<FixedArray> fields = factory->NewFixedArray(
5732 number_of_allocated_fields);
5733
5734 // Fill in the instance descriptor and the fields.
5735 int current_offset = 0;
Emily Bernierd0a1eb72015-03-24 16:35:39 -04005736 for (int i = 0; i < instance_descriptor_length; i++) {
5737 int index = Smi::cast(iteration_order->get(i))->value();
5738 Object* k = dictionary->KeyAt(index);
5739 DCHECK(dictionary->IsKey(k));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00005740 // Dictionary keys are internalized upon insertion.
5741 // TODO(jkummerow): Turn this into a DCHECK if it's not hit in the wild.
5742 CHECK(k->IsUniqueName());
5743 Handle<Name> key(Name::cast(k), isolate);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005744
Emily Bernierd0a1eb72015-03-24 16:35:39 -04005745 Object* value = dictionary->ValueAt(index);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005746
Emily Bernierd0a1eb72015-03-24 16:35:39 -04005747 PropertyDetails details = dictionary->DetailsAt(index);
5748 int enumeration_index = details.dictionary_index();
5749 PropertyType type = details.type();
5750
5751 if (value->IsJSFunction()) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00005752 DataConstantDescriptor d(key, handle(value, isolate),
5753 details.attributes());
Emily Bernierd0a1eb72015-03-24 16:35:39 -04005754 descriptors->Set(enumeration_index - 1, &d);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00005755 } else if (type == DATA) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -04005756 if (current_offset < inobject_props) {
5757 object->InObjectPropertyAtPut(current_offset, value,
5758 UPDATE_WRITE_BARRIER);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005759 } else {
Emily Bernierd0a1eb72015-03-24 16:35:39 -04005760 int offset = current_offset - inobject_props;
5761 fields->set(offset, value);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005762 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00005763 DataDescriptor d(key, current_offset, details.attributes(),
5764 // TODO(verwaest): value->OptimalRepresentation();
5765 Representation::Tagged());
Emily Bernierd0a1eb72015-03-24 16:35:39 -04005766 current_offset += d.GetDetails().field_width_in_words();
5767 descriptors->Set(enumeration_index - 1, &d);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00005768 } else if (type == ACCESSOR_CONSTANT) {
5769 AccessorConstantDescriptor d(key, handle(value, isolate),
5770 details.attributes());
Emily Bernierd0a1eb72015-03-24 16:35:39 -04005771 descriptors->Set(enumeration_index - 1, &d);
5772 } else {
5773 UNREACHABLE();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005774 }
5775 }
5776 DCHECK(current_offset == number_of_fields);
5777
5778 descriptors->Sort();
5779
Emily Bernierd0a1eb72015-03-24 16:35:39 -04005780 Handle<LayoutDescriptor> layout_descriptor = LayoutDescriptor::New(
5781 new_map, descriptors, descriptors->number_of_descriptors());
5782
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005783 DisallowHeapAllocation no_gc;
Emily Bernierd0a1eb72015-03-24 16:35:39 -04005784 new_map->InitializeDescriptors(*descriptors, *layout_descriptor);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005785 new_map->set_unused_property_fields(unused_property_fields);
5786
5787 // Transform the object.
5788 object->synchronized_set_map(*new_map);
5789
5790 object->set_properties(*fields);
5791 DCHECK(object->IsJSObject());
5792
5793 // Check that it really works.
5794 DCHECK(object->HasFastProperties());
Ben Murdoch3ef787d2012-04-12 10:51:47 +01005795}
5796
5797
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005798void JSObject::ResetElements(Handle<JSObject> object) {
5799 Isolate* isolate = object->GetIsolate();
5800 CHECK(object->map() != isolate->heap()->sloppy_arguments_elements_map());
5801 if (object->map()->has_dictionary_elements()) {
5802 Handle<SeededNumberDictionary> new_elements =
5803 SeededNumberDictionary::New(isolate, 0);
5804 object->set_elements(*new_elements);
5805 } else {
5806 object->set_elements(object->map()->GetInitialElements());
5807 }
5808}
5809
5810
5811static Handle<SeededNumberDictionary> CopyFastElementsToDictionary(
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00005812 Handle<FixedArrayBase> array, int length,
5813 Handle<SeededNumberDictionary> dictionary, bool used_as_prototype) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005814 Isolate* isolate = array->GetIsolate();
5815 Factory* factory = isolate->factory();
5816 bool has_double_elements = array->IsFixedDoubleArray();
5817 for (int i = 0; i < length; i++) {
5818 Handle<Object> value;
5819 if (has_double_elements) {
5820 Handle<FixedDoubleArray> double_array =
5821 Handle<FixedDoubleArray>::cast(array);
5822 if (double_array->is_the_hole(i)) {
5823 value = factory->the_hole_value();
5824 } else {
5825 value = factory->NewHeapNumber(double_array->get_scalar(i));
5826 }
5827 } else {
5828 value = handle(Handle<FixedArray>::cast(array)->get(i), isolate);
5829 }
5830 if (!value->IsTheHole()) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00005831 PropertyDetails details = PropertyDetails::Empty();
5832 dictionary = SeededNumberDictionary::AddNumberEntry(
5833 dictionary, i, value, details, used_as_prototype);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005834 }
5835 }
5836 return dictionary;
Steve Blocka7e24c12009-10-30 11:49:00 +00005837}
5838
5839
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00005840void JSObject::RequireSlowElements(SeededNumberDictionary* dictionary) {
5841 if (dictionary->requires_slow_elements()) return;
5842 dictionary->set_requires_slow_elements();
5843 // TODO(verwaest): Remove this hack.
5844 if (map()->is_prototype_map()) {
5845 TypeFeedbackVector::ClearAllKeyedStoreICs(GetIsolate());
5846 }
5847}
5848
5849
5850Handle<SeededNumberDictionary> JSObject::GetNormalizedElementDictionary(
5851 Handle<JSObject> object, Handle<FixedArrayBase> elements) {
5852 DCHECK(!object->HasDictionaryElements());
5853 DCHECK(!object->HasSlowArgumentsElements());
5854 Isolate* isolate = object->GetIsolate();
5855 // Ensure that notifications fire if the array or object prototypes are
5856 // normalizing.
5857 isolate->UpdateArrayProtectorOnNormalizeElements(object);
5858 int length = object->IsJSArray()
5859 ? Smi::cast(Handle<JSArray>::cast(object)->length())->value()
5860 : elements->length();
5861 int used = object->GetFastElementsUsage();
5862 Handle<SeededNumberDictionary> dictionary =
5863 SeededNumberDictionary::New(isolate, used);
5864 return CopyFastElementsToDictionary(elements, length, dictionary,
5865 object->map()->is_prototype_map());
5866}
5867
5868
Ben Murdoch3ef787d2012-04-12 10:51:47 +01005869Handle<SeededNumberDictionary> JSObject::NormalizeElements(
5870 Handle<JSObject> object) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00005871 DCHECK(!object->HasFixedTypedArrayElements());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005872 Isolate* isolate = object->GetIsolate();
Steve Block8defd9f2010-07-08 12:39:36 +01005873
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00005874 // Find the backing store.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00005875 Handle<FixedArrayBase> elements(object->elements(), isolate);
5876 bool is_arguments = object->HasSloppyArgumentsElements();
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00005877 if (is_arguments) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00005878 FixedArray* parameter_map = FixedArray::cast(*elements);
5879 elements = handle(FixedArrayBase::cast(parameter_map->get(1)), isolate);
John Reck59135872010-11-02 12:39:01 -07005880 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00005881
5882 if (elements->IsDictionary()) {
5883 return Handle<SeededNumberDictionary>::cast(elements);
5884 }
Steve Blocka7e24c12009-10-30 11:49:00 +00005885
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005886 DCHECK(object->HasFastSmiOrObjectElements() ||
5887 object->HasFastDoubleElements() ||
5888 object->HasFastArgumentsElements());
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00005889
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00005890 Handle<SeededNumberDictionary> dictionary =
5891 GetNormalizedElementDictionary(object, elements);
Steve Blocka7e24c12009-10-30 11:49:00 +00005892
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00005893 // Switch to using the dictionary as the backing storage for elements.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00005894 ElementsKind target_kind =
5895 is_arguments ? SLOW_SLOPPY_ARGUMENTS_ELEMENTS : DICTIONARY_ELEMENTS;
5896 Handle<Map> new_map = JSObject::GetElementsTransitionMap(object, target_kind);
5897 // Set the new map first to satify the elements type assert in set_elements().
5898 JSObject::MigrateToMap(object, new_map);
5899
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00005900 if (is_arguments) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005901 FixedArray::cast(object->elements())->set(1, *dictionary);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00005902 } else {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005903 object->set_elements(*dictionary);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00005904 }
5905
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005906 isolate->counters()->elements_to_dictionary()->Increment();
Steve Blocka7e24c12009-10-30 11:49:00 +00005907
5908#ifdef DEBUG
5909 if (FLAG_trace_normalization) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005910 OFStream os(stdout);
5911 os << "Object elements have been normalized:\n";
5912 object->Print(os);
Steve Blocka7e24c12009-10-30 11:49:00 +00005913 }
5914#endif
5915
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00005916 DCHECK(object->HasDictionaryElements() || object->HasSlowArgumentsElements());
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00005917 return dictionary;
Steve Blocka7e24c12009-10-30 11:49:00 +00005918}
5919
5920
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005921static Smi* GenerateIdentityHash(Isolate* isolate) {
Ben Murdoch69a99ed2011-11-30 16:03:39 +00005922 int hash_value;
5923 int attempts = 0;
5924 do {
5925 // Generate a random 32-bit hash value but limit range to fit
5926 // within a smi.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005927 hash_value = isolate->random_number_generator()->NextInt() & Smi::kMaxValue;
Ben Murdoch69a99ed2011-11-30 16:03:39 +00005928 attempts++;
5929 } while (hash_value == 0 && attempts < 30);
5930 hash_value = hash_value != 0 ? hash_value : 1; // never return 0
5931
Ben Murdoch3ef787d2012-04-12 10:51:47 +01005932 return Smi::FromInt(hash_value);
5933}
5934
5935
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005936void JSObject::SetIdentityHash(Handle<JSObject> object, Handle<Smi> hash) {
5937 DCHECK(!object->IsJSGlobalProxy());
5938 Isolate* isolate = object->GetIsolate();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00005939 Handle<Name> hash_code_symbol(isolate->heap()->hash_code_symbol());
5940 JSObject::AddProperty(object, hash_code_symbol, hash, NONE);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01005941}
5942
5943
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005944template<typename ProxyType>
5945static Handle<Smi> GetOrCreateIdentityHashHelper(Handle<ProxyType> proxy) {
5946 Isolate* isolate = proxy->GetIsolate();
Ben Murdoch3ef787d2012-04-12 10:51:47 +01005947
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005948 Handle<Object> maybe_hash(proxy->hash(), isolate);
5949 if (maybe_hash->IsSmi()) return Handle<Smi>::cast(maybe_hash);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01005950
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005951 Handle<Smi> hash(GenerateIdentityHash(isolate), isolate);
5952 proxy->set_hash(*hash);
Ben Murdoch69a99ed2011-11-30 16:03:39 +00005953 return hash;
5954}
5955
5956
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005957Object* JSObject::GetIdentityHash() {
5958 DisallowHeapAllocation no_gc;
5959 Isolate* isolate = GetIsolate();
5960 if (IsJSGlobalProxy()) {
5961 return JSGlobalProxy::cast(this)->hash();
Ben Murdoch3ef787d2012-04-12 10:51:47 +01005962 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00005963 Handle<Name> hash_code_symbol(isolate->heap()->hash_code_symbol());
5964 Handle<Object> stored_value =
5965 Object::GetPropertyOrElement(Handle<Object>(this, isolate),
5966 hash_code_symbol).ToHandleChecked();
5967 return stored_value->IsSmi() ? *stored_value
5968 : isolate->heap()->undefined_value();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005969}
5970
5971
5972Handle<Smi> JSObject::GetOrCreateIdentityHash(Handle<JSObject> object) {
5973 if (object->IsJSGlobalProxy()) {
5974 return GetOrCreateIdentityHashHelper(Handle<JSGlobalProxy>::cast(object));
5975 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005976 Isolate* isolate = object->GetIsolate();
5977
5978 Handle<Object> maybe_hash(object->GetIdentityHash(), isolate);
5979 if (maybe_hash->IsSmi()) return Handle<Smi>::cast(maybe_hash);
5980
5981 Handle<Smi> hash(GenerateIdentityHash(isolate), isolate);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00005982 Handle<Name> hash_code_symbol(isolate->heap()->hash_code_symbol());
5983 JSObject::AddProperty(object, hash_code_symbol, hash, NONE);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01005984 return hash;
5985}
5986
5987
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005988Object* JSProxy::GetIdentityHash() {
5989 return this->hash();
Ben Murdoch3ef787d2012-04-12 10:51:47 +01005990}
5991
5992
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005993Handle<Smi> JSProxy::GetOrCreateIdentityHash(Handle<JSProxy> proxy) {
5994 return GetOrCreateIdentityHashHelper(proxy);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01005995}
5996
5997
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005998Object* JSObject::GetHiddenProperty(Handle<Name> key) {
5999 DisallowHeapAllocation no_gc;
6000 DCHECK(key->IsUniqueName());
Ben Murdoch3ef787d2012-04-12 10:51:47 +01006001 if (IsJSGlobalProxy()) {
6002 // For a proxy, use the prototype as target object.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006003 PrototypeIterator iter(GetIsolate(), this);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01006004 // If the proxy is detached, return undefined.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006005 if (iter.IsAtEnd()) return GetHeap()->the_hole_value();
6006 DCHECK(iter.GetCurrent()->IsJSGlobalObject());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00006007 return iter.GetCurrent<JSObject>()->GetHiddenProperty(key);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01006008 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006009 DCHECK(!IsJSGlobalProxy());
6010 Object* inline_value = GetHiddenPropertiesHashTable();
6011
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006012 if (inline_value->IsUndefined()) return GetHeap()->the_hole_value();
6013
6014 ObjectHashTable* hashtable = ObjectHashTable::cast(inline_value);
6015 Object* entry = hashtable->Lookup(key);
6016 return entry;
6017}
6018
6019
6020Handle<Object> JSObject::SetHiddenProperty(Handle<JSObject> object,
6021 Handle<Name> key,
6022 Handle<Object> value) {
6023 Isolate* isolate = object->GetIsolate();
6024
6025 DCHECK(key->IsUniqueName());
6026 if (object->IsJSGlobalProxy()) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006027 // For a proxy, use the prototype as target object.
6028 PrototypeIterator iter(isolate, object);
6029 // If the proxy is detached, return undefined.
6030 if (iter.IsAtEnd()) return isolate->factory()->undefined_value();
6031 DCHECK(PrototypeIterator::GetCurrent(iter)->IsJSGlobalObject());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00006032 return SetHiddenProperty(PrototypeIterator::GetCurrent<JSObject>(iter), key,
6033 value);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006034 }
6035 DCHECK(!object->IsJSGlobalProxy());
6036
6037 Handle<Object> inline_value(object->GetHiddenPropertiesHashTable(), isolate);
6038
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006039 Handle<ObjectHashTable> hashtable =
6040 GetOrCreateHiddenPropertiesHashtable(object);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01006041
6042 // If it was found, check if the key is already in the dictionary.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006043 Handle<ObjectHashTable> new_table = ObjectHashTable::Put(hashtable, key,
6044 value);
6045 if (*new_table != *hashtable) {
Ben Murdoch3ef787d2012-04-12 10:51:47 +01006046 // If adding the key expanded the dictionary (i.e., Add returned a new
6047 // dictionary), store it back to the object.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006048 SetHiddenPropertiesHashTable(object, new_table);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01006049 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006050
Ben Murdoch3ef787d2012-04-12 10:51:47 +01006051 // Return this to mark success.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006052 return object;
Ben Murdoch3ef787d2012-04-12 10:51:47 +01006053}
6054
6055
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006056void JSObject::DeleteHiddenProperty(Handle<JSObject> object, Handle<Name> key) {
6057 Isolate* isolate = object->GetIsolate();
6058 DCHECK(key->IsUniqueName());
6059
6060 if (object->IsJSGlobalProxy()) {
6061 PrototypeIterator iter(isolate, object);
6062 if (iter.IsAtEnd()) return;
6063 DCHECK(PrototypeIterator::GetCurrent(iter)->IsJSGlobalObject());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00006064 return DeleteHiddenProperty(PrototypeIterator::GetCurrent<JSObject>(iter),
6065 key);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01006066 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006067
6068 Object* inline_value = object->GetHiddenPropertiesHashTable();
6069
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00006070 if (inline_value->IsUndefined()) return;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006071
6072 Handle<ObjectHashTable> hashtable(ObjectHashTable::cast(inline_value));
6073 bool was_present = false;
6074 ObjectHashTable::Remove(hashtable, key, &was_present);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01006075}
6076
6077
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006078bool JSObject::HasHiddenProperties(Handle<JSObject> object) {
6079 Handle<Name> hidden = object->GetIsolate()->factory()->hidden_string();
6080 LookupIterator it(object, hidden, LookupIterator::OWN_SKIP_INTERCEPTOR);
6081 Maybe<PropertyAttributes> maybe = GetPropertyAttributes(&it);
6082 // Cannot get an exception since the hidden_string isn't accessible to JS.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00006083 DCHECK(maybe.IsJust());
6084 return maybe.FromJust() != ABSENT;
Ben Murdoch3ef787d2012-04-12 10:51:47 +01006085}
6086
6087
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006088Object* JSObject::GetHiddenPropertiesHashTable() {
6089 DCHECK(!IsJSGlobalProxy());
Ben Murdoch3ef787d2012-04-12 10:51:47 +01006090 if (HasFastProperties()) {
6091 // If the object has fast properties, check whether the first slot
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006092 // in the descriptor array matches the hidden string. Since the
6093 // hidden strings hash code is zero (and no other name has hash
Ben Murdoch3ef787d2012-04-12 10:51:47 +01006094 // code zero) it will always occupy the first entry if present.
6095 DescriptorArray* descriptors = this->map()->instance_descriptors();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006096 if (descriptors->number_of_descriptors() > 0) {
6097 int sorted_index = descriptors->GetSortedKeyIndex(0);
6098 if (descriptors->GetKey(sorted_index) == GetHeap()->hidden_string() &&
6099 sorted_index < map()->NumberOfOwnDescriptors()) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00006100 DCHECK(descriptors->GetType(sorted_index) == DATA);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006101 DCHECK(descriptors->GetDetails(sorted_index).representation().
6102 IsCompatibleForLoad(Representation::Tagged()));
6103 FieldIndex index = FieldIndex::ForDescriptor(this->map(),
6104 sorted_index);
6105 return this->RawFastPropertyAt(index);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01006106 } else {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006107 return GetHeap()->undefined_value();
Ben Murdoch3ef787d2012-04-12 10:51:47 +01006108 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006109 } else {
6110 return GetHeap()->undefined_value();
Ben Murdoch3ef787d2012-04-12 10:51:47 +01006111 }
6112 } else {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006113 Isolate* isolate = GetIsolate();
6114 LookupIterator it(handle(this), isolate->factory()->hidden_string(),
6115 LookupIterator::OWN_SKIP_INTERCEPTOR);
6116 // Access check is always skipped for the hidden string anyways.
6117 return *GetDataProperty(&it);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01006118 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006119}
6120
6121Handle<ObjectHashTable> JSObject::GetOrCreateHiddenPropertiesHashtable(
6122 Handle<JSObject> object) {
6123 Isolate* isolate = object->GetIsolate();
6124
6125 static const int kInitialCapacity = 4;
6126 Handle<Object> inline_value(object->GetHiddenPropertiesHashTable(), isolate);
6127 if (inline_value->IsHashTable()) {
6128 return Handle<ObjectHashTable>::cast(inline_value);
6129 }
6130
6131 Handle<ObjectHashTable> hashtable = ObjectHashTable::New(
6132 isolate, kInitialCapacity, USE_CUSTOM_MINIMUM_CAPACITY);
6133
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00006134 DCHECK(inline_value->IsUndefined());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006135 SetHiddenPropertiesHashTable(object, hashtable);
6136 return hashtable;
Ben Murdoch3ef787d2012-04-12 10:51:47 +01006137}
6138
6139
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006140Handle<Object> JSObject::SetHiddenPropertiesHashTable(Handle<JSObject> object,
6141 Handle<Object> value) {
6142 DCHECK(!object->IsJSGlobalProxy());
6143 Isolate* isolate = object->GetIsolate();
6144 Handle<Name> name = isolate->factory()->hidden_string();
6145 SetOwnPropertyIgnoreAttributes(object, name, value, DONT_ENUM).Assert();
6146 return object;
6147}
6148
6149
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00006150Maybe<bool> JSObject::DeletePropertyWithInterceptor(LookupIterator* it) {
6151 Isolate* isolate = it->isolate();
6152 // Make sure that the top context does not change when doing callbacks or
6153 // interceptor calls.
6154 AssertNoContextChange ncc(isolate);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006155
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00006156 DCHECK_EQ(LookupIterator::INTERCEPTOR, it->state());
6157 Handle<InterceptorInfo> interceptor(it->GetInterceptor());
6158 if (interceptor->deleter()->IsUndefined()) return Nothing<bool>();
6159
6160 Handle<JSObject> holder = it->GetHolder<JSObject>();
6161
6162 PropertyCallbackArguments args(isolate, interceptor->data(),
6163 *it->GetReceiver(), *holder);
6164 v8::Local<v8::Boolean> result;
6165 if (it->IsElement()) {
6166 uint32_t index = it->index();
6167 v8::IndexedPropertyDeleterCallback deleter =
6168 v8::ToCData<v8::IndexedPropertyDeleterCallback>(interceptor->deleter());
6169 LOG(isolate,
6170 ApiIndexedPropertyAccess("interceptor-indexed-delete", *holder, index));
6171 result = args.Call(deleter, index);
6172 } else if (it->name()->IsSymbol() && !interceptor->can_intercept_symbols()) {
6173 return Nothing<bool>();
6174 } else {
6175 Handle<Name> name = it->name();
6176 DCHECK(!name->IsPrivate());
6177 v8::GenericNamedPropertyDeleterCallback deleter =
6178 v8::ToCData<v8::GenericNamedPropertyDeleterCallback>(
6179 interceptor->deleter());
6180 LOG(isolate,
6181 ApiNamedPropertyAccess("interceptor-named-delete", *holder, *name));
6182 result = args.Call(deleter, v8::Utils::ToLocal(name));
Emily Bernierd0a1eb72015-03-24 16:35:39 -04006183 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006184
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00006185 RETURN_VALUE_IF_SCHEDULED_EXCEPTION(isolate, Nothing<bool>());
6186 if (result.IsEmpty()) return Nothing<bool>();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006187
6188 DCHECK(result->IsBoolean());
6189 Handle<Object> result_internal = v8::Utils::OpenHandle(*result);
6190 result_internal->VerifyApiCallResultType();
6191 // Rebox CustomArguments::kReturnValueOffset before returning.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00006192 return Just(result_internal->BooleanValue());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006193}
6194
6195
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00006196void JSReceiver::DeleteNormalizedProperty(Handle<JSReceiver> object,
6197 Handle<Name> name, int entry) {
6198 DCHECK(!object->HasFastProperties());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006199 Isolate* isolate = object->GetIsolate();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006200
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00006201 if (object->IsJSGlobalObject()) {
6202 // If we have a global object, invalidate the cell and swap in a new one.
6203 Handle<GlobalDictionary> dictionary(
6204 JSObject::cast(*object)->global_dictionary());
6205 DCHECK_NE(GlobalDictionary::kNotFound, entry);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006206
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00006207 auto cell = PropertyCell::InvalidateEntry(dictionary, entry);
6208 cell->set_value(isolate->heap()->the_hole_value());
6209 // TODO(ishell): InvalidateForDelete
6210 cell->set_property_details(
6211 cell->property_details().set_cell_type(PropertyCellType::kInvalidated));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006212 } else {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00006213 Handle<NameDictionary> dictionary(object->property_dictionary());
6214 DCHECK_NE(NameDictionary::kNotFound, entry);
Steve Blocka7e24c12009-10-30 11:49:00 +00006215
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00006216 NameDictionary::DeleteProperty(dictionary, entry);
6217 Handle<NameDictionary> new_properties =
6218 NameDictionary::Shrink(dictionary, name);
6219 object->set_properties(*new_properties);
Steve Blocka7e24c12009-10-30 11:49:00 +00006220 }
Steve Blocka7e24c12009-10-30 11:49:00 +00006221}
6222
6223
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00006224Maybe<bool> JSReceiver::DeleteProperty(LookupIterator* it,
6225 LanguageMode language_mode) {
6226 Isolate* isolate = it->isolate();
Steve Blocka7e24c12009-10-30 11:49:00 +00006227
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00006228 if (it->state() == LookupIterator::JSPROXY) {
6229 return JSProxy::DeletePropertyOrElement(it->GetHolder<JSProxy>(),
6230 it->GetName(), language_mode);
Steve Blocka7e24c12009-10-30 11:49:00 +00006231 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006232
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00006233 if (it->GetReceiver()->IsJSProxy()) {
6234 if (it->state() != LookupIterator::NOT_FOUND) {
6235 DCHECK_EQ(LookupIterator::DATA, it->state());
6236 DCHECK(it->GetName()->IsPrivate());
6237 it->Delete();
6238 }
6239 return Just(true);
6240 }
6241 Handle<JSObject> receiver = Handle<JSObject>::cast(it->GetReceiver());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006242
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00006243 bool is_observed =
6244 receiver->map()->is_observed() &&
6245 (it->IsElement() || !isolate->IsInternallyUsedPropertyName(it->name()));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006246
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00006247 Handle<Object> old_value = it->factory()->the_hole_value();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006248
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00006249 for (; it->IsFound(); it->Next()) {
6250 switch (it->state()) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006251 case LookupIterator::JSPROXY:
6252 case LookupIterator::NOT_FOUND:
6253 case LookupIterator::TRANSITION:
6254 UNREACHABLE();
6255 case LookupIterator::ACCESS_CHECK:
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00006256 if (it->HasAccess()) break;
6257 isolate->ReportFailedAccessCheck(it->GetHolder<JSObject>());
6258 RETURN_VALUE_IF_SCHEDULED_EXCEPTION(isolate, Nothing<bool>());
6259 return Just(false);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006260 case LookupIterator::INTERCEPTOR: {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00006261 Maybe<bool> result = JSObject::DeletePropertyWithInterceptor(it);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006262 // An exception was thrown in the interceptor. Propagate.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00006263 if (isolate->has_pending_exception()) return Nothing<bool>();
6264 // Delete with interceptor succeeded. Return result.
6265 // TODO(neis): In strict mode, we should probably throw if the
6266 // interceptor returns false.
6267 if (result.IsJust()) return result;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006268 break;
6269 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00006270 case LookupIterator::INTEGER_INDEXED_EXOTIC:
6271 return Just(true);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006272 case LookupIterator::DATA:
6273 if (is_observed) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00006274 old_value = it->GetDataValue();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006275 }
6276 // Fall through.
6277 case LookupIterator::ACCESSOR: {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00006278 if (!it->IsConfigurable() || receiver->map()->is_strong()) {
6279 // Fail if the property is not configurable, or on a strong object.
6280 if (is_strict(language_mode)) {
6281 MessageTemplate::Template templ =
6282 receiver->map()->is_strong()
6283 ? MessageTemplate::kStrongDeleteProperty
6284 : MessageTemplate::kStrictDeleteProperty;
6285 isolate->Throw(*isolate->factory()->NewTypeError(
6286 templ, it->GetName(), receiver));
6287 return Nothing<bool>();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006288 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00006289 return Just(false);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006290 }
6291
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00006292 it->Delete();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006293
6294 if (is_observed) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00006295 RETURN_ON_EXCEPTION_VALUE(
6296 isolate, JSObject::EnqueueChangeRecord(receiver, "delete",
6297 it->GetName(), old_value),
6298 Nothing<bool>());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006299 }
6300
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00006301 return Just(true);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006302 }
6303 }
6304 }
6305
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00006306 return Just(true);
Steve Blocka7e24c12009-10-30 11:49:00 +00006307}
6308
6309
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00006310Maybe<bool> JSReceiver::DeleteElement(Handle<JSReceiver> object, uint32_t index,
6311 LanguageMode language_mode) {
6312 LookupIterator it(object->GetIsolate(), object, index,
6313 LookupIterator::HIDDEN);
6314 return DeleteProperty(&it, language_mode);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01006315}
6316
6317
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00006318Maybe<bool> JSReceiver::DeleteProperty(Handle<JSReceiver> object,
6319 Handle<Name> name,
6320 LanguageMode language_mode) {
6321 LookupIterator it(object, name, LookupIterator::HIDDEN);
6322 return DeleteProperty(&it, language_mode);
6323}
6324
6325
6326Maybe<bool> JSReceiver::DeletePropertyOrElement(Handle<JSReceiver> object,
6327 Handle<Name> name,
6328 LanguageMode language_mode) {
6329 LookupIterator it = LookupIterator::PropertyOrElement(
6330 name->GetIsolate(), object, name, LookupIterator::HIDDEN);
6331 return DeleteProperty(&it, language_mode);
6332}
6333
6334
6335// ES6 7.1.14
6336MaybeHandle<Object> ToPropertyKey(Isolate* isolate, Handle<Object> value) {
6337 // 1. Let key be ToPrimitive(argument, hint String).
6338 MaybeHandle<Object> maybe_key =
6339 Object::ToPrimitive(value, ToPrimitiveHint::kString);
6340 // 2. ReturnIfAbrupt(key).
6341 Handle<Object> key;
6342 if (!maybe_key.ToHandle(&key)) return key;
6343 // 3. If Type(key) is Symbol, then return key.
6344 if (key->IsSymbol()) return key;
6345 // 4. Return ToString(key).
6346 // Extending spec'ed behavior, we'd be happy to return an element index.
6347 if (key->IsSmi()) return key;
6348 if (key->IsHeapNumber()) {
6349 uint32_t uint_value;
6350 if (value->ToArrayLength(&uint_value) &&
6351 uint_value <= static_cast<uint32_t>(Smi::kMaxValue)) {
6352 return handle(Smi::FromInt(static_cast<int>(uint_value)), isolate);
6353 }
Ben Murdoch3ef787d2012-04-12 10:51:47 +01006354 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00006355 return Object::ToString(isolate, key);
6356}
6357
6358
6359// ES6 19.1.2.4
6360// static
6361Object* JSReceiver::DefineProperty(Isolate* isolate, Handle<Object> object,
6362 Handle<Object> key,
6363 Handle<Object> attributes) {
6364 // 1. If Type(O) is not Object, throw a TypeError exception.
6365 if (!object->IsJSReceiver()) {
6366 Handle<String> fun_name =
6367 isolate->factory()->InternalizeUtf8String("Object.defineProperty");
6368 THROW_NEW_ERROR_RETURN_FAILURE(
6369 isolate, NewTypeError(MessageTemplate::kCalledOnNonObject, fun_name));
6370 }
6371 // 2. Let key be ToPropertyKey(P).
6372 // 3. ReturnIfAbrupt(key).
6373 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, key, ToPropertyKey(isolate, key));
6374 // 4. Let desc be ToPropertyDescriptor(Attributes).
6375 // 5. ReturnIfAbrupt(desc).
6376 PropertyDescriptor desc;
6377 if (!PropertyDescriptor::ToPropertyDescriptor(isolate, attributes, &desc)) {
6378 return isolate->heap()->exception();
6379 }
6380 // 6. Let success be DefinePropertyOrThrow(O,key, desc).
6381 Maybe<bool> success = DefineOwnProperty(
6382 isolate, Handle<JSReceiver>::cast(object), key, &desc, THROW_ON_ERROR);
6383 // 7. ReturnIfAbrupt(success).
6384 MAYBE_RETURN(success, isolate->heap()->exception());
6385 CHECK(success.FromJust());
6386 // 8. Return O.
6387 return *object;
6388}
6389
6390
6391// ES6 19.1.2.3.1
6392// static
6393MaybeHandle<Object> JSReceiver::DefineProperties(Isolate* isolate,
6394 Handle<Object> object,
6395 Handle<Object> properties) {
6396 // 1. If Type(O) is not Object, throw a TypeError exception.
6397 if (!object->IsJSReceiver()) {
6398 Handle<String> fun_name =
6399 isolate->factory()->InternalizeUtf8String("Object.defineProperties");
6400 THROW_NEW_ERROR(isolate,
6401 NewTypeError(MessageTemplate::kCalledOnNonObject, fun_name),
6402 Object);
6403 }
6404 // 2. Let props be ToObject(Properties).
6405 // 3. ReturnIfAbrupt(props).
6406 Handle<JSReceiver> props;
6407 if (!Object::ToObject(isolate, properties).ToHandle(&props)) {
6408 THROW_NEW_ERROR(isolate,
6409 NewTypeError(MessageTemplate::kUndefinedOrNullToObject),
6410 Object);
6411 }
6412 // 4. Let keys be props.[[OwnPropertyKeys]]().
6413 // 5. ReturnIfAbrupt(keys).
6414 Handle<FixedArray> keys;
6415 ASSIGN_RETURN_ON_EXCEPTION(
6416 isolate, keys,
6417 JSReceiver::GetKeys(props, JSReceiver::OWN_ONLY, ALL_PROPERTIES), Object);
6418 // 6. Let descriptors be an empty List.
6419 int capacity = keys->length();
6420 std::vector<PropertyDescriptor> descriptors(capacity);
6421 size_t descriptors_index = 0;
6422 // 7. Repeat for each element nextKey of keys in List order,
6423 for (int i = 0; i < keys->length(); ++i) {
6424 Handle<Object> next_key(keys->get(i), isolate);
6425 // 7a. Let propDesc be props.[[GetOwnProperty]](nextKey).
6426 // 7b. ReturnIfAbrupt(propDesc).
6427 bool success = false;
6428 LookupIterator it = LookupIterator::PropertyOrElement(
6429 isolate, props, next_key, &success, LookupIterator::HIDDEN);
6430 DCHECK(success);
6431 Maybe<PropertyAttributes> maybe = JSReceiver::GetPropertyAttributes(&it);
6432 if (!maybe.IsJust()) return MaybeHandle<Object>();
6433 PropertyAttributes attrs = maybe.FromJust();
6434 // 7c. If propDesc is not undefined and propDesc.[[Enumerable]] is true:
6435 if (attrs == ABSENT) continue;
6436 if (attrs & DONT_ENUM) continue;
6437 // 7c i. Let descObj be Get(props, nextKey).
6438 // 7c ii. ReturnIfAbrupt(descObj).
6439 Handle<Object> desc_obj;
6440 ASSIGN_RETURN_ON_EXCEPTION(isolate, desc_obj, Object::GetProperty(&it),
6441 Object);
6442 // 7c iii. Let desc be ToPropertyDescriptor(descObj).
6443 success = PropertyDescriptor::ToPropertyDescriptor(
6444 isolate, desc_obj, &descriptors[descriptors_index]);
6445 // 7c iv. ReturnIfAbrupt(desc).
6446 if (!success) return MaybeHandle<Object>();
6447 // 7c v. Append the pair (a two element List) consisting of nextKey and
6448 // desc to the end of descriptors.
6449 descriptors[descriptors_index].set_name(next_key);
6450 descriptors_index++;
6451 }
6452 // 8. For each pair from descriptors in list order,
6453 for (size_t i = 0; i < descriptors_index; ++i) {
6454 PropertyDescriptor* desc = &descriptors[i];
6455 // 8a. Let P be the first element of pair.
6456 // 8b. Let desc be the second element of pair.
6457 // 8c. Let status be DefinePropertyOrThrow(O, P, desc).
6458 Maybe<bool> status =
6459 DefineOwnProperty(isolate, Handle<JSReceiver>::cast(object),
6460 desc->name(), desc, THROW_ON_ERROR);
6461 // 8d. ReturnIfAbrupt(status).
6462 if (!status.IsJust()) return MaybeHandle<Object>();
6463 CHECK(status.FromJust());
6464 }
6465 // 9. Return o.
6466 return object;
6467}
6468
6469
6470// static
6471Maybe<bool> JSReceiver::DefineOwnProperty(Isolate* isolate,
6472 Handle<JSReceiver> object,
6473 Handle<Object> key,
6474 PropertyDescriptor* desc,
6475 ShouldThrow should_throw) {
6476 if (object->IsJSArray()) {
6477 return JSArray::DefineOwnProperty(isolate, Handle<JSArray>::cast(object),
6478 key, desc, should_throw);
6479 }
6480 if (object->IsJSProxy()) {
6481 return JSProxy::DefineOwnProperty(isolate, Handle<JSProxy>::cast(object),
6482 key, desc, should_throw);
6483 }
6484 // TODO(jkummerow): Support Modules (ES6 9.4.6.6)
6485
6486 // OrdinaryDefineOwnProperty, by virtue of calling
6487 // DefineOwnPropertyIgnoreAttributes, can handle arguments (ES6 9.4.4.2)
6488 // and IntegerIndexedExotics (ES6 9.4.5.3), with one exception:
6489 // TODO(jkummerow): Setting an indexed accessor on a typed array should throw.
6490 return OrdinaryDefineOwnProperty(isolate, Handle<JSObject>::cast(object), key,
6491 desc, should_throw);
6492}
6493
6494
6495// static
6496Maybe<bool> JSReceiver::OrdinaryDefineOwnProperty(Isolate* isolate,
6497 Handle<JSObject> object,
6498 Handle<Object> key,
6499 PropertyDescriptor* desc,
6500 ShouldThrow should_throw) {
6501 bool success = false;
6502 DCHECK(key->IsName() || key->IsNumber()); // |key| is a PropertyKey...
6503 LookupIterator it = LookupIterator::PropertyOrElement(
6504 isolate, object, key, &success, LookupIterator::HIDDEN);
6505 DCHECK(success); // ...so creating a LookupIterator can't fail.
6506
6507 // Deal with access checks first.
6508 if (it.state() == LookupIterator::ACCESS_CHECK) {
6509 if (!it.HasAccess()) {
6510 isolate->ReportFailedAccessCheck(it.GetHolder<JSObject>());
6511 RETURN_VALUE_IF_SCHEDULED_EXCEPTION(isolate, Nothing<bool>());
6512 return Just(true);
6513 }
6514 it.Next();
6515 }
6516
6517 return OrdinaryDefineOwnProperty(&it, desc, should_throw);
6518}
6519
6520
6521// ES6 9.1.6.1
6522// static
6523Maybe<bool> JSReceiver::OrdinaryDefineOwnProperty(LookupIterator* it,
6524 PropertyDescriptor* desc,
6525 ShouldThrow should_throw) {
6526 Isolate* isolate = it->isolate();
6527 // 1. Let current be O.[[GetOwnProperty]](P).
6528 // 2. ReturnIfAbrupt(current).
6529 PropertyDescriptor current;
6530 MAYBE_RETURN(GetOwnPropertyDescriptor(it, &current), Nothing<bool>());
6531
6532 // TODO(jkummerow/verwaest): It would be nice if we didn't have to reset
6533 // the iterator every time. Currently, the reasons why we need it are:
6534 // - handle interceptors correctly
6535 // - handle accessors correctly (which might change the holder's map)
6536 it->Restart();
6537 // 3. Let extensible be the value of the [[Extensible]] internal slot of O.
6538 Handle<JSObject> object = Handle<JSObject>::cast(it->GetReceiver());
6539 bool extensible = JSObject::IsExtensible(object);
6540
6541 return ValidateAndApplyPropertyDescriptor(isolate, it, extensible, desc,
6542 &current, should_throw);
6543}
6544
6545
6546// ES6 9.1.6.2
6547// static
6548Maybe<bool> JSReceiver::IsCompatiblePropertyDescriptor(
6549 Isolate* isolate, bool extensible, PropertyDescriptor* desc,
6550 PropertyDescriptor* current, Handle<Name> property_name,
6551 ShouldThrow should_throw) {
6552 // 1. Return ValidateAndApplyPropertyDescriptor(undefined, undefined,
6553 // Extensible, Desc, Current).
6554 return ValidateAndApplyPropertyDescriptor(
6555 isolate, NULL, extensible, desc, current, should_throw, property_name);
6556}
6557
6558
6559// ES6 9.1.6.3
6560// static
6561Maybe<bool> JSReceiver::ValidateAndApplyPropertyDescriptor(
6562 Isolate* isolate, LookupIterator* it, bool extensible,
6563 PropertyDescriptor* desc, PropertyDescriptor* current,
6564 ShouldThrow should_throw, Handle<Name> property_name) {
6565 // We either need a LookupIterator, or a property name.
6566 DCHECK((it == NULL) != property_name.is_null());
6567 Handle<JSObject> object;
6568 if (it != NULL) object = Handle<JSObject>::cast(it->GetReceiver());
6569 bool desc_is_data_descriptor = PropertyDescriptor::IsDataDescriptor(desc);
6570 bool desc_is_accessor_descriptor =
6571 PropertyDescriptor::IsAccessorDescriptor(desc);
6572 bool desc_is_generic_descriptor =
6573 PropertyDescriptor::IsGenericDescriptor(desc);
6574 // 1. (Assert)
6575 // 2. If current is undefined, then
6576 if (current->is_empty()) {
6577 // 2a. If extensible is false, return false.
6578 if (!extensible) {
6579 RETURN_FAILURE(isolate, should_throw,
6580 NewTypeError(MessageTemplate::kDefineDisallowed,
6581 it != NULL ? it->GetName() : property_name));
6582 }
6583 // 2c. If IsGenericDescriptor(Desc) or IsDataDescriptor(Desc) is true, then:
6584 // (This is equivalent to !IsAccessorDescriptor(desc).)
6585 DCHECK((desc_is_generic_descriptor || desc_is_data_descriptor) ==
6586 !desc_is_accessor_descriptor);
6587 if (!desc_is_accessor_descriptor) {
6588 // 2c i. If O is not undefined, create an own data property named P of
6589 // object O whose [[Value]], [[Writable]], [[Enumerable]] and
6590 // [[Configurable]] attribute values are described by Desc. If the value
6591 // of an attribute field of Desc is absent, the attribute of the newly
6592 // created property is set to its default value.
6593 if (it != NULL) {
6594 if (!desc->has_writable()) desc->set_writable(false);
6595 if (!desc->has_enumerable()) desc->set_enumerable(false);
6596 if (!desc->has_configurable()) desc->set_configurable(false);
6597 Handle<Object> value(
6598 desc->has_value()
6599 ? desc->value()
6600 : Handle<Object>::cast(isolate->factory()->undefined_value()));
6601 MaybeHandle<Object> result =
6602 JSObject::DefineOwnPropertyIgnoreAttributes(
6603 it, value, desc->ToAttributes(), JSObject::DONT_FORCE_FIELD);
6604 if (result.is_null()) return Nothing<bool>();
6605 }
6606 } else {
6607 // 2d. Else Desc must be an accessor Property Descriptor,
6608 DCHECK(desc_is_accessor_descriptor);
6609 // 2d i. If O is not undefined, create an own accessor property named P
6610 // of object O whose [[Get]], [[Set]], [[Enumerable]] and
6611 // [[Configurable]] attribute values are described by Desc. If the value
6612 // of an attribute field of Desc is absent, the attribute of the newly
6613 // created property is set to its default value.
6614 if (it != NULL) {
6615 if (!desc->has_enumerable()) desc->set_enumerable(false);
6616 if (!desc->has_configurable()) desc->set_configurable(false);
6617 Handle<Object> getter(
6618 desc->has_get()
6619 ? desc->get()
6620 : Handle<Object>::cast(isolate->factory()->null_value()));
6621 Handle<Object> setter(
6622 desc->has_set()
6623 ? desc->set()
6624 : Handle<Object>::cast(isolate->factory()->null_value()));
6625 MaybeHandle<Object> result =
6626 JSObject::DefineAccessor(it, getter, setter, desc->ToAttributes());
6627 if (result.is_null()) return Nothing<bool>();
6628 }
6629 }
6630 // 2e. Return true.
6631 return Just(true);
6632 }
6633 // 3. Return true, if every field in Desc is absent.
6634 // 4. Return true, if every field in Desc also occurs in current and the
6635 // value of every field in Desc is the same value as the corresponding field
6636 // in current when compared using the SameValue algorithm.
6637 if ((!desc->has_enumerable() ||
6638 desc->enumerable() == current->enumerable()) &&
6639 (!desc->has_configurable() ||
6640 desc->configurable() == current->configurable()) &&
6641 (!desc->has_value() ||
6642 (current->has_value() && current->value()->SameValue(*desc->value()))) &&
6643 (!desc->has_writable() ||
6644 (current->has_writable() && current->writable() == desc->writable())) &&
6645 (!desc->has_get() ||
6646 (current->has_get() && current->get()->SameValue(*desc->get()))) &&
6647 (!desc->has_set() ||
6648 (current->has_set() && current->set()->SameValue(*desc->set())))) {
6649 return Just(true);
6650 }
6651 // 5. If the [[Configurable]] field of current is false, then
6652 if (!current->configurable()) {
6653 // 5a. Return false, if the [[Configurable]] field of Desc is true.
6654 if (desc->has_configurable() && desc->configurable()) {
6655 RETURN_FAILURE(isolate, should_throw,
6656 NewTypeError(MessageTemplate::kRedefineDisallowed,
6657 it != NULL ? it->GetName() : property_name));
6658 }
6659 // 5b. Return false, if the [[Enumerable]] field of Desc is present and the
6660 // [[Enumerable]] fields of current and Desc are the Boolean negation of
6661 // each other.
6662 if (desc->has_enumerable() && desc->enumerable() != current->enumerable()) {
6663 RETURN_FAILURE(isolate, should_throw,
6664 NewTypeError(MessageTemplate::kRedefineDisallowed,
6665 it != NULL ? it->GetName() : property_name));
6666 }
6667 }
6668
6669 bool current_is_data_descriptor =
6670 PropertyDescriptor::IsDataDescriptor(current);
6671 // 6. If IsGenericDescriptor(Desc) is true, no further validation is required.
6672 if (desc_is_generic_descriptor) {
6673 // Nothing to see here.
6674
6675 // 7. Else if IsDataDescriptor(current) and IsDataDescriptor(Desc) have
6676 // different results, then:
6677 } else if (current_is_data_descriptor != desc_is_data_descriptor) {
6678 // 7a. Return false, if the [[Configurable]] field of current is false.
6679 if (!current->configurable()) {
6680 RETURN_FAILURE(isolate, should_throw,
6681 NewTypeError(MessageTemplate::kRedefineDisallowed,
6682 it != NULL ? it->GetName() : property_name));
6683 }
6684 // 7b. If IsDataDescriptor(current) is true, then:
6685 if (current_is_data_descriptor) {
6686 // 7b i. If O is not undefined, convert the property named P of object O
6687 // from a data property to an accessor property. Preserve the existing
6688 // values of the converted property's [[Configurable]] and [[Enumerable]]
6689 // attributes and set the rest of the property's attributes to their
6690 // default values.
6691 // --> Folded into step 10.
6692 } else {
6693 // 7c i. If O is not undefined, convert the property named P of object O
6694 // from an accessor property to a data property. Preserve the existing
6695 // values of the converted property’s [[Configurable]] and [[Enumerable]]
6696 // attributes and set the rest of the property’s attributes to their
6697 // default values.
6698 // --> Folded into step 10.
6699 }
6700
6701 // 8. Else if IsDataDescriptor(current) and IsDataDescriptor(Desc) are both
6702 // true, then:
6703 } else if (current_is_data_descriptor && desc_is_data_descriptor) {
6704 // 8a. If the [[Configurable]] field of current is false, then:
6705 if (!current->configurable()) {
6706 // [Strong mode] Disallow changing writable -> readonly for
6707 // non-configurable properties.
6708 if (it != NULL && current->writable() && desc->has_writable() &&
6709 !desc->writable() && object->map()->is_strong()) {
6710 RETURN_FAILURE(isolate, should_throw,
6711 NewTypeError(MessageTemplate::kStrongRedefineDisallowed,
6712 object, it->GetName()));
6713 }
6714 // 8a i. Return false, if the [[Writable]] field of current is false and
6715 // the [[Writable]] field of Desc is true.
6716 if (!current->writable() && desc->has_writable() && desc->writable()) {
6717 RETURN_FAILURE(
6718 isolate, should_throw,
6719 NewTypeError(MessageTemplate::kRedefineDisallowed,
6720 it != NULL ? it->GetName() : property_name));
6721 }
6722 // 8a ii. If the [[Writable]] field of current is false, then:
6723 if (!current->writable()) {
6724 // 8a ii 1. Return false, if the [[Value]] field of Desc is present and
6725 // SameValue(Desc.[[Value]], current.[[Value]]) is false.
6726 if (desc->has_value() && !desc->value()->SameValue(*current->value())) {
6727 RETURN_FAILURE(
6728 isolate, should_throw,
6729 NewTypeError(MessageTemplate::kRedefineDisallowed,
6730 it != NULL ? it->GetName() : property_name));
6731 }
6732 }
6733 }
6734 } else {
6735 // 9. Else IsAccessorDescriptor(current) and IsAccessorDescriptor(Desc)
6736 // are both true,
6737 DCHECK(PropertyDescriptor::IsAccessorDescriptor(current) &&
6738 desc_is_accessor_descriptor);
6739 // 9a. If the [[Configurable]] field of current is false, then:
6740 if (!current->configurable()) {
6741 // 9a i. Return false, if the [[Set]] field of Desc is present and
6742 // SameValue(Desc.[[Set]], current.[[Set]]) is false.
6743 if (desc->has_set() && !desc->set()->SameValue(*current->set())) {
6744 RETURN_FAILURE(
6745 isolate, should_throw,
6746 NewTypeError(MessageTemplate::kRedefineDisallowed,
6747 it != NULL ? it->GetName() : property_name));
6748 }
6749 // 9a ii. Return false, if the [[Get]] field of Desc is present and
6750 // SameValue(Desc.[[Get]], current.[[Get]]) is false.
6751 if (desc->has_get() && !desc->get()->SameValue(*current->get())) {
6752 RETURN_FAILURE(
6753 isolate, should_throw,
6754 NewTypeError(MessageTemplate::kRedefineDisallowed,
6755 it != NULL ? it->GetName() : property_name));
6756 }
6757 }
6758 }
6759
6760 // 10. If O is not undefined, then:
6761 if (it != NULL) {
6762 // 10a. For each field of Desc that is present, set the corresponding
6763 // attribute of the property named P of object O to the value of the field.
6764 PropertyAttributes attrs = NONE;
6765
6766 if (desc->has_enumerable()) {
6767 attrs = static_cast<PropertyAttributes>(
6768 attrs | (desc->enumerable() ? NONE : DONT_ENUM));
6769 } else {
6770 attrs = static_cast<PropertyAttributes>(
6771 attrs | (current->enumerable() ? NONE : DONT_ENUM));
6772 }
6773 if (desc->has_configurable()) {
6774 attrs = static_cast<PropertyAttributes>(
6775 attrs | (desc->configurable() ? NONE : DONT_DELETE));
6776 } else {
6777 attrs = static_cast<PropertyAttributes>(
6778 attrs | (current->configurable() ? NONE : DONT_DELETE));
6779 }
6780 if (desc_is_data_descriptor ||
6781 (desc_is_generic_descriptor && current_is_data_descriptor)) {
6782 if (desc->has_writable()) {
6783 attrs = static_cast<PropertyAttributes>(
6784 attrs | (desc->writable() ? NONE : READ_ONLY));
6785 } else {
6786 attrs = static_cast<PropertyAttributes>(
6787 attrs | (current->writable() ? NONE : READ_ONLY));
6788 }
6789 Handle<Object> value(
6790 desc->has_value() ? desc->value()
6791 : current->has_value()
6792 ? current->value()
6793 : Handle<Object>::cast(
6794 isolate->factory()->undefined_value()));
6795 MaybeHandle<Object> result = JSObject::DefineOwnPropertyIgnoreAttributes(
6796 it, value, attrs, JSObject::DONT_FORCE_FIELD);
6797 if (result.is_null()) return Nothing<bool>();
6798 } else {
6799 DCHECK(desc_is_accessor_descriptor ||
6800 (desc_is_generic_descriptor &&
6801 PropertyDescriptor::IsAccessorDescriptor(current)));
6802 Handle<Object> getter(
6803 desc->has_get()
6804 ? desc->get()
6805 : current->has_get()
6806 ? current->get()
6807 : Handle<Object>::cast(isolate->factory()->null_value()));
6808 Handle<Object> setter(
6809 desc->has_set()
6810 ? desc->set()
6811 : current->has_set()
6812 ? current->set()
6813 : Handle<Object>::cast(isolate->factory()->null_value()));
6814 MaybeHandle<Object> result =
6815 JSObject::DefineAccessor(it, getter, setter, attrs);
6816 if (result.is_null()) return Nothing<bool>();
6817 }
6818 }
6819
6820 // 11. Return true.
6821 return Just(true);
6822}
6823
6824
6825// static
6826Maybe<bool> JSReceiver::CreateDataProperty(LookupIterator* it,
6827 Handle<Object> value,
6828 ShouldThrow should_throw) {
6829 DCHECK(!it->check_prototype_chain());
6830 Handle<JSReceiver> receiver = Handle<JSReceiver>::cast(it->GetReceiver());
6831 Isolate* isolate = receiver->GetIsolate();
6832
6833 if (receiver->IsJSObject()) {
6834 return JSObject::CreateDataProperty(it, value); // Shortcut.
6835 }
6836
6837 PropertyDescriptor new_desc;
6838 new_desc.set_value(value);
6839 new_desc.set_writable(true);
6840 new_desc.set_enumerable(true);
6841 new_desc.set_configurable(true);
6842
6843 return JSReceiver::DefineOwnProperty(isolate, receiver, it->GetName(),
6844 &new_desc, should_throw);
6845}
6846
6847
6848Maybe<bool> JSObject::CreateDataProperty(LookupIterator* it,
6849 Handle<Object> value) {
6850 DCHECK(it->GetReceiver()->IsJSObject());
6851 MAYBE_RETURN(JSReceiver::GetPropertyAttributes(it), Nothing<bool>());
6852
6853 if (it->IsFound()) {
6854 if (!it->IsConfigurable()) return Just(false);
6855 } else {
6856 if (!JSObject::IsExtensible(Handle<JSObject>::cast(it->GetReceiver())))
6857 return Just(false);
6858 }
6859
6860 RETURN_ON_EXCEPTION_VALUE(
6861 it->isolate(),
6862 DefineOwnPropertyIgnoreAttributes(it, value, NONE, DONT_FORCE_FIELD),
6863 Nothing<bool>());
6864
6865 return Just(true);
6866}
6867
6868
6869// TODO(jkummerow): Consider unification with FastAsArrayLength() in
6870// accessors.cc.
6871bool PropertyKeyToArrayLength(Handle<Object> value, uint32_t* length) {
6872 DCHECK(value->IsNumber() || value->IsName());
6873 if (value->ToArrayLength(length)) return true;
6874 if (value->IsString()) return String::cast(*value)->AsArrayIndex(length);
6875 return false;
6876}
6877
6878
6879bool PropertyKeyToArrayIndex(Handle<Object> index_obj, uint32_t* output) {
6880 return PropertyKeyToArrayLength(index_obj, output) && *output != kMaxUInt32;
6881}
6882
6883
6884// ES6 9.4.2.1
6885// static
6886Maybe<bool> JSArray::DefineOwnProperty(Isolate* isolate, Handle<JSArray> o,
6887 Handle<Object> name,
6888 PropertyDescriptor* desc,
6889 ShouldThrow should_throw) {
6890 // 1. Assert: IsPropertyKey(P) is true. ("P" is |name|.)
6891 // 2. If P is "length", then:
6892 // TODO(jkummerow): Check if we need slow string comparison.
6893 if (*name == isolate->heap()->length_string()) {
6894 // 2a. Return ArraySetLength(A, Desc).
6895 return ArraySetLength(isolate, o, desc, should_throw);
6896 }
6897 // 3. Else if P is an array index, then:
6898 uint32_t index = 0;
6899 if (PropertyKeyToArrayIndex(name, &index)) {
6900 // 3a. Let oldLenDesc be OrdinaryGetOwnProperty(A, "length").
6901 PropertyDescriptor old_len_desc;
6902 Maybe<bool> success = GetOwnPropertyDescriptor(
6903 isolate, o, isolate->factory()->length_string(), &old_len_desc);
6904 // 3b. (Assert)
6905 DCHECK(success.FromJust());
6906 USE(success);
6907 // 3c. Let oldLen be oldLenDesc.[[Value]].
6908 uint32_t old_len = 0;
6909 CHECK(old_len_desc.value()->ToArrayLength(&old_len));
6910 // 3d. Let index be ToUint32(P).
6911 // (Already done above.)
6912 // 3e. (Assert)
6913 // 3f. If index >= oldLen and oldLenDesc.[[Writable]] is false,
6914 // return false.
6915 if (index >= old_len && old_len_desc.has_writable() &&
6916 !old_len_desc.writable()) {
6917 RETURN_FAILURE(isolate, should_throw,
6918 NewTypeError(MessageTemplate::kDefineDisallowed, name));
6919 }
6920 // 3g. Let succeeded be OrdinaryDefineOwnProperty(A, P, Desc).
6921 Maybe<bool> succeeded =
6922 OrdinaryDefineOwnProperty(isolate, o, name, desc, should_throw);
6923 // 3h. Assert: succeeded is not an abrupt completion.
6924 // In our case, if should_throw == THROW_ON_ERROR, it can be!
6925 // 3i. If succeeded is false, return false.
6926 if (succeeded.IsNothing() || !succeeded.FromJust()) return succeeded;
6927 // 3j. If index >= oldLen, then:
6928 if (index >= old_len) {
6929 // 3j i. Set oldLenDesc.[[Value]] to index + 1.
6930 old_len_desc.set_value(isolate->factory()->NewNumberFromUint(index + 1));
6931 // 3j ii. Let succeeded be
6932 // OrdinaryDefineOwnProperty(A, "length", oldLenDesc).
6933 succeeded = OrdinaryDefineOwnProperty(isolate, o,
6934 isolate->factory()->length_string(),
6935 &old_len_desc, should_throw);
6936 // 3j iii. Assert: succeeded is true.
6937 DCHECK(succeeded.FromJust());
6938 USE(succeeded);
6939 }
6940 // 3k. Return true.
6941 return Just(true);
6942 }
6943
6944 // 4. Return OrdinaryDefineOwnProperty(A, P, Desc).
6945 return OrdinaryDefineOwnProperty(isolate, o, name, desc, should_throw);
6946}
6947
6948
6949// Part of ES6 9.4.2.4 ArraySetLength.
6950// static
6951bool JSArray::AnythingToArrayLength(Isolate* isolate,
6952 Handle<Object> length_object,
6953 uint32_t* output) {
6954 // Fast path: check numbers and strings that can be converted directly
6955 // and unobservably.
6956 if (length_object->ToArrayLength(output)) return true;
6957 if (length_object->IsString() &&
6958 Handle<String>::cast(length_object)->AsArrayIndex(output)) {
6959 return true;
6960 }
6961 // Slow path: follow steps in ES6 9.4.2.4 "ArraySetLength".
6962 // 3. Let newLen be ToUint32(Desc.[[Value]]).
6963 Handle<Object> uint32_v;
6964 if (!Object::ToUint32(isolate, length_object).ToHandle(&uint32_v)) {
6965 // 4. ReturnIfAbrupt(newLen).
6966 return false;
6967 }
6968 // 5. Let numberLen be ToNumber(Desc.[[Value]]).
6969 Handle<Object> number_v;
6970 if (!Object::ToNumber(length_object).ToHandle(&number_v)) {
6971 // 6. ReturnIfAbrupt(newLen).
6972 return false;
6973 }
6974 // 7. If newLen != numberLen, throw a RangeError exception.
6975 if (uint32_v->Number() != number_v->Number()) {
6976 Handle<Object> exception =
6977 isolate->factory()->NewRangeError(MessageTemplate::kInvalidArrayLength);
6978 isolate->Throw(*exception);
6979 return false;
6980 }
6981 CHECK(uint32_v->ToArrayLength(output));
6982 return true;
6983}
6984
6985
6986// ES6 9.4.2.4
6987// static
6988Maybe<bool> JSArray::ArraySetLength(Isolate* isolate, Handle<JSArray> a,
6989 PropertyDescriptor* desc,
6990 ShouldThrow should_throw) {
6991 // 1. If the [[Value]] field of Desc is absent, then
6992 if (!desc->has_value()) {
6993 // 1a. Return OrdinaryDefineOwnProperty(A, "length", Desc).
6994 return OrdinaryDefineOwnProperty(
6995 isolate, a, isolate->factory()->length_string(), desc, should_throw);
6996 }
6997 // 2. Let newLenDesc be a copy of Desc.
6998 // (Actual copying is not necessary.)
6999 PropertyDescriptor* new_len_desc = desc;
7000 // 3. - 7. Convert Desc.[[Value]] to newLen.
7001 uint32_t new_len = 0;
7002 if (!AnythingToArrayLength(isolate, desc->value(), &new_len)) {
7003 DCHECK(isolate->has_pending_exception());
7004 return Nothing<bool>();
7005 }
7006 // 8. Set newLenDesc.[[Value]] to newLen.
7007 // (Done below, if needed.)
7008 // 9. Let oldLenDesc be OrdinaryGetOwnProperty(A, "length").
7009 PropertyDescriptor old_len_desc;
7010 Maybe<bool> success = GetOwnPropertyDescriptor(
7011 isolate, a, isolate->factory()->length_string(), &old_len_desc);
7012 // 10. (Assert)
7013 DCHECK(success.FromJust());
7014 USE(success);
7015 // 11. Let oldLen be oldLenDesc.[[Value]].
7016 uint32_t old_len = 0;
7017 CHECK(old_len_desc.value()->ToArrayLength(&old_len));
7018 // 12. If newLen >= oldLen, then
7019 if (new_len >= old_len) {
7020 // 8. Set newLenDesc.[[Value]] to newLen.
7021 // 12a. Return OrdinaryDefineOwnProperty(A, "length", newLenDesc).
7022 new_len_desc->set_value(isolate->factory()->NewNumberFromUint(new_len));
7023 return OrdinaryDefineOwnProperty(isolate, a,
7024 isolate->factory()->length_string(),
7025 new_len_desc, should_throw);
7026 }
7027 // 13. If oldLenDesc.[[Writable]] is false, return false.
7028 if (!old_len_desc.writable()) {
7029 RETURN_FAILURE(isolate, should_throw,
7030 NewTypeError(MessageTemplate::kRedefineDisallowed,
7031 isolate->factory()->length_string()));
7032 }
7033 // 14. If newLenDesc.[[Writable]] is absent or has the value true,
7034 // let newWritable be true.
7035 bool new_writable = false;
7036 if (!new_len_desc->has_writable() || new_len_desc->writable()) {
7037 new_writable = true;
7038 } else {
7039 // 15. Else,
7040 // 15a. Need to defer setting the [[Writable]] attribute to false in case
7041 // any elements cannot be deleted.
7042 // 15b. Let newWritable be false. (It's initialized as "false" anyway.)
7043 // 15c. Set newLenDesc.[[Writable]] to true.
7044 // (Not needed.)
7045 }
7046 // Most of steps 16 through 19 is implemented by JSArray::SetLength.
7047 if (JSArray::ObservableSetLength(a, new_len).is_null()) {
7048 DCHECK(isolate->has_pending_exception());
7049 return Nothing<bool>();
7050 }
7051 // Steps 19d-ii, 20.
7052 if (!new_writable) {
7053 PropertyDescriptor readonly;
7054 readonly.set_writable(false);
7055 Maybe<bool> success = OrdinaryDefineOwnProperty(
7056 isolate, a, isolate->factory()->length_string(), &readonly,
7057 should_throw);
7058 DCHECK(success.FromJust());
7059 USE(success);
7060 }
7061 uint32_t actual_new_len = 0;
7062 CHECK(a->length()->ToArrayLength(&actual_new_len));
7063 // Steps 19d-v, 21. Return false if there were non-deletable elements.
7064 bool result = actual_new_len == new_len;
7065 if (!result) {
7066 RETURN_FAILURE(
7067 isolate, should_throw,
7068 NewTypeError(MessageTemplate::kStrictDeleteProperty,
7069 isolate->factory()->NewNumberFromUint(actual_new_len - 1),
7070 a));
7071 }
7072 return Just(result);
7073}
7074
7075
7076// ES6 9.5.6
7077// static
7078Maybe<bool> JSProxy::DefineOwnProperty(Isolate* isolate, Handle<JSProxy> proxy,
7079 Handle<Object> key,
7080 PropertyDescriptor* desc,
7081 ShouldThrow should_throw) {
7082 STACK_CHECK(Nothing<bool>());
7083 if (key->IsSymbol() && Handle<Symbol>::cast(key)->IsPrivate()) {
7084 return AddPrivateProperty(isolate, proxy, Handle<Symbol>::cast(key), desc,
7085 should_throw);
7086 }
7087 Handle<String> trap_name = isolate->factory()->defineProperty_string();
7088 // 1. Assert: IsPropertyKey(P) is true.
7089 DCHECK(key->IsName() || key->IsNumber());
7090 // 2. Let handler be the value of the [[ProxyHandler]] internal slot of O.
7091 Handle<Object> handler(proxy->handler(), isolate);
7092 // 3. If handler is null, throw a TypeError exception.
7093 // 4. Assert: Type(handler) is Object.
7094 if (proxy->IsRevoked()) {
7095 isolate->Throw(*isolate->factory()->NewTypeError(
7096 MessageTemplate::kProxyRevoked, trap_name));
7097 return Nothing<bool>();
7098 }
7099 // 5. Let target be the value of the [[ProxyTarget]] internal slot of O.
7100 Handle<JSReceiver> target(proxy->target(), isolate);
7101 // 6. Let trap be ? GetMethod(handler, "defineProperty").
7102 Handle<Object> trap;
7103 ASSIGN_RETURN_ON_EXCEPTION_VALUE(
7104 isolate, trap,
7105 Object::GetMethod(Handle<JSReceiver>::cast(handler), trap_name),
7106 Nothing<bool>());
7107 // 7. If trap is undefined, then:
7108 if (trap->IsUndefined()) {
7109 // 7a. Return target.[[DefineOwnProperty]](P, Desc).
7110 return JSReceiver::DefineOwnProperty(isolate, target, key, desc,
7111 should_throw);
7112 }
7113 // 8. Let descObj be FromPropertyDescriptor(Desc).
7114 Handle<Object> desc_obj = desc->ToObject(isolate);
7115 // 9. Let booleanTrapResult be
7116 // ToBoolean(? Call(trap, handler, «target, P, descObj»)).
7117 Handle<Name> property_name =
7118 key->IsName()
7119 ? Handle<Name>::cast(key)
7120 : Handle<Name>::cast(isolate->factory()->NumberToString(key));
7121 // Do not leak private property names.
7122 DCHECK(!property_name->IsPrivate());
7123 Handle<Object> trap_result_obj;
7124 Handle<Object> args[] = {target, property_name, desc_obj};
7125 ASSIGN_RETURN_ON_EXCEPTION_VALUE(
7126 isolate, trap_result_obj,
7127 Execution::Call(isolate, trap, handler, arraysize(args), args),
7128 Nothing<bool>());
7129 // 10. If booleanTrapResult is false, return false.
7130 if (!trap_result_obj->BooleanValue()) {
7131 RETURN_FAILURE(isolate, should_throw,
7132 NewTypeError(MessageTemplate::kProxyTrapReturnedFalsishFor,
7133 trap_name, property_name));
7134 }
7135 // 11. Let targetDesc be ? target.[[GetOwnProperty]](P).
7136 PropertyDescriptor target_desc;
7137 Maybe<bool> target_found =
7138 JSReceiver::GetOwnPropertyDescriptor(isolate, target, key, &target_desc);
7139 MAYBE_RETURN(target_found, Nothing<bool>());
7140 // 12. Let extensibleTarget be ? IsExtensible(target).
7141 Maybe<bool> maybe_extensible = JSReceiver::IsExtensible(target);
7142 MAYBE_RETURN(maybe_extensible, Nothing<bool>());
7143 bool extensible_target = maybe_extensible.FromJust();
7144 // 13. If Desc has a [[Configurable]] field and if Desc.[[Configurable]]
7145 // is false, then:
7146 // 13a. Let settingConfigFalse be true.
7147 // 14. Else let settingConfigFalse be false.
7148 bool setting_config_false = desc->has_configurable() && !desc->configurable();
7149 // 15. If targetDesc is undefined, then
7150 if (!target_found.FromJust()) {
7151 // 15a. If extensibleTarget is false, throw a TypeError exception.
7152 if (!extensible_target) {
7153 isolate->Throw(*isolate->factory()->NewTypeError(
7154 MessageTemplate::kProxyDefinePropertyNonExtensible, property_name));
7155 return Nothing<bool>();
7156 }
7157 // 15b. If settingConfigFalse is true, throw a TypeError exception.
7158 if (setting_config_false) {
7159 isolate->Throw(*isolate->factory()->NewTypeError(
7160 MessageTemplate::kProxyDefinePropertyNonConfigurable, property_name));
7161 return Nothing<bool>();
7162 }
7163 } else {
7164 // 16. Else targetDesc is not undefined,
7165 // 16a. If IsCompatiblePropertyDescriptor(extensibleTarget, Desc,
7166 // targetDesc) is false, throw a TypeError exception.
7167 Maybe<bool> valid =
7168 IsCompatiblePropertyDescriptor(isolate, extensible_target, desc,
7169 &target_desc, property_name, DONT_THROW);
7170 MAYBE_RETURN(valid, Nothing<bool>());
7171 if (!valid.FromJust()) {
7172 isolate->Throw(*isolate->factory()->NewTypeError(
7173 MessageTemplate::kProxyDefinePropertyIncompatible, property_name));
7174 return Nothing<bool>();
7175 }
7176 // 16b. If settingConfigFalse is true and targetDesc.[[Configurable]] is
7177 // true, throw a TypeError exception.
7178 if (setting_config_false && target_desc.configurable()) {
7179 isolate->Throw(*isolate->factory()->NewTypeError(
7180 MessageTemplate::kProxyDefinePropertyNonConfigurable, property_name));
7181 return Nothing<bool>();
7182 }
7183 }
7184 // 17. Return true.
7185 return Just(true);
7186}
7187
7188
7189// static
7190Maybe<bool> JSProxy::AddPrivateProperty(Isolate* isolate, Handle<JSProxy> proxy,
7191 Handle<Symbol> private_name,
7192 PropertyDescriptor* desc,
7193 ShouldThrow should_throw) {
7194 // Despite the generic name, this can only add private data properties.
7195 if (!PropertyDescriptor::IsDataDescriptor(desc) ||
7196 desc->ToAttributes() != DONT_ENUM) {
7197 RETURN_FAILURE(isolate, should_throw,
7198 NewTypeError(MessageTemplate::kProxyPrivate));
7199 }
7200 DCHECK(proxy->map()->is_dictionary_map());
7201 Handle<Object> value =
7202 desc->has_value()
7203 ? desc->value()
7204 : Handle<Object>::cast(isolate->factory()->undefined_value());
7205
7206 LookupIterator it(proxy, private_name);
7207
7208 if (it.IsFound()) {
7209 DCHECK_EQ(LookupIterator::DATA, it.state());
7210 DCHECK_EQ(DONT_ENUM, it.property_details().attributes());
7211 it.WriteDataValue(value);
7212 return Just(true);
7213 }
7214
7215 Handle<NameDictionary> dict(proxy->property_dictionary());
7216 PropertyDetails details(DONT_ENUM, DATA, 0, PropertyCellType::kNoCell);
7217 Handle<NameDictionary> result =
7218 NameDictionary::Add(dict, private_name, value, details);
7219 if (!dict.is_identical_to(result)) proxy->set_properties(*result);
7220 return Just(true);
7221}
7222
7223
7224// static
7225Maybe<bool> JSReceiver::GetOwnPropertyDescriptor(Isolate* isolate,
7226 Handle<JSReceiver> object,
7227 Handle<Object> key,
7228 PropertyDescriptor* desc) {
7229 bool success = false;
7230 DCHECK(key->IsName() || key->IsNumber()); // |key| is a PropertyKey...
7231 LookupIterator it = LookupIterator::PropertyOrElement(
7232 isolate, object, key, &success, LookupIterator::HIDDEN);
7233 DCHECK(success); // ...so creating a LookupIterator can't fail.
7234 return GetOwnPropertyDescriptor(&it, desc);
7235}
7236
7237
7238// ES6 9.1.5.1
7239// Returns true on success, false if the property didn't exist, nothing if
7240// an exception was thrown.
7241// static
7242Maybe<bool> JSReceiver::GetOwnPropertyDescriptor(LookupIterator* it,
7243 PropertyDescriptor* desc) {
7244 Isolate* isolate = it->isolate();
7245 // "Virtual" dispatch.
7246 if (it->IsFound() && it->GetHolder<JSReceiver>()->IsJSProxy()) {
7247 return JSProxy::GetOwnPropertyDescriptor(isolate, it->GetHolder<JSProxy>(),
7248 it->GetName(), desc);
7249 }
7250
7251 // 1. (Assert)
7252 // 2. If O does not have an own property with key P, return undefined.
7253 Maybe<PropertyAttributes> maybe = JSObject::GetPropertyAttributes(it);
7254 MAYBE_RETURN(maybe, Nothing<bool>());
7255 PropertyAttributes attrs = maybe.FromJust();
7256 if (attrs == ABSENT) return Just(false);
7257 DCHECK(!isolate->has_pending_exception());
7258
7259 // 3. Let D be a newly created Property Descriptor with no fields.
7260 DCHECK(desc->is_empty());
7261 // 4. Let X be O's own property whose key is P.
7262 // 5. If X is a data property, then
7263 bool is_accessor_pair = it->state() == LookupIterator::ACCESSOR &&
7264 it->GetAccessors()->IsAccessorPair();
7265 if (!is_accessor_pair) {
7266 // 5a. Set D.[[Value]] to the value of X's [[Value]] attribute.
7267 Handle<Object> value;
7268 if (!JSObject::GetProperty(it).ToHandle(&value)) {
7269 DCHECK(isolate->has_pending_exception());
7270 return Nothing<bool>();
7271 }
7272 desc->set_value(value);
7273 // 5b. Set D.[[Writable]] to the value of X's [[Writable]] attribute
7274 desc->set_writable((attrs & READ_ONLY) == 0);
7275 } else {
7276 // 6. Else X is an accessor property, so
7277 Handle<AccessorPair> accessors =
7278 Handle<AccessorPair>::cast(it->GetAccessors());
7279 // 6a. Set D.[[Get]] to the value of X's [[Get]] attribute.
7280 desc->set_get(handle(accessors->GetComponent(ACCESSOR_GETTER), isolate));
7281 // 6b. Set D.[[Set]] to the value of X's [[Set]] attribute.
7282 desc->set_set(handle(accessors->GetComponent(ACCESSOR_SETTER), isolate));
7283 }
7284
7285 // 7. Set D.[[Enumerable]] to the value of X's [[Enumerable]] attribute.
7286 desc->set_enumerable((attrs & DONT_ENUM) == 0);
7287 // 8. Set D.[[Configurable]] to the value of X's [[Configurable]] attribute.
7288 desc->set_configurable((attrs & DONT_DELETE) == 0);
7289 // 9. Return D.
7290 DCHECK(PropertyDescriptor::IsAccessorDescriptor(desc) !=
7291 PropertyDescriptor::IsDataDescriptor(desc));
7292 return Just(true);
7293}
7294
7295
7296// ES6 9.5.5
7297// static
7298Maybe<bool> JSProxy::GetOwnPropertyDescriptor(Isolate* isolate,
7299 Handle<JSProxy> proxy,
7300 Handle<Name> name,
7301 PropertyDescriptor* desc) {
7302 DCHECK(!name->IsPrivate());
7303 STACK_CHECK(Nothing<bool>());
7304
7305 Handle<String> trap_name =
7306 isolate->factory()->getOwnPropertyDescriptor_string();
7307 // 1. (Assert)
7308 // 2. Let handler be the value of the [[ProxyHandler]] internal slot of O.
7309 Handle<Object> handler(proxy->handler(), isolate);
7310 // 3. If handler is null, throw a TypeError exception.
7311 // 4. Assert: Type(handler) is Object.
7312 if (proxy->IsRevoked()) {
7313 isolate->Throw(*isolate->factory()->NewTypeError(
7314 MessageTemplate::kProxyRevoked, trap_name));
7315 return Nothing<bool>();
7316 }
7317 // 5. Let target be the value of the [[ProxyTarget]] internal slot of O.
7318 Handle<JSReceiver> target(proxy->target(), isolate);
7319 // 6. Let trap be ? GetMethod(handler, "getOwnPropertyDescriptor").
7320 Handle<Object> trap;
7321 ASSIGN_RETURN_ON_EXCEPTION_VALUE(
7322 isolate, trap,
7323 Object::GetMethod(Handle<JSReceiver>::cast(handler), trap_name),
7324 Nothing<bool>());
7325 // 7. If trap is undefined, then
7326 if (trap->IsUndefined()) {
7327 // 7a. Return target.[[GetOwnProperty]](P).
7328 return JSReceiver::GetOwnPropertyDescriptor(isolate, target, name, desc);
7329 }
7330 // 8. Let trapResultObj be ? Call(trap, handler, «target, P»).
7331 Handle<Object> trap_result_obj;
7332 Handle<Object> args[] = {target, name};
7333 ASSIGN_RETURN_ON_EXCEPTION_VALUE(
7334 isolate, trap_result_obj,
7335 Execution::Call(isolate, trap, handler, arraysize(args), args),
7336 Nothing<bool>());
7337 // 9. If Type(trapResultObj) is neither Object nor Undefined, throw a
7338 // TypeError exception.
7339 if (!trap_result_obj->IsJSReceiver() && !trap_result_obj->IsUndefined()) {
7340 isolate->Throw(*isolate->factory()->NewTypeError(
7341 MessageTemplate::kProxyGetOwnPropertyDescriptorInvalid, name));
7342 return Nothing<bool>();
7343 }
7344 // 10. Let targetDesc be ? target.[[GetOwnProperty]](P).
7345 PropertyDescriptor target_desc;
7346 Maybe<bool> found =
7347 JSReceiver::GetOwnPropertyDescriptor(isolate, target, name, &target_desc);
7348 MAYBE_RETURN(found, Nothing<bool>());
7349 // 11. If trapResultObj is undefined, then
7350 if (trap_result_obj->IsUndefined()) {
7351 // 11a. If targetDesc is undefined, return undefined.
7352 if (!found.FromJust()) return Just(false);
7353 // 11b. If targetDesc.[[Configurable]] is false, throw a TypeError
7354 // exception.
7355 if (!target_desc.configurable()) {
7356 isolate->Throw(*isolate->factory()->NewTypeError(
7357 MessageTemplate::kProxyGetOwnPropertyDescriptorUndefined, name));
7358 return Nothing<bool>();
7359 }
7360 // 11c. Let extensibleTarget be ? IsExtensible(target).
7361 Maybe<bool> extensible_target = JSReceiver::IsExtensible(target);
7362 MAYBE_RETURN(extensible_target, Nothing<bool>());
7363 // 11d. (Assert)
7364 // 11e. If extensibleTarget is false, throw a TypeError exception.
7365 if (!extensible_target.FromJust()) {
7366 isolate->Throw(*isolate->factory()->NewTypeError(
7367 MessageTemplate::kProxyGetOwnPropertyDescriptorNonExtensible, name));
7368 return Nothing<bool>();
7369 }
7370 // 11f. Return undefined.
7371 return Just(false);
7372 }
7373 // 12. Let extensibleTarget be ? IsExtensible(target).
7374 Maybe<bool> extensible_target = JSReceiver::IsExtensible(target);
7375 MAYBE_RETURN(extensible_target, Nothing<bool>());
7376 // 13. Let resultDesc be ? ToPropertyDescriptor(trapResultObj).
7377 if (!PropertyDescriptor::ToPropertyDescriptor(isolate, trap_result_obj,
7378 desc)) {
7379 DCHECK(isolate->has_pending_exception());
7380 return Nothing<bool>();
7381 }
7382 // 14. Call CompletePropertyDescriptor(resultDesc).
7383 PropertyDescriptor::CompletePropertyDescriptor(isolate, desc);
7384 // 15. Let valid be IsCompatiblePropertyDescriptor (extensibleTarget,
7385 // resultDesc, targetDesc).
7386 Maybe<bool> valid =
7387 IsCompatiblePropertyDescriptor(isolate, extensible_target.FromJust(),
7388 desc, &target_desc, name, DONT_THROW);
7389 MAYBE_RETURN(valid, Nothing<bool>());
7390 // 16. If valid is false, throw a TypeError exception.
7391 if (!valid.FromJust()) {
7392 isolate->Throw(*isolate->factory()->NewTypeError(
7393 MessageTemplate::kProxyGetOwnPropertyDescriptorIncompatible, name));
7394 return Nothing<bool>();
7395 }
7396 // 17. If resultDesc.[[Configurable]] is false, then
7397 if (!desc->configurable()) {
7398 // 17a. If targetDesc is undefined or targetDesc.[[Configurable]] is true:
7399 if (target_desc.is_empty() || target_desc.configurable()) {
7400 // 17a i. Throw a TypeError exception.
7401 isolate->Throw(*isolate->factory()->NewTypeError(
7402 MessageTemplate::kProxyGetOwnPropertyDescriptorNonConfigurable,
7403 name));
7404 return Nothing<bool>();
7405 }
7406 }
7407 // 18. Return resultDesc.
7408 return Just(true);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01007409}
7410
7411
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00007412bool JSObject::ReferencesObjectFromElements(FixedArray* elements,
7413 ElementsKind kind,
7414 Object* object) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007415 DCHECK(IsFastObjectElementsKind(kind) ||
Ben Murdoch3ef787d2012-04-12 10:51:47 +01007416 kind == DICTIONARY_ELEMENTS);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007417 if (IsFastObjectElementsKind(kind)) {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00007418 int length = IsJSArray()
7419 ? Smi::cast(JSArray::cast(this)->length())->value()
7420 : elements->length();
7421 for (int i = 0; i < length; ++i) {
7422 Object* element = elements->get(i);
7423 if (!element->IsTheHole() && element == object) return true;
7424 }
7425 } else {
Ben Murdochc7cc0282012-03-05 14:35:55 +00007426 Object* key =
7427 SeededNumberDictionary::cast(elements)->SlowReverseLookup(object);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00007428 if (!key->IsUndefined()) return true;
7429 }
7430 return false;
7431}
7432
7433
Steve Blocka7e24c12009-10-30 11:49:00 +00007434// Check whether this object references another object.
7435bool JSObject::ReferencesObject(Object* obj) {
Ben Murdoch8b112d22011-06-08 16:22:53 +01007436 Map* map_of_this = map();
Ben Murdoch3ef787d2012-04-12 10:51:47 +01007437 Heap* heap = GetHeap();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007438 DisallowHeapAllocation no_allocation;
Steve Blocka7e24c12009-10-30 11:49:00 +00007439
7440 // Is the object the constructor for this object?
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00007441 if (map_of_this->GetConstructor() == obj) {
Steve Blocka7e24c12009-10-30 11:49:00 +00007442 return true;
7443 }
7444
7445 // Is the object the prototype for this object?
Ben Murdoch8b112d22011-06-08 16:22:53 +01007446 if (map_of_this->prototype() == obj) {
Steve Blocka7e24c12009-10-30 11:49:00 +00007447 return true;
7448 }
7449
7450 // Check if the object is among the named properties.
7451 Object* key = SlowReverseLookup(obj);
Steve Block44f0eee2011-05-26 01:26:41 +01007452 if (!key->IsUndefined()) {
Steve Blocka7e24c12009-10-30 11:49:00 +00007453 return true;
7454 }
7455
7456 // Check if the object is among the indexed properties.
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00007457 ElementsKind kind = GetElementsKind();
7458 switch (kind) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007459 // Raw pixels and external arrays do not reference other
7460 // objects.
7461#define TYPED_ARRAY_CASE(Type, type, TYPE, ctype, size) \
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007462 case TYPE##_ELEMENTS: \
Steve Blocka7e24c12009-10-30 11:49:00 +00007463 break;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007464
7465 TYPED_ARRAYS(TYPED_ARRAY_CASE)
7466#undef TYPED_ARRAY_CASE
7467
7468 case FAST_DOUBLE_ELEMENTS:
7469 case FAST_HOLEY_DOUBLE_ELEMENTS:
7470 break;
7471 case FAST_SMI_ELEMENTS:
7472 case FAST_HOLEY_SMI_ELEMENTS:
Ben Murdoch3ef787d2012-04-12 10:51:47 +01007473 break;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00007474 case FAST_ELEMENTS:
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007475 case FAST_HOLEY_ELEMENTS:
Steve Blocka7e24c12009-10-30 11:49:00 +00007476 case DICTIONARY_ELEMENTS: {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00007477 FixedArray* elements = FixedArray::cast(this->elements());
7478 if (ReferencesObjectFromElements(elements, kind, obj)) return true;
Steve Blocka7e24c12009-10-30 11:49:00 +00007479 break;
7480 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00007481 case FAST_SLOPPY_ARGUMENTS_ELEMENTS:
7482 case SLOW_SLOPPY_ARGUMENTS_ELEMENTS: {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00007483 FixedArray* parameter_map = FixedArray::cast(elements());
7484 // Check the mapped parameters.
7485 int length = parameter_map->length();
7486 for (int i = 2; i < length; ++i) {
7487 Object* value = parameter_map->get(i);
7488 if (!value->IsTheHole() && value == obj) return true;
7489 }
7490 // Check the arguments.
7491 FixedArray* arguments = FixedArray::cast(parameter_map->get(1));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007492 kind = arguments->IsDictionary() ? DICTIONARY_ELEMENTS :
7493 FAST_HOLEY_ELEMENTS;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00007494 if (ReferencesObjectFromElements(arguments, kind, obj)) return true;
Steve Blocka7e24c12009-10-30 11:49:00 +00007495 break;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00007496 }
Steve Blocka7e24c12009-10-30 11:49:00 +00007497 }
7498
Steve Block6ded16b2010-05-10 14:33:55 +01007499 // For functions check the context.
7500 if (IsJSFunction()) {
Steve Blocka7e24c12009-10-30 11:49:00 +00007501 // Get the constructor function for arguments array.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007502 Map* arguments_map =
7503 heap->isolate()->context()->native_context()->sloppy_arguments_map();
Steve Blocka7e24c12009-10-30 11:49:00 +00007504 JSFunction* arguments_function =
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00007505 JSFunction::cast(arguments_map->GetConstructor());
Steve Blocka7e24c12009-10-30 11:49:00 +00007506
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007507 // Get the context and don't check if it is the native context.
Steve Blocka7e24c12009-10-30 11:49:00 +00007508 JSFunction* f = JSFunction::cast(this);
7509 Context* context = f->context();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007510 if (context->IsNativeContext()) {
Steve Blocka7e24c12009-10-30 11:49:00 +00007511 return false;
7512 }
7513
7514 // Check the non-special context slots.
7515 for (int i = Context::MIN_CONTEXT_SLOTS; i < context->length(); i++) {
7516 // Only check JS objects.
7517 if (context->get(i)->IsJSObject()) {
7518 JSObject* ctxobj = JSObject::cast(context->get(i));
7519 // If it is an arguments array check the content.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00007520 if (ctxobj->map()->GetConstructor() == arguments_function) {
Steve Blocka7e24c12009-10-30 11:49:00 +00007521 if (ctxobj->ReferencesObject(obj)) {
7522 return true;
7523 }
7524 } else if (ctxobj == obj) {
7525 return true;
7526 }
7527 }
7528 }
7529
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00007530 // Check the context extension (if any) if it can have references.
7531 if (context->has_extension() && !context->IsCatchContext()) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00007532 // With harmony scoping, a JSFunction may have a script context.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007533 // TODO(mvstanton): walk into the ScopeInfo.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00007534 if (context->IsScriptContext()) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007535 return false;
7536 }
7537
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00007538 return context->extension_object()->ReferencesObject(obj);
Steve Blocka7e24c12009-10-30 11:49:00 +00007539 }
7540 }
7541
7542 // No references to object.
7543 return false;
7544}
7545
7546
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00007547Maybe<bool> JSReceiver::SetIntegrityLevel(Handle<JSReceiver> receiver,
7548 IntegrityLevel level,
7549 ShouldThrow should_throw) {
7550 DCHECK(level == SEALED || level == FROZEN);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01007551
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00007552 if (receiver->IsJSObject()) {
7553 Handle<JSObject> object = Handle<JSObject>::cast(receiver);
7554 if (!object->HasSloppyArgumentsElements() &&
7555 !object->map()->is_observed() &&
7556 (!object->map()->is_strong() || level == SEALED)) { // Fast path.
7557 if (level == SEALED) {
7558 return JSObject::PreventExtensionsWithTransition<SEALED>(object,
7559 should_throw);
7560 } else {
7561 return JSObject::PreventExtensionsWithTransition<FROZEN>(object,
7562 should_throw);
7563 }
7564 }
Emily Bernierd0a1eb72015-03-24 16:35:39 -04007565 }
7566
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00007567 Isolate* isolate = receiver->GetIsolate();
7568
7569 MAYBE_RETURN(JSReceiver::PreventExtensions(receiver, should_throw),
7570 Nothing<bool>());
7571
7572 Handle<FixedArray> keys;
7573 ASSIGN_RETURN_ON_EXCEPTION_VALUE(
7574 isolate, keys, JSReceiver::OwnPropertyKeys(receiver), Nothing<bool>());
7575
7576 PropertyDescriptor no_conf;
7577 no_conf.set_configurable(false);
7578
7579 PropertyDescriptor no_conf_no_write;
7580 no_conf_no_write.set_configurable(false);
7581 no_conf_no_write.set_writable(false);
7582
7583 if (level == SEALED) {
7584 for (int i = 0; i < keys->length(); ++i) {
7585 Handle<Object> key(keys->get(i), isolate);
7586 MAYBE_RETURN(
7587 DefineOwnProperty(isolate, receiver, key, &no_conf, THROW_ON_ERROR),
7588 Nothing<bool>());
7589 }
7590 return Just(true);
7591 }
7592
7593 for (int i = 0; i < keys->length(); ++i) {
7594 Handle<Object> key(keys->get(i), isolate);
7595 PropertyDescriptor current_desc;
7596 Maybe<bool> owned = JSReceiver::GetOwnPropertyDescriptor(
7597 isolate, receiver, key, &current_desc);
7598 MAYBE_RETURN(owned, Nothing<bool>());
7599 if (owned.FromJust()) {
7600 PropertyDescriptor desc =
7601 PropertyDescriptor::IsAccessorDescriptor(&current_desc)
7602 ? no_conf
7603 : no_conf_no_write;
7604 MAYBE_RETURN(
7605 DefineOwnProperty(isolate, receiver, key, &desc, THROW_ON_ERROR),
7606 Nothing<bool>());
7607 }
7608 }
7609 return Just(true);
7610}
7611
7612
7613Maybe<bool> JSReceiver::TestIntegrityLevel(Handle<JSReceiver> object,
7614 IntegrityLevel level) {
7615 DCHECK(level == SEALED || level == FROZEN);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04007616 Isolate* isolate = object->GetIsolate();
7617
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00007618 Maybe<bool> extensible = JSReceiver::IsExtensible(object);
7619 MAYBE_RETURN(extensible, Nothing<bool>());
7620 if (extensible.FromJust()) return Just(false);
7621
7622 Handle<FixedArray> keys;
7623 ASSIGN_RETURN_ON_EXCEPTION_VALUE(
7624 isolate, keys, JSReceiver::OwnPropertyKeys(object), Nothing<bool>());
7625
7626 for (int i = 0; i < keys->length(); ++i) {
7627 Handle<Object> key(keys->get(i), isolate);
7628 PropertyDescriptor current_desc;
7629 Maybe<bool> owned = JSReceiver::GetOwnPropertyDescriptor(
7630 isolate, object, key, &current_desc);
7631 MAYBE_RETURN(owned, Nothing<bool>());
7632 if (owned.FromJust()) {
7633 if (current_desc.configurable()) return Just(false);
7634 if (level == FROZEN &&
7635 PropertyDescriptor::IsDataDescriptor(&current_desc) &&
7636 current_desc.writable()) {
7637 return Just(false);
7638 }
7639 }
Ben Murdoche0cee9b2011-05-25 10:26:03 +01007640 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00007641 return Just(true);
7642}
7643
7644
7645Maybe<bool> JSReceiver::PreventExtensions(Handle<JSReceiver> object,
7646 ShouldThrow should_throw) {
7647 if (object->IsJSProxy()) {
7648 return JSProxy::PreventExtensions(Handle<JSProxy>::cast(object),
7649 should_throw);
7650 }
7651 DCHECK(object->IsJSObject());
7652 return JSObject::PreventExtensions(Handle<JSObject>::cast(object),
7653 should_throw);
7654}
7655
7656
7657Maybe<bool> JSProxy::PreventExtensions(Handle<JSProxy> proxy,
7658 ShouldThrow should_throw) {
7659 Isolate* isolate = proxy->GetIsolate();
7660 STACK_CHECK(Nothing<bool>());
7661 Factory* factory = isolate->factory();
7662 Handle<String> trap_name = factory->preventExtensions_string();
7663
7664 if (proxy->IsRevoked()) {
7665 isolate->Throw(
7666 *factory->NewTypeError(MessageTemplate::kProxyRevoked, trap_name));
7667 return Nothing<bool>();
7668 }
7669 Handle<JSReceiver> target(proxy->target(), isolate);
7670 Handle<JSReceiver> handler(JSReceiver::cast(proxy->handler()), isolate);
7671
7672 Handle<Object> trap;
7673 ASSIGN_RETURN_ON_EXCEPTION_VALUE(
7674 isolate, trap, Object::GetMethod(handler, trap_name), Nothing<bool>());
7675 if (trap->IsUndefined()) {
7676 return JSReceiver::PreventExtensions(target, should_throw);
7677 }
7678
7679 Handle<Object> trap_result;
7680 Handle<Object> args[] = {target};
7681 ASSIGN_RETURN_ON_EXCEPTION_VALUE(
7682 isolate, trap_result,
7683 Execution::Call(isolate, trap, handler, arraysize(args), args),
7684 Nothing<bool>());
7685 if (!trap_result->BooleanValue()) {
7686 RETURN_FAILURE(
7687 isolate, should_throw,
7688 NewTypeError(MessageTemplate::kProxyTrapReturnedFalsish, trap_name));
7689 }
7690
7691 // Enforce the invariant.
7692 Maybe<bool> target_result = JSReceiver::IsExtensible(target);
7693 MAYBE_RETURN(target_result, Nothing<bool>());
7694 if (target_result.FromJust()) {
7695 isolate->Throw(*factory->NewTypeError(
7696 MessageTemplate::kProxyPreventExtensionsExtensible));
7697 return Nothing<bool>();
7698 }
7699 return Just(true);
7700}
7701
7702
7703Maybe<bool> JSObject::PreventExtensions(Handle<JSObject> object,
7704 ShouldThrow should_throw) {
7705 Isolate* isolate = object->GetIsolate();
7706
7707 if (!object->HasSloppyArgumentsElements() && !object->map()->is_observed()) {
7708 return PreventExtensionsWithTransition<NONE>(object, should_throw);
7709 }
7710
7711 if (object->IsAccessCheckNeeded() &&
7712 !isolate->MayAccess(handle(isolate->context()), object)) {
7713 isolate->ReportFailedAccessCheck(object);
7714 RETURN_VALUE_IF_SCHEDULED_EXCEPTION(isolate, Nothing<bool>());
7715 RETURN_FAILURE(isolate, should_throw,
7716 NewTypeError(MessageTemplate::kNoAccess));
7717 }
7718
7719 if (!object->map()->is_extensible()) return Just(true);
Ben Murdoche0cee9b2011-05-25 10:26:03 +01007720
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007721 if (object->IsJSGlobalProxy()) {
7722 PrototypeIterator iter(isolate, object);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00007723 if (iter.IsAtEnd()) return Just(true);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007724 DCHECK(PrototypeIterator::GetCurrent(iter)->IsJSGlobalObject());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00007725 return PreventExtensions(PrototypeIterator::GetCurrent<JSObject>(iter),
7726 should_throw);
Steve Block1e0659c2011-05-24 12:43:12 +01007727 }
7728
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00007729 if (!object->HasFixedTypedArrayElements()) {
7730 // If there are fast elements we normalize.
7731 Handle<SeededNumberDictionary> dictionary = NormalizeElements(object);
7732 DCHECK(object->HasDictionaryElements() ||
7733 object->HasSlowArgumentsElements());
7734
7735 // Make sure that we never go back to fast case.
7736 object->RequireSlowElements(*dictionary);
Ben Murdoch257744e2011-11-30 15:57:28 +00007737 }
7738
Steve Block8defd9f2010-07-08 12:39:36 +01007739 // Do a map transition, other objects with this map may still
7740 // be extensible.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007741 // TODO(adamk): Extend the NormalizedMapCache to handle non-extensible maps.
Emily Bernierd0a1eb72015-03-24 16:35:39 -04007742 Handle<Map> new_map = Map::Copy(handle(object->map()), "PreventExtensions");
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007743
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00007744 new_map->set_is_extensible(false);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007745 JSObject::MigrateToMap(object, new_map);
7746 DCHECK(!object->map()->is_extensible());
7747
7748 if (object->map()->is_observed()) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00007749 RETURN_ON_EXCEPTION_VALUE(
Emily Bernierd0a1eb72015-03-24 16:35:39 -04007750 isolate,
7751 EnqueueChangeRecord(object, "preventExtensions", Handle<Name>(),
7752 isolate->factory()->the_hole_value()),
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00007753 Nothing<bool>());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007754 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00007755 return Just(true);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007756}
7757
7758
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00007759Maybe<bool> JSReceiver::IsExtensible(Handle<JSReceiver> object) {
7760 if (object->IsJSProxy()) {
7761 return JSProxy::IsExtensible(Handle<JSProxy>::cast(object));
Emily Bernierd0a1eb72015-03-24 16:35:39 -04007762 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00007763 return Just(JSObject::IsExtensible(Handle<JSObject>::cast(object)));
7764}
7765
7766
7767Maybe<bool> JSProxy::IsExtensible(Handle<JSProxy> proxy) {
7768 Isolate* isolate = proxy->GetIsolate();
7769 STACK_CHECK(Nothing<bool>());
7770 Factory* factory = isolate->factory();
7771 Handle<String> trap_name = factory->isExtensible_string();
7772
7773 if (proxy->IsRevoked()) {
7774 isolate->Throw(
7775 *factory->NewTypeError(MessageTemplate::kProxyRevoked, trap_name));
7776 return Nothing<bool>();
7777 }
7778 Handle<JSReceiver> target(proxy->target(), isolate);
7779 Handle<JSReceiver> handler(JSReceiver::cast(proxy->handler()), isolate);
7780
7781 Handle<Object> trap;
7782 ASSIGN_RETURN_ON_EXCEPTION_VALUE(
7783 isolate, trap, Object::GetMethod(handler, trap_name), Nothing<bool>());
7784 if (trap->IsUndefined()) {
7785 return JSReceiver::IsExtensible(target);
7786 }
7787
7788 Handle<Object> trap_result;
7789 Handle<Object> args[] = {target};
7790 ASSIGN_RETURN_ON_EXCEPTION_VALUE(
7791 isolate, trap_result,
7792 Execution::Call(isolate, trap, handler, arraysize(args), args),
7793 Nothing<bool>());
7794
7795 // Enforce the invariant.
7796 Maybe<bool> target_result = JSReceiver::IsExtensible(target);
7797 MAYBE_RETURN(target_result, Nothing<bool>());
7798 if (target_result.FromJust() != trap_result->BooleanValue()) {
7799 isolate->Throw(
7800 *factory->NewTypeError(MessageTemplate::kProxyIsExtensibleInconsistent,
7801 factory->ToBoolean(target_result.FromJust())));
7802 return Nothing<bool>();
7803 }
7804 return target_result;
7805}
7806
7807
7808bool JSObject::IsExtensible(Handle<JSObject> object) {
7809 Isolate* isolate = object->GetIsolate();
7810 if (object->IsAccessCheckNeeded() &&
7811 !isolate->MayAccess(handle(isolate->context()), object)) {
7812 return true;
7813 }
7814 if (object->IsJSGlobalProxy()) {
7815 PrototypeIterator iter(isolate, *object);
7816 if (iter.IsAtEnd()) return false;
7817 DCHECK(iter.GetCurrent()->IsJSGlobalObject());
7818 return iter.GetCurrent<JSObject>()->map()->is_extensible();
7819 }
7820 return object->map()->is_extensible();
Emily Bernierd0a1eb72015-03-24 16:35:39 -04007821}
7822
7823
7824template <typename Dictionary>
7825static void ApplyAttributesToDictionary(Dictionary* dictionary,
7826 const PropertyAttributes attributes) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007827 int capacity = dictionary->Capacity();
7828 for (int i = 0; i < capacity; i++) {
7829 Object* k = dictionary->KeyAt(i);
7830 if (dictionary->IsKey(k) &&
7831 !(k->IsSymbol() && Symbol::cast(k)->is_private())) {
7832 PropertyDetails details = dictionary->DetailsAt(i);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04007833 int attrs = attributes;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007834 // READ_ONLY is an invalid attribute for JS setters/getters.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00007835 if ((attributes & READ_ONLY) && details.type() == ACCESSOR_CONSTANT) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007836 Object* v = dictionary->ValueAt(i);
7837 if (v->IsPropertyCell()) v = PropertyCell::cast(v)->value();
Emily Bernierd0a1eb72015-03-24 16:35:39 -04007838 if (v->IsAccessorPair()) attrs &= ~READ_ONLY;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007839 }
7840 details = details.CopyAddAttributes(
7841 static_cast<PropertyAttributes>(attrs));
7842 dictionary->DetailsAtPut(i, details);
7843 }
7844 }
7845}
7846
7847
Emily Bernierd0a1eb72015-03-24 16:35:39 -04007848template <PropertyAttributes attrs>
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00007849Maybe<bool> JSObject::PreventExtensionsWithTransition(
7850 Handle<JSObject> object, ShouldThrow should_throw) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -04007851 STATIC_ASSERT(attrs == NONE || attrs == SEALED || attrs == FROZEN);
7852
7853 // Sealing/freezing sloppy arguments should be handled elsewhere.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007854 DCHECK(!object->HasSloppyArgumentsElements());
7855 DCHECK(!object->map()->is_observed());
7856
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007857 Isolate* isolate = object->GetIsolate();
7858 if (object->IsAccessCheckNeeded() &&
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00007859 !isolate->MayAccess(handle(isolate->context()), object)) {
7860 isolate->ReportFailedAccessCheck(object);
7861 RETURN_VALUE_IF_SCHEDULED_EXCEPTION(isolate, Nothing<bool>());
7862 RETURN_FAILURE(isolate, should_throw,
7863 NewTypeError(MessageTemplate::kNoAccess));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007864 }
7865
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00007866 if (attrs == NONE && !object->map()->is_extensible()) return Just(true);
7867
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007868 if (object->IsJSGlobalProxy()) {
7869 PrototypeIterator iter(isolate, object);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00007870 if (iter.IsAtEnd()) return Just(true);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007871 DCHECK(PrototypeIterator::GetCurrent(iter)->IsJSGlobalObject());
Emily Bernierd0a1eb72015-03-24 16:35:39 -04007872 return PreventExtensionsWithTransition<attrs>(
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00007873 PrototypeIterator::GetCurrent<JSObject>(iter), should_throw);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007874 }
7875
7876 Handle<SeededNumberDictionary> new_element_dictionary;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00007877 if (!object->HasFixedTypedArrayElements() &&
7878 !object->HasDictionaryElements()) {
7879 int length =
7880 object->IsJSArray()
7881 ? Smi::cast(Handle<JSArray>::cast(object)->length())->value()
7882 : object->elements()->length();
7883 new_element_dictionary =
7884 length == 0 ? isolate->factory()->empty_slow_element_dictionary()
7885 : GetNormalizedElementDictionary(
7886 object, handle(object->elements()));
Emily Bernierd0a1eb72015-03-24 16:35:39 -04007887 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007888
Emily Bernierd0a1eb72015-03-24 16:35:39 -04007889 Handle<Symbol> transition_marker;
7890 if (attrs == NONE) {
7891 transition_marker = isolate->factory()->nonextensible_symbol();
7892 } else if (attrs == SEALED) {
7893 transition_marker = isolate->factory()->sealed_symbol();
7894 } else {
7895 DCHECK(attrs == FROZEN);
7896 transition_marker = isolate->factory()->frozen_symbol();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007897 }
7898
7899 Handle<Map> old_map(object->map(), isolate);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00007900 Map* transition =
7901 TransitionArray::SearchSpecial(*old_map, *transition_marker);
7902 if (transition != NULL) {
7903 Handle<Map> transition_map(transition, isolate);
7904 DCHECK(transition_map->has_dictionary_elements() ||
7905 transition_map->has_fixed_typed_array_elements());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007906 DCHECK(!transition_map->is_extensible());
7907 JSObject::MigrateToMap(object, transition_map);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00007908 } else if (TransitionArray::CanHaveMoreTransitions(old_map)) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -04007909 // Create a new descriptor array with the appropriate property attributes
7910 Handle<Map> new_map = Map::CopyForPreventExtensions(
7911 old_map, attrs, transition_marker, "CopyForPreventExtensions");
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007912 JSObject::MigrateToMap(object, new_map);
7913 } else {
7914 DCHECK(old_map->is_dictionary_map() || !old_map->is_prototype_map());
7915 // Slow path: need to normalize properties for safety
Emily Bernierd0a1eb72015-03-24 16:35:39 -04007916 NormalizeProperties(object, CLEAR_INOBJECT_PROPERTIES, 0,
7917 "SlowPreventExtensions");
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007918
7919 // Create a new map, since other objects with this map may be extensible.
7920 // TODO(adamk): Extend the NormalizedMapCache to handle non-extensible maps.
Emily Bernierd0a1eb72015-03-24 16:35:39 -04007921 Handle<Map> new_map =
7922 Map::Copy(handle(object->map()), "SlowCopyForPreventExtensions");
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007923 new_map->set_is_extensible(false);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00007924 if (!new_element_dictionary.is_null()) {
7925 new_map->set_elements_kind(DICTIONARY_ELEMENTS);
7926 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007927 JSObject::MigrateToMap(object, new_map);
7928
Emily Bernierd0a1eb72015-03-24 16:35:39 -04007929 if (attrs != NONE) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00007930 if (object->IsJSGlobalObject()) {
7931 ApplyAttributesToDictionary(object->global_dictionary(), attrs);
7932 } else {
7933 ApplyAttributesToDictionary(object->property_dictionary(), attrs);
7934 }
Emily Bernierd0a1eb72015-03-24 16:35:39 -04007935 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007936 }
7937
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00007938 // Both seal and preventExtensions always go through without modifications to
7939 // typed array elements. Freeze works only if there are no actual elements.
7940 if (object->HasFixedTypedArrayElements()) {
7941 if (attrs == FROZEN &&
7942 JSArrayBufferView::cast(*object)->byte_length()->Number() > 0) {
7943 isolate->Throw(*isolate->factory()->NewTypeError(
7944 MessageTemplate::kCannotFreezeArrayBufferView));
7945 return Nothing<bool>();
7946 }
7947 return Just(true);
7948 }
7949
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007950 DCHECK(object->map()->has_dictionary_elements());
7951 if (!new_element_dictionary.is_null()) {
7952 object->set_elements(*new_element_dictionary);
7953 }
7954
7955 if (object->elements() != isolate->heap()->empty_slow_element_dictionary()) {
7956 SeededNumberDictionary* dictionary = object->element_dictionary();
7957 // Make sure we never go back to the fast case
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00007958 object->RequireSlowElements(dictionary);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04007959 if (attrs != NONE) {
7960 ApplyAttributesToDictionary(dictionary, attrs);
7961 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007962 }
7963
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00007964 return Just(true);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04007965}
7966
7967
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007968void JSObject::SetObserved(Handle<JSObject> object) {
7969 DCHECK(!object->IsJSGlobalProxy());
7970 DCHECK(!object->IsJSGlobalObject());
7971 Isolate* isolate = object->GetIsolate();
7972 Handle<Map> new_map;
7973 Handle<Map> old_map(object->map(), isolate);
7974 DCHECK(!old_map->is_observed());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00007975 Map* transition = TransitionArray::SearchSpecial(
7976 *old_map, isolate->heap()->observed_symbol());
7977 if (transition != NULL) {
7978 new_map = handle(transition, isolate);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007979 DCHECK(new_map->is_observed());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00007980 } else if (TransitionArray::CanHaveMoreTransitions(old_map)) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007981 new_map = Map::CopyForObserved(old_map);
7982 } else {
Emily Bernierd0a1eb72015-03-24 16:35:39 -04007983 new_map = Map::Copy(old_map, "SlowObserved");
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007984 new_map->set_is_observed();
7985 }
7986 JSObject::MigrateToMap(object, new_map);
7987}
7988
7989
7990Handle<Object> JSObject::FastPropertyAt(Handle<JSObject> object,
7991 Representation representation,
7992 FieldIndex index) {
7993 Isolate* isolate = object->GetIsolate();
Emily Bernierd0a1eb72015-03-24 16:35:39 -04007994 if (object->IsUnboxedDoubleField(index)) {
7995 double value = object->RawFastDoublePropertyAt(index);
7996 return isolate->factory()->NewHeapNumber(value);
7997 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007998 Handle<Object> raw_value(object->RawFastPropertyAt(index), isolate);
7999 return Object::WrapForRead(isolate, raw_value, representation);
8000}
8001
8002
8003template<class ContextObject>
8004class JSObjectWalkVisitor {
8005 public:
8006 JSObjectWalkVisitor(ContextObject* site_context, bool copying,
8007 JSObject::DeepCopyHints hints)
8008 : site_context_(site_context),
8009 copying_(copying),
8010 hints_(hints) {}
8011
8012 MUST_USE_RESULT MaybeHandle<JSObject> StructureWalk(Handle<JSObject> object);
8013
8014 protected:
8015 MUST_USE_RESULT inline MaybeHandle<JSObject> VisitElementOrProperty(
8016 Handle<JSObject> object,
8017 Handle<JSObject> value) {
8018 Handle<AllocationSite> current_site = site_context()->EnterNewScope();
8019 MaybeHandle<JSObject> copy_of_value = StructureWalk(value);
8020 site_context()->ExitScope(current_site, value);
8021 return copy_of_value;
8022 }
8023
8024 inline ContextObject* site_context() { return site_context_; }
8025 inline Isolate* isolate() { return site_context()->isolate(); }
8026
8027 inline bool copying() const { return copying_; }
8028
8029 private:
8030 ContextObject* site_context_;
8031 const bool copying_;
8032 const JSObject::DeepCopyHints hints_;
8033};
8034
8035
8036template <class ContextObject>
8037MaybeHandle<JSObject> JSObjectWalkVisitor<ContextObject>::StructureWalk(
8038 Handle<JSObject> object) {
8039 Isolate* isolate = this->isolate();
8040 bool copying = this->copying();
8041 bool shallow = hints_ == JSObject::kObjectIsShallow;
8042
8043 if (!shallow) {
8044 StackLimitCheck check(isolate);
8045
8046 if (check.HasOverflowed()) {
8047 isolate->StackOverflow();
8048 return MaybeHandle<JSObject>();
8049 }
8050 }
8051
8052 if (object->map()->is_deprecated()) {
8053 JSObject::MigrateInstance(object);
8054 }
8055
8056 Handle<JSObject> copy;
8057 if (copying) {
8058 Handle<AllocationSite> site_to_pass;
8059 if (site_context()->ShouldCreateMemento(object)) {
8060 site_to_pass = site_context()->current();
8061 }
8062 copy = isolate->factory()->CopyJSObjectWithAllocationSite(
8063 object, site_to_pass);
8064 } else {
8065 copy = object;
8066 }
8067
8068 DCHECK(copying || copy.is_identical_to(object));
8069
8070 ElementsKind kind = copy->GetElementsKind();
8071 if (copying && IsFastSmiOrObjectElementsKind(kind) &&
8072 FixedArray::cast(copy->elements())->map() ==
8073 isolate->heap()->fixed_cow_array_map()) {
8074 isolate->counters()->cow_arrays_created_runtime()->Increment();
8075 }
8076
8077 if (!shallow) {
8078 HandleScope scope(isolate);
8079
8080 // Deep copy own properties.
8081 if (copy->HasFastProperties()) {
8082 Handle<DescriptorArray> descriptors(copy->map()->instance_descriptors());
8083 int limit = copy->map()->NumberOfOwnDescriptors();
8084 for (int i = 0; i < limit; i++) {
8085 PropertyDetails details = descriptors->GetDetails(i);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00008086 if (details.type() != DATA) continue;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00008087 FieldIndex index = FieldIndex::ForDescriptor(copy->map(), i);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04008088 if (object->IsUnboxedDoubleField(index)) {
8089 if (copying) {
8090 double value = object->RawFastDoublePropertyAt(index);
8091 copy->RawFastDoublePropertyAtPut(index, value);
8092 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00008093 } else {
Emily Bernierd0a1eb72015-03-24 16:35:39 -04008094 Handle<Object> value(object->RawFastPropertyAt(index), isolate);
8095 if (value->IsJSObject()) {
8096 ASSIGN_RETURN_ON_EXCEPTION(
8097 isolate, value,
8098 VisitElementOrProperty(copy, Handle<JSObject>::cast(value)),
8099 JSObject);
8100 if (copying) {
8101 copy->FastPropertyAtPut(index, *value);
8102 }
8103 } else {
8104 if (copying) {
8105 Representation representation = details.representation();
8106 value = Object::NewStorageFor(isolate, value, representation);
8107 copy->FastPropertyAtPut(index, *value);
8108 }
8109 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00008110 }
8111 }
8112 } else {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00008113 // Only deep copy fields from the object literal expression.
8114 // In particular, don't try to copy the length attribute of
8115 // an array.
8116 PropertyFilter filter = static_cast<PropertyFilter>(
8117 ONLY_WRITABLE | ONLY_ENUMERABLE | ONLY_CONFIGURABLE);
8118 KeyAccumulator accumulator(isolate, filter);
8119 accumulator.NextPrototype();
8120 copy->CollectOwnPropertyNames(&accumulator, filter);
8121 Handle<FixedArray> names = accumulator.GetKeys();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00008122 for (int i = 0; i < names->length(); i++) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00008123 DCHECK(names->get(i)->IsName());
8124 Handle<Name> name(Name::cast(names->get(i)));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00008125 Handle<Object> value =
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00008126 Object::GetProperty(copy, name).ToHandleChecked();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00008127 if (value->IsJSObject()) {
8128 Handle<JSObject> result;
8129 ASSIGN_RETURN_ON_EXCEPTION(
8130 isolate, result,
8131 VisitElementOrProperty(copy, Handle<JSObject>::cast(value)),
8132 JSObject);
8133 if (copying) {
8134 // Creating object copy for literals. No strict mode needed.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00008135 JSObject::SetProperty(copy, name, result, SLOPPY).Assert();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00008136 }
8137 }
8138 }
8139 }
8140
8141 // Deep copy own elements.
8142 // Pixel elements cannot be created using an object literal.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00008143 DCHECK(!copy->HasFixedTypedArrayElements());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00008144 switch (kind) {
8145 case FAST_SMI_ELEMENTS:
8146 case FAST_ELEMENTS:
8147 case FAST_HOLEY_SMI_ELEMENTS:
8148 case FAST_HOLEY_ELEMENTS: {
8149 Handle<FixedArray> elements(FixedArray::cast(copy->elements()));
8150 if (elements->map() == isolate->heap()->fixed_cow_array_map()) {
8151#ifdef DEBUG
8152 for (int i = 0; i < elements->length(); i++) {
8153 DCHECK(!elements->get(i)->IsJSObject());
8154 }
8155#endif
8156 } else {
8157 for (int i = 0; i < elements->length(); i++) {
8158 Handle<Object> value(elements->get(i), isolate);
8159 DCHECK(value->IsSmi() ||
8160 value->IsTheHole() ||
8161 (IsFastObjectElementsKind(copy->GetElementsKind())));
8162 if (value->IsJSObject()) {
8163 Handle<JSObject> result;
8164 ASSIGN_RETURN_ON_EXCEPTION(
8165 isolate, result,
8166 VisitElementOrProperty(copy, Handle<JSObject>::cast(value)),
8167 JSObject);
8168 if (copying) {
8169 elements->set(i, *result);
8170 }
8171 }
8172 }
8173 }
8174 break;
8175 }
8176 case DICTIONARY_ELEMENTS: {
8177 Handle<SeededNumberDictionary> element_dictionary(
8178 copy->element_dictionary());
8179 int capacity = element_dictionary->Capacity();
8180 for (int i = 0; i < capacity; i++) {
8181 Object* k = element_dictionary->KeyAt(i);
8182 if (element_dictionary->IsKey(k)) {
8183 Handle<Object> value(element_dictionary->ValueAt(i), isolate);
8184 if (value->IsJSObject()) {
8185 Handle<JSObject> result;
8186 ASSIGN_RETURN_ON_EXCEPTION(
8187 isolate, result,
8188 VisitElementOrProperty(copy, Handle<JSObject>::cast(value)),
8189 JSObject);
8190 if (copying) {
8191 element_dictionary->ValueAtPut(i, *result);
8192 }
8193 }
8194 }
8195 }
8196 break;
8197 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00008198 case FAST_SLOPPY_ARGUMENTS_ELEMENTS:
8199 case SLOW_SLOPPY_ARGUMENTS_ELEMENTS:
Ben Murdochb8a8cc12014-11-26 15:28:44 +00008200 UNIMPLEMENTED();
8201 break;
8202
8203
8204#define TYPED_ARRAY_CASE(Type, type, TYPE, ctype, size) \
Ben Murdochb8a8cc12014-11-26 15:28:44 +00008205 case TYPE##_ELEMENTS: \
8206
8207 TYPED_ARRAYS(TYPED_ARRAY_CASE)
8208#undef TYPED_ARRAY_CASE
8209
8210 case FAST_DOUBLE_ELEMENTS:
8211 case FAST_HOLEY_DOUBLE_ELEMENTS:
8212 // No contained objects, nothing to do.
8213 break;
8214 }
8215 }
8216
8217 return copy;
8218}
8219
8220
8221MaybeHandle<JSObject> JSObject::DeepWalk(
8222 Handle<JSObject> object,
8223 AllocationSiteCreationContext* site_context) {
8224 JSObjectWalkVisitor<AllocationSiteCreationContext> v(site_context, false,
8225 kNoHints);
8226 MaybeHandle<JSObject> result = v.StructureWalk(object);
8227 Handle<JSObject> for_assert;
8228 DCHECK(!result.ToHandle(&for_assert) || for_assert.is_identical_to(object));
8229 return result;
8230}
8231
8232
8233MaybeHandle<JSObject> JSObject::DeepCopy(
8234 Handle<JSObject> object,
8235 AllocationSiteUsageContext* site_context,
8236 DeepCopyHints hints) {
8237 JSObjectWalkVisitor<AllocationSiteUsageContext> v(site_context, true, hints);
8238 MaybeHandle<JSObject> copy = v.StructureWalk(object);
8239 Handle<JSObject> for_assert;
8240 DCHECK(!copy.ToHandle(&for_assert) || !for_assert.is_identical_to(object));
8241 return copy;
Steve Block8defd9f2010-07-08 12:39:36 +01008242}
8243
8244
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00008245// static
8246MaybeHandle<Object> JSReceiver::ToPrimitive(Handle<JSReceiver> receiver,
8247 ToPrimitiveHint hint) {
8248 Isolate* const isolate = receiver->GetIsolate();
8249 Handle<Object> exotic_to_prim;
8250 ASSIGN_RETURN_ON_EXCEPTION(
8251 isolate, exotic_to_prim,
8252 GetMethod(receiver, isolate->factory()->to_primitive_symbol()), Object);
8253 if (!exotic_to_prim->IsUndefined()) {
8254 Handle<Object> hint_string;
8255 switch (hint) {
8256 case ToPrimitiveHint::kDefault:
8257 hint_string = isolate->factory()->default_string();
8258 break;
8259 case ToPrimitiveHint::kNumber:
8260 hint_string = isolate->factory()->number_string();
8261 break;
8262 case ToPrimitiveHint::kString:
8263 hint_string = isolate->factory()->string_string();
8264 break;
8265 }
8266 Handle<Object> result;
8267 ASSIGN_RETURN_ON_EXCEPTION(
8268 isolate, result,
8269 Execution::Call(isolate, exotic_to_prim, receiver, 1, &hint_string),
8270 Object);
8271 if (result->IsPrimitive()) return result;
8272 THROW_NEW_ERROR(isolate,
8273 NewTypeError(MessageTemplate::kCannotConvertToPrimitive),
8274 Object);
8275 }
8276 return OrdinaryToPrimitive(receiver, (hint == ToPrimitiveHint::kString)
8277 ? OrdinaryToPrimitiveHint::kString
8278 : OrdinaryToPrimitiveHint::kNumber);
8279}
8280
8281
8282// static
8283MaybeHandle<Object> JSReceiver::OrdinaryToPrimitive(
8284 Handle<JSReceiver> receiver, OrdinaryToPrimitiveHint hint) {
8285 Isolate* const isolate = receiver->GetIsolate();
8286 Handle<String> method_names[2];
8287 switch (hint) {
8288 case OrdinaryToPrimitiveHint::kNumber:
8289 method_names[0] = isolate->factory()->valueOf_string();
8290 method_names[1] = isolate->factory()->toString_string();
8291 break;
8292 case OrdinaryToPrimitiveHint::kString:
8293 method_names[0] = isolate->factory()->toString_string();
8294 method_names[1] = isolate->factory()->valueOf_string();
8295 break;
8296 }
8297 for (Handle<String> name : method_names) {
8298 Handle<Object> method;
8299 ASSIGN_RETURN_ON_EXCEPTION(isolate, method,
8300 JSReceiver::GetProperty(receiver, name), Object);
8301 if (method->IsCallable()) {
8302 Handle<Object> result;
8303 ASSIGN_RETURN_ON_EXCEPTION(
8304 isolate, result, Execution::Call(isolate, method, receiver, 0, NULL),
8305 Object);
8306 if (result->IsPrimitive()) return result;
8307 }
8308 }
8309 THROW_NEW_ERROR(isolate,
8310 NewTypeError(MessageTemplate::kCannotConvertToPrimitive),
8311 Object);
8312}
8313
8314
8315// TODO(cbruni/jkummerow): Consider moving this into elements.cc.
8316bool HasEnumerableElements(JSObject* object) {
8317 if (object->IsJSValue()) {
8318 Object* value = JSValue::cast(object)->value();
8319 if (value->IsString()) {
8320 if (String::cast(value)->length() > 0) return true;
8321 }
8322 }
8323 switch (object->GetElementsKind()) {
8324 case FAST_SMI_ELEMENTS:
8325 case FAST_ELEMENTS:
8326 case FAST_DOUBLE_ELEMENTS: {
8327 int length = object->IsJSArray()
8328 ? Smi::cast(JSArray::cast(object)->length())->value()
8329 : object->elements()->length();
8330 return length > 0;
8331 }
8332 case FAST_HOLEY_SMI_ELEMENTS:
8333 case FAST_HOLEY_ELEMENTS: {
8334 FixedArray* elements = FixedArray::cast(object->elements());
8335 int length = object->IsJSArray()
8336 ? Smi::cast(JSArray::cast(object)->length())->value()
8337 : elements->length();
8338 for (int i = 0; i < length; i++) {
8339 if (!elements->is_the_hole(i)) return true;
8340 }
8341 return false;
8342 }
8343 case FAST_HOLEY_DOUBLE_ELEMENTS: {
8344 int length = object->IsJSArray()
8345 ? Smi::cast(JSArray::cast(object)->length())->value()
8346 : object->elements()->length();
8347 // Zero-length arrays would use the empty FixedArray...
8348 if (length == 0) return false;
8349 // ...so only cast to FixedDoubleArray otherwise.
8350 FixedDoubleArray* elements = FixedDoubleArray::cast(object->elements());
8351 for (int i = 0; i < length; i++) {
8352 if (!elements->is_the_hole(i)) return true;
8353 }
8354 return false;
8355 }
8356#define TYPED_ARRAY_CASE(Type, type, TYPE, ctype, size) \
8357 case TYPE##_ELEMENTS:
8358
8359 TYPED_ARRAYS(TYPED_ARRAY_CASE)
8360#undef TYPED_ARRAY_CASE
8361 {
8362 int length = object->elements()->length();
8363 return length > 0;
8364 }
8365 case DICTIONARY_ELEMENTS: {
8366 SeededNumberDictionary* elements =
8367 SeededNumberDictionary::cast(object->elements());
8368 return elements->NumberOfElementsFilterAttributes(ONLY_ENUMERABLE) > 0;
8369 }
8370 case FAST_SLOPPY_ARGUMENTS_ELEMENTS:
8371 case SLOW_SLOPPY_ARGUMENTS_ELEMENTS:
8372 // We're approximating non-empty arguments objects here.
8373 return true;
8374 }
8375 UNREACHABLE();
8376 return true;
8377}
8378
8379
Steve Blocka7e24c12009-10-30 11:49:00 +00008380// Tests for the fast common case for property enumeration:
Ben Murdoch3ef787d2012-04-12 10:51:47 +01008381// - This object and all prototypes has an enum cache (which means that
8382// it is no proxy, has no interceptors and needs no access checks).
Steve Blockd0582a62009-12-15 09:54:21 +00008383// - This object has no elements.
8384// - No prototype has enumerable properties/elements.
Ben Murdoch3ef787d2012-04-12 10:51:47 +01008385bool JSReceiver::IsSimpleEnum() {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00008386 for (PrototypeIterator iter(GetIsolate(), this,
8387 PrototypeIterator::START_AT_RECEIVER);
8388 !iter.IsAtEnd(); iter.Advance()) {
8389 if (!iter.GetCurrent()->IsJSObject()) return false;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00008390 JSObject* current = iter.GetCurrent<JSObject>();
8391 int enum_length = current->map()->EnumLength();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00008392 if (enum_length == kInvalidEnumCacheSentinel) return false;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00008393 if (current->IsAccessCheckNeeded()) return false;
8394 DCHECK(!current->HasNamedInterceptor());
8395 DCHECK(!current->HasIndexedInterceptor());
8396 if (HasEnumerableElements(current)) return false;
8397 if (current != this && enum_length != 0) return false;
Steve Blocka7e24c12009-10-30 11:49:00 +00008398 }
8399 return true;
8400}
8401
8402
Ben Murdochb8a8cc12014-11-26 15:28:44 +00008403int Map::NumberOfDescribedProperties(DescriptorFlag which,
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00008404 PropertyFilter filter) {
Steve Blocka7e24c12009-10-30 11:49:00 +00008405 int result = 0;
8406 DescriptorArray* descs = instance_descriptors();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00008407 int limit = which == ALL_DESCRIPTORS
8408 ? descs->number_of_descriptors()
8409 : NumberOfOwnDescriptors();
8410 for (int i = 0; i < limit; i++) {
8411 if ((descs->GetDetails(i).attributes() & filter) == 0 &&
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00008412 !descs->GetKey(i)->FilterKey(filter)) {
Ben Murdoch3ef787d2012-04-12 10:51:47 +01008413 result++;
8414 }
Steve Blocka7e24c12009-10-30 11:49:00 +00008415 }
8416 return result;
8417}
8418
8419
Steve Blocka7e24c12009-10-30 11:49:00 +00008420int Map::NextFreePropertyIndex() {
Emily Bernierd0a1eb72015-03-24 16:35:39 -04008421 int free_index = 0;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00008422 int number_of_own_descriptors = NumberOfOwnDescriptors();
Steve Blocka7e24c12009-10-30 11:49:00 +00008423 DescriptorArray* descs = instance_descriptors();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00008424 for (int i = 0; i < number_of_own_descriptors; i++) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -04008425 PropertyDetails details = descs->GetDetails(i);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00008426 if (details.location() == kField) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -04008427 int candidate = details.field_index() + details.field_width_in_words();
8428 if (candidate > free_index) free_index = candidate;
Steve Blocka7e24c12009-10-30 11:49:00 +00008429 }
8430 }
Emily Bernierd0a1eb72015-03-24 16:35:39 -04008431 return free_index;
Steve Blocka7e24c12009-10-30 11:49:00 +00008432}
8433
8434
Ben Murdochb8a8cc12014-11-26 15:28:44 +00008435static bool ContainsOnlyValidKeys(Handle<FixedArray> array) {
8436 int len = array->length();
8437 for (int i = 0; i < len; i++) {
8438 Object* e = array->get(i);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04008439 if (!(e->IsName() || e->IsNumber())) return false;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00008440 }
8441 return true;
8442}
8443
8444
8445static Handle<FixedArray> ReduceFixedArrayTo(
8446 Handle<FixedArray> array, int length) {
8447 DCHECK(array->length() >= length);
8448 if (array->length() == length) return array;
8449
8450 Handle<FixedArray> new_array =
8451 array->GetIsolate()->factory()->NewFixedArray(length);
8452 for (int i = 0; i < length; ++i) new_array->set(i, array->get(i));
8453 return new_array;
8454}
8455
8456
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00008457namespace {
8458
8459Handle<FixedArray> GetFastEnumPropertyKeys(Isolate* isolate,
8460 Handle<JSObject> object,
8461 bool cache_enum_length) {
8462 Handle<Map> map(object->map());
8463 Handle<DescriptorArray> descs =
8464 Handle<DescriptorArray>(map->instance_descriptors(), isolate);
8465 int own_property_count = map->EnumLength();
8466 // If the enum length of the given map is set to kInvalidEnumCache, this
8467 // means that the map itself has never used the present enum cache. The
8468 // first step to using the cache is to set the enum length of the map by
8469 // counting the number of own descriptors that are ENUMERABLE_STRINGS.
8470 if (own_property_count == kInvalidEnumCacheSentinel) {
8471 own_property_count =
8472 map->NumberOfDescribedProperties(OWN_DESCRIPTORS, ENUMERABLE_STRINGS);
8473 } else {
8474 DCHECK(
8475 own_property_count ==
8476 map->NumberOfDescribedProperties(OWN_DESCRIPTORS, ENUMERABLE_STRINGS));
8477 }
8478
8479 if (descs->HasEnumCache()) {
8480 Handle<FixedArray> keys(descs->GetEnumCache(), isolate);
8481 // In case the number of properties required in the enum are actually
8482 // present, we can reuse the enum cache. Otherwise, this means that the
8483 // enum cache was generated for a previous (smaller) version of the
8484 // Descriptor Array. In that case we regenerate the enum cache.
8485 if (own_property_count <= keys->length()) {
8486 isolate->counters()->enum_cache_hits()->Increment();
8487 if (cache_enum_length) map->SetEnumLength(own_property_count);
8488 return ReduceFixedArrayTo(keys, own_property_count);
8489 }
8490 }
8491
8492 if (descs->IsEmpty()) {
8493 isolate->counters()->enum_cache_hits()->Increment();
8494 if (cache_enum_length) map->SetEnumLength(0);
8495 return isolate->factory()->empty_fixed_array();
8496 }
8497
8498 isolate->counters()->enum_cache_misses()->Increment();
8499
8500 Handle<FixedArray> storage =
8501 isolate->factory()->NewFixedArray(own_property_count);
8502 Handle<FixedArray> indices =
8503 isolate->factory()->NewFixedArray(own_property_count);
8504
8505 int size = map->NumberOfOwnDescriptors();
8506 int index = 0;
8507
8508 for (int i = 0; i < size; i++) {
8509 PropertyDetails details = descs->GetDetails(i);
8510 Object* key = descs->GetKey(i);
8511 if (details.IsDontEnum() || key->IsSymbol()) continue;
8512 storage->set(index, key);
8513 if (!indices.is_null()) {
8514 if (details.type() != DATA) {
8515 indices = Handle<FixedArray>();
8516 } else {
8517 FieldIndex field_index = FieldIndex::ForDescriptor(*map, i);
8518 int load_by_field_index = field_index.GetLoadByFieldIndex();
8519 indices->set(index, Smi::FromInt(load_by_field_index));
8520 }
8521 }
8522 index++;
8523 }
8524 DCHECK(index == storage->length());
8525
8526 DescriptorArray::SetEnumCache(descs, isolate, storage, indices);
8527 if (cache_enum_length) {
8528 map->SetEnumLength(own_property_count);
8529 }
8530 return storage;
8531}
8532
8533} // namespace
8534
8535
8536Handle<FixedArray> JSObject::GetEnumPropertyKeys(Handle<JSObject> object,
8537 bool cache_enum_length) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00008538 Isolate* isolate = object->GetIsolate();
8539 if (object->HasFastProperties()) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00008540 return GetFastEnumPropertyKeys(isolate, object, cache_enum_length);
8541 } else if (object->IsJSGlobalObject()) {
8542 Handle<GlobalDictionary> dictionary(object->global_dictionary());
8543 int length = dictionary->NumberOfEnumElements();
8544 if (length == 0) {
8545 return Handle<FixedArray>(isolate->heap()->empty_fixed_array());
Steve Blocka7e24c12009-10-30 11:49:00 +00008546 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00008547 Handle<FixedArray> storage = isolate->factory()->NewFixedArray(length);
8548 dictionary->CopyEnumKeysTo(*storage);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00008549 return storage;
8550 } else {
8551 Handle<NameDictionary> dictionary(object->property_dictionary());
8552 int length = dictionary->NumberOfEnumElements();
8553 if (length == 0) {
8554 return Handle<FixedArray>(isolate->heap()->empty_fixed_array());
8555 }
8556 Handle<FixedArray> storage = isolate->factory()->NewFixedArray(length);
8557 dictionary->CopyEnumKeysTo(*storage);
8558 return storage;
Steve Blocka7e24c12009-10-30 11:49:00 +00008559 }
Steve Blocka7e24c12009-10-30 11:49:00 +00008560}
8561
8562
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00008563enum IndexedOrNamed { kIndexed, kNamed };
Steve Blocka7e24c12009-10-30 11:49:00 +00008564
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00008565
8566// Returns |true| on success, |nothing| on exception.
8567template <class Callback, IndexedOrNamed type>
8568static Maybe<bool> GetKeysFromInterceptor(Isolate* isolate,
8569 Handle<JSReceiver> receiver,
8570 Handle<JSObject> object,
8571 PropertyFilter filter,
8572 KeyAccumulator* accumulator) {
8573 if (type == kIndexed) {
8574 if (!object->HasIndexedInterceptor()) return Just(true);
8575 } else {
8576 if (!object->HasNamedInterceptor()) return Just(true);
8577 }
8578 Handle<InterceptorInfo> interceptor(type == kIndexed
8579 ? object->GetIndexedInterceptor()
8580 : object->GetNamedInterceptor(),
8581 isolate);
8582 if ((filter & ONLY_ALL_CAN_READ) && !interceptor->all_can_read()) {
8583 return Just(true);
8584 }
8585 PropertyCallbackArguments args(isolate, interceptor->data(), *receiver,
8586 *object);
8587 v8::Local<v8::Object> result;
8588 if (!interceptor->enumerator()->IsUndefined()) {
8589 Callback enum_fun = v8::ToCData<Callback>(interceptor->enumerator());
8590 const char* log_tag = type == kIndexed ? "interceptor-indexed-enum"
8591 : "interceptor-named-enum";
8592 LOG(isolate, ApiObjectAccess(log_tag, *object));
8593 result = args.Call(enum_fun);
8594 }
8595 RETURN_VALUE_IF_SCHEDULED_EXCEPTION(isolate, Nothing<bool>());
8596 if (result.IsEmpty()) return Just(true);
8597 DCHECK(v8::Utils::OpenHandle(*result)->IsJSArray() ||
8598 (v8::Utils::OpenHandle(*result)->IsJSObject() &&
8599 Handle<JSObject>::cast(v8::Utils::OpenHandle(*result))
8600 ->HasSloppyArgumentsElements()));
8601 // The accumulator takes care of string/symbol filtering.
8602 if (type == kIndexed) {
8603 accumulator->AddElementKeysFromInterceptor(
8604 Handle<JSObject>::cast(v8::Utils::OpenHandle(*result)));
8605 } else {
8606 accumulator->AddKeys(
8607 Handle<JSObject>::cast(v8::Utils::OpenHandle(*result)));
8608 }
8609 return Just(true);
8610}
8611
8612
8613// Returns |true| on success, |false| if prototype walking should be stopped,
8614// |nothing| if an exception was thrown.
8615static Maybe<bool> GetKeysFromJSObject(Isolate* isolate,
8616 Handle<JSReceiver> receiver,
8617 Handle<JSObject> object,
8618 PropertyFilter* filter,
8619 JSReceiver::KeyCollectionType type,
8620 KeyAccumulator* accumulator) {
8621 accumulator->NextPrototype();
8622 // Check access rights if required.
8623 if (object->IsAccessCheckNeeded() &&
8624 !isolate->MayAccess(handle(isolate->context()), object)) {
8625 // The cross-origin spec says that [[Enumerate]] shall return an empty
8626 // iterator when it doesn't have access...
8627 if (type == JSReceiver::INCLUDE_PROTOS) {
8628 return Just(false);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00008629 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00008630 // ...whereas [[OwnPropertyKeys]] shall return whitelisted properties.
8631 DCHECK(type == JSReceiver::OWN_ONLY);
8632 *filter = static_cast<PropertyFilter>(*filter | ONLY_ALL_CAN_READ);
8633 }
Steve Block44f0eee2011-05-26 01:26:41 +01008634
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00008635 JSObject::CollectOwnElementKeys(object, accumulator, *filter);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00008636
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00008637 // Add the element keys from the interceptor.
8638 Maybe<bool> success =
8639 GetKeysFromInterceptor<v8::IndexedPropertyEnumeratorCallback, kIndexed>(
8640 isolate, receiver, object, *filter, accumulator);
8641 MAYBE_RETURN(success, Nothing<bool>());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00008642
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00008643 if (*filter == ENUMERABLE_STRINGS) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00008644 // We can cache the computed property keys if access checks are
8645 // not needed and no interceptors are involved.
8646 //
8647 // We do not use the cache if the object has elements and
8648 // therefore it does not make sense to cache the property names
8649 // for arguments objects. Arguments objects will always have
8650 // elements.
8651 // Wrapped strings have elements, but don't have an elements
8652 // array or dictionary. So the fast inline test for whether to
8653 // use the cache says yes, so we should not create a cache.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00008654 Handle<JSFunction> arguments_function(
8655 JSFunction::cast(isolate->sloppy_arguments_map()->GetConstructor()));
8656 bool has_hidden_prototype = false;
8657 Object* prototype = object->map()->prototype();
8658 if (prototype->IsJSObject()) {
8659 has_hidden_prototype =
8660 JSObject::cast(prototype)->map()->is_hidden_prototype();
8661 }
8662 bool cache_enum_length =
8663 ((object->map()->GetConstructor() != *arguments_function) &&
8664 !object->IsJSValue() && !object->IsAccessCheckNeeded() &&
8665 !object->HasNamedInterceptor() && !object->HasIndexedInterceptor() &&
8666 !has_hidden_prototype);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00008667 // Compute the property keys and cache them if possible.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00008668 Handle<FixedArray> enum_keys =
8669 JSObject::GetEnumPropertyKeys(object, cache_enum_length);
8670 accumulator->AddKeys(enum_keys);
8671 } else {
8672 object->CollectOwnPropertyNames(accumulator, *filter);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01008673 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00008674
8675 // Add the property keys from the interceptor.
8676 success = GetKeysFromInterceptor<v8::GenericNamedPropertyEnumeratorCallback,
8677 kNamed>(isolate, receiver, object, *filter,
8678 accumulator);
8679 MAYBE_RETURN(success, Nothing<bool>());
8680 return Just(true);
Steve Blocka7e24c12009-10-30 11:49:00 +00008681}
8682
8683
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00008684// Helper function for JSReceiver::GetKeys() below. Can be called recursively.
8685// Returns |true| or |nothing|.
8686static Maybe<bool> GetKeys_Internal(Isolate* isolate,
8687 Handle<JSReceiver> receiver,
8688 Handle<JSReceiver> object,
8689 JSReceiver::KeyCollectionType type,
8690 PropertyFilter filter,
8691 KeyAccumulator* accumulator) {
8692 PrototypeIterator::WhereToEnd end = type == JSReceiver::OWN_ONLY
8693 ? PrototypeIterator::END_AT_NON_HIDDEN
8694 : PrototypeIterator::END_AT_NULL;
8695 for (PrototypeIterator iter(isolate, object,
8696 PrototypeIterator::START_AT_RECEIVER);
8697 !iter.IsAtEnd(end); iter.Advance()) {
8698 Handle<JSReceiver> current =
8699 PrototypeIterator::GetCurrent<JSReceiver>(iter);
8700 Maybe<bool> result = Just(false); // Dummy initialization.
8701 if (current->IsJSProxy()) {
8702 if (type == JSReceiver::OWN_ONLY) {
8703 result = JSProxy::OwnPropertyKeys(isolate, receiver,
8704 Handle<JSProxy>::cast(current),
8705 filter, accumulator);
8706 } else {
8707 DCHECK(type == JSReceiver::INCLUDE_PROTOS);
8708 result = JSProxy::Enumerate(
8709 isolate, receiver, Handle<JSProxy>::cast(current), accumulator);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01008710 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00008711 } else {
8712 DCHECK(current->IsJSObject());
8713 result = GetKeysFromJSObject(isolate, receiver,
8714 Handle<JSObject>::cast(current), &filter,
8715 type, accumulator);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01008716 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00008717 MAYBE_RETURN(result, Nothing<bool>());
8718 if (!result.FromJust()) break; // |false| means "stop iterating".
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00008719 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00008720 return Just(true);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00008721}
8722
8723
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00008724// ES6 9.5.11
8725// Returns false in case of exception.
8726// static
8727Maybe<bool> JSProxy::Enumerate(Isolate* isolate, Handle<JSReceiver> receiver,
8728 Handle<JSProxy> proxy,
8729 KeyAccumulator* accumulator) {
8730 STACK_CHECK(Nothing<bool>());
8731 // 1. Let handler be the value of the [[ProxyHandler]] internal slot of O.
8732 Handle<Object> handler(proxy->handler(), isolate);
8733 // 2. If handler is null, throw a TypeError exception.
8734 // 3. Assert: Type(handler) is Object.
8735 if (proxy->IsRevoked()) {
8736 isolate->Throw(*isolate->factory()->NewTypeError(
8737 MessageTemplate::kProxyRevoked,
8738 isolate->factory()->enumerate_string()));
8739 return Nothing<bool>();
8740 }
8741 // 4. Let target be the value of the [[ProxyTarget]] internal slot of O.
8742 Handle<JSReceiver> target(proxy->target(), isolate);
8743 // 5. Let trap be ? GetMethod(handler, "enumerate").
8744 Handle<Object> trap;
8745 ASSIGN_RETURN_ON_EXCEPTION_VALUE(
8746 isolate, trap, Object::GetMethod(Handle<JSReceiver>::cast(handler),
8747 isolate->factory()->enumerate_string()),
8748 Nothing<bool>());
8749 // 6. If trap is undefined, then
8750 if (trap->IsUndefined()) {
8751 // 6a. Return target.[[Enumerate]]().
8752 return GetKeys_Internal(isolate, receiver, target, INCLUDE_PROTOS,
8753 ENUMERABLE_STRINGS, accumulator);
8754 }
8755 // The "proxy_enumerate" helper calls the trap (steps 7 - 9), which returns
8756 // a generator; it then iterates over that generator until it's exhausted
8757 // and returns an array containing the generated values.
8758 Handle<Object> trap_result_array;
8759 Handle<Object> args[] = {trap, handler, target};
8760 ASSIGN_RETURN_ON_EXCEPTION_VALUE(
8761 isolate, trap_result_array,
8762 Execution::Call(isolate, isolate->proxy_enumerate(),
8763 isolate->factory()->undefined_value(), arraysize(args),
8764 args),
8765 Nothing<bool>());
8766 accumulator->NextPrototype();
8767 accumulator->AddKeysFromProxy(Handle<JSObject>::cast(trap_result_array));
8768 return Just(true);
8769}
Ben Murdochb8a8cc12014-11-26 15:28:44 +00008770
Ben Murdochb8a8cc12014-11-26 15:28:44 +00008771
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00008772// ES6 9.5.12
8773// Returns |true| on success, |nothing| in case of exception.
8774// static
8775Maybe<bool> JSProxy::OwnPropertyKeys(Isolate* isolate,
8776 Handle<JSReceiver> receiver,
8777 Handle<JSProxy> proxy,
8778 PropertyFilter filter,
8779 KeyAccumulator* accumulator) {
8780 STACK_CHECK(Nothing<bool>());
8781 // 1. Let handler be the value of the [[ProxyHandler]] internal slot of O.
8782 Handle<Object> handler(proxy->handler(), isolate);
8783 // 2. If handler is null, throw a TypeError exception.
8784 // 3. Assert: Type(handler) is Object.
8785 if (proxy->IsRevoked()) {
8786 isolate->Throw(*isolate->factory()->NewTypeError(
8787 MessageTemplate::kProxyRevoked, isolate->factory()->ownKeys_string()));
8788 return Nothing<bool>();
8789 }
8790 // 4. Let target be the value of the [[ProxyTarget]] internal slot of O.
8791 Handle<JSReceiver> target(proxy->target(), isolate);
8792 // 5. Let trap be ? GetMethod(handler, "ownKeys").
8793 Handle<Object> trap;
8794 ASSIGN_RETURN_ON_EXCEPTION_VALUE(
8795 isolate, trap, Object::GetMethod(Handle<JSReceiver>::cast(handler),
8796 isolate->factory()->ownKeys_string()),
8797 Nothing<bool>());
8798 // 6. If trap is undefined, then
8799 if (trap->IsUndefined()) {
8800 // 6a. Return target.[[OwnPropertyKeys]]().
8801 return GetKeys_Internal(isolate, receiver, target, OWN_ONLY, filter,
8802 accumulator);
8803 }
8804 // 7. Let trapResultArray be Call(trap, handler, «target»).
8805 Handle<Object> trap_result_array;
8806 Handle<Object> args[] = {target};
8807 ASSIGN_RETURN_ON_EXCEPTION_VALUE(
8808 isolate, trap_result_array,
8809 Execution::Call(isolate, trap, handler, arraysize(args), args),
8810 Nothing<bool>());
8811 // 8. Let trapResult be ? CreateListFromArrayLike(trapResultArray,
8812 // «String, Symbol»).
8813 Handle<FixedArray> trap_result;
8814 ASSIGN_RETURN_ON_EXCEPTION_VALUE(
8815 isolate, trap_result,
8816 Object::CreateListFromArrayLike(isolate, trap_result_array,
8817 ElementTypes::kStringAndSymbol),
8818 Nothing<bool>());
8819 // 9. Let extensibleTarget be ? IsExtensible(target).
8820 Maybe<bool> maybe_extensible = JSReceiver::IsExtensible(target);
8821 MAYBE_RETURN(maybe_extensible, Nothing<bool>());
8822 bool extensible_target = maybe_extensible.FromJust();
8823 // 10. Let targetKeys be ? target.[[OwnPropertyKeys]]().
8824 Handle<FixedArray> target_keys;
8825 ASSIGN_RETURN_ON_EXCEPTION_VALUE(isolate, target_keys,
8826 JSReceiver::OwnPropertyKeys(target),
8827 Nothing<bool>());
8828 // 11. (Assert)
8829 // 12. Let targetConfigurableKeys be an empty List.
8830 // To save memory, we're re-using target_keys and will modify it in-place.
8831 Handle<FixedArray> target_configurable_keys = target_keys;
8832 // 13. Let targetNonconfigurableKeys be an empty List.
8833 Handle<FixedArray> target_nonconfigurable_keys =
8834 isolate->factory()->NewFixedArray(target_keys->length());
8835 int nonconfigurable_keys_length = 0;
8836 // 14. Repeat, for each element key of targetKeys:
8837 for (int i = 0; i < target_keys->length(); ++i) {
8838 // 14a. Let desc be ? target.[[GetOwnProperty]](key).
8839 PropertyDescriptor desc;
8840 Maybe<bool> found = JSReceiver::GetOwnPropertyDescriptor(
8841 isolate, target, handle(target_keys->get(i), isolate), &desc);
8842 MAYBE_RETURN(found, Nothing<bool>());
8843 // 14b. If desc is not undefined and desc.[[Configurable]] is false, then
8844 if (found.FromJust() && !desc.configurable()) {
8845 // 14b i. Append key as an element of targetNonconfigurableKeys.
8846 target_nonconfigurable_keys->set(nonconfigurable_keys_length,
8847 target_keys->get(i));
8848 nonconfigurable_keys_length++;
8849 // The key was moved, null it out in the original list.
8850 target_keys->set(i, Smi::FromInt(0));
8851 } else {
8852 // 14c. Else,
8853 // 14c i. Append key as an element of targetConfigurableKeys.
8854 // (No-op, just keep it in |target_keys|.)
Steve Blocka7e24c12009-10-30 11:49:00 +00008855 }
Ben Murdoch3ef787d2012-04-12 10:51:47 +01008856 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00008857 accumulator->NextPrototype(); // Prepare for accumulating keys.
8858 // 15. If extensibleTarget is true and targetNonconfigurableKeys is empty,
8859 // then:
8860 if (extensible_target && nonconfigurable_keys_length == 0) {
8861 // 15a. Return trapResult.
8862 return accumulator->AddKeysFromProxy(proxy, trap_result);
8863 }
8864 // 16. Let uncheckedResultKeys be a new List which is a copy of trapResult.
8865 Zone set_zone;
8866 const int kPresent = 1;
8867 const int kGone = 0;
8868 IdentityMap<int> unchecked_result_keys(isolate->heap(), &set_zone);
8869 int unchecked_result_keys_size = trap_result->length();
8870 for (int i = 0; i < trap_result->length(); ++i) {
8871 DCHECK(trap_result->get(i)->IsUniqueName());
8872 unchecked_result_keys.Set(trap_result->get(i), kPresent);
8873 }
8874 // 17. Repeat, for each key that is an element of targetNonconfigurableKeys:
8875 for (int i = 0; i < nonconfigurable_keys_length; ++i) {
8876 Object* key = target_nonconfigurable_keys->get(i);
8877 // 17a. If key is not an element of uncheckedResultKeys, throw a
8878 // TypeError exception.
8879 int* found = unchecked_result_keys.Find(key);
8880 if (found == nullptr || *found == kGone) {
8881 isolate->Throw(*isolate->factory()->NewTypeError(
8882 MessageTemplate::kProxyOwnKeysMissing, handle(key, isolate)));
8883 return Nothing<bool>();
8884 }
8885 // 17b. Remove key from uncheckedResultKeys.
8886 *found = kGone;
8887 unchecked_result_keys_size--;
8888 }
8889 // 18. If extensibleTarget is true, return trapResult.
8890 if (extensible_target) {
8891 return accumulator->AddKeysFromProxy(proxy, trap_result);
8892 }
8893 // 19. Repeat, for each key that is an element of targetConfigurableKeys:
8894 for (int i = 0; i < target_configurable_keys->length(); ++i) {
8895 Object* key = target_configurable_keys->get(i);
8896 if (key->IsSmi()) continue; // Zapped entry, was nonconfigurable.
8897 // 19a. If key is not an element of uncheckedResultKeys, throw a
8898 // TypeError exception.
8899 int* found = unchecked_result_keys.Find(key);
8900 if (found == nullptr || *found == kGone) {
8901 isolate->Throw(*isolate->factory()->NewTypeError(
8902 MessageTemplate::kProxyOwnKeysMissing, handle(key, isolate)));
8903 return Nothing<bool>();
8904 }
8905 // 19b. Remove key from uncheckedResultKeys.
8906 *found = kGone;
8907 unchecked_result_keys_size--;
8908 }
8909 // 20. If uncheckedResultKeys is not empty, throw a TypeError exception.
8910 if (unchecked_result_keys_size != 0) {
8911 DCHECK_GT(unchecked_result_keys_size, 0);
8912 isolate->Throw(*isolate->factory()->NewTypeError(
8913 MessageTemplate::kProxyOwnKeysNonExtensible));
8914 return Nothing<bool>();
8915 }
8916 // 21. Return trapResult.
8917 return accumulator->AddKeysFromProxy(proxy, trap_result);
8918}
Ben Murdoch3ef787d2012-04-12 10:51:47 +01008919
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00008920
8921MaybeHandle<FixedArray> JSReceiver::GetKeys(Handle<JSReceiver> object,
8922 KeyCollectionType type,
8923 PropertyFilter filter,
8924 GetKeysConversion keys_conversion) {
8925 USE(ContainsOnlyValidKeys);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00008926 Isolate* isolate = object->GetIsolate();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00008927 KeyAccumulator accumulator(isolate, filter);
8928 MAYBE_RETURN(
8929 GetKeys_Internal(isolate, object, object, type, filter, &accumulator),
8930 MaybeHandle<FixedArray>());
8931 Handle<FixedArray> keys = accumulator.GetKeys(keys_conversion);
8932 DCHECK(ContainsOnlyValidKeys(keys));
8933 return keys;
Ben Murdoch3ef787d2012-04-12 10:51:47 +01008934}
8935
8936
Ben Murdochb8a8cc12014-11-26 15:28:44 +00008937bool Map::DictionaryElementsInPrototypeChainOnly() {
8938 if (IsDictionaryElementsKind(elements_kind())) {
8939 return false;
8940 }
8941
8942 for (PrototypeIterator iter(this); !iter.IsAtEnd(); iter.Advance()) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00008943 // Be conservative, don't walk into proxies.
8944 if (iter.GetCurrent()->IsJSProxy()) return true;
8945 // String wrappers have non-configurable, non-writable elements.
8946 if (iter.GetCurrent()->IsStringWrapper()) return true;
8947 JSObject* current = iter.GetCurrent<JSObject>();
8948
8949 if (current->HasDictionaryElements() &&
8950 current->element_dictionary()->requires_slow_elements()) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00008951 return true;
8952 }
8953
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00008954 if (current->HasSlowArgumentsElements()) {
8955 FixedArray* parameter_map = FixedArray::cast(current->elements());
8956 Object* arguments = parameter_map->get(1);
8957 if (SeededNumberDictionary::cast(arguments)->requires_slow_elements()) {
8958 return true;
8959 }
Steve Blocka7e24c12009-10-30 11:49:00 +00008960 }
8961 }
8962
Ben Murdochb8a8cc12014-11-26 15:28:44 +00008963 return false;
Leon Clarkef7060e22010-06-03 12:02:55 +01008964}
8965
8966
Ben Murdochb8a8cc12014-11-26 15:28:44 +00008967MaybeHandle<Object> JSObject::DefineAccessor(Handle<JSObject> object,
8968 Handle<Name> name,
8969 Handle<Object> getter,
8970 Handle<Object> setter,
8971 PropertyAttributes attributes) {
8972 Isolate* isolate = object->GetIsolate();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00008973
8974 LookupIterator it = LookupIterator::PropertyOrElement(
8975 isolate, object, name, LookupIterator::HIDDEN_SKIP_INTERCEPTOR);
8976 return DefineAccessor(&it, getter, setter, attributes);
8977}
8978
8979
8980MaybeHandle<Object> JSObject::DefineAccessor(LookupIterator* it,
8981 Handle<Object> getter,
8982 Handle<Object> setter,
8983 PropertyAttributes attributes) {
8984 Isolate* isolate = it->isolate();
8985
8986 if (it->state() == LookupIterator::ACCESS_CHECK) {
8987 if (!it->HasAccess()) {
8988 isolate->ReportFailedAccessCheck(it->GetHolder<JSObject>());
8989 RETURN_EXCEPTION_IF_SCHEDULED_EXCEPTION(isolate, Object);
8990 return isolate->factory()->undefined_value();
8991 }
8992 it->Next();
Steve Blocka7e24c12009-10-30 11:49:00 +00008993 }
8994
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00008995 Handle<JSObject> object = Handle<JSObject>::cast(it->GetReceiver());
8996 // Ignore accessors on typed arrays.
8997 if (it->IsElement() && object->HasFixedTypedArrayElements()) {
8998 return it->factory()->undefined_value();
Steve Blocka7e24c12009-10-30 11:49:00 +00008999 }
9000
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009001 Handle<Object> old_value = isolate->factory()->the_hole_value();
9002 bool is_observed = object->map()->is_observed() &&
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00009003 !isolate->IsInternallyUsedPropertyName(it->GetName());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009004 bool preexists = false;
9005 if (is_observed) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00009006 CHECK(GetPropertyAttributes(it).IsJust());
9007 preexists = it->IsFound();
9008 if (preexists && (it->state() == LookupIterator::DATA ||
9009 it->GetAccessors()->IsAccessorInfo())) {
9010 old_value = GetProperty(it).ToHandleChecked();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009011 }
9012 }
9013
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00009014 DCHECK(getter->IsCallable() || getter->IsUndefined() || getter->IsNull());
9015 DCHECK(setter->IsCallable() || setter->IsUndefined() || setter->IsNull());
9016 // At least one of the accessors needs to be a new value.
9017 DCHECK(!getter->IsNull() || !setter->IsNull());
9018 if (!getter->IsNull()) {
9019 it->TransitionToAccessorProperty(ACCESSOR_GETTER, getter, attributes);
9020 }
9021 if (!setter->IsNull()) {
9022 it->TransitionToAccessorProperty(ACCESSOR_SETTER, setter, attributes);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009023 }
9024
9025 if (is_observed) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00009026 // Make sure the top context isn't changed.
9027 AssertNoContextChange ncc(isolate);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009028 const char* type = preexists ? "reconfigure" : "add";
Emily Bernierd0a1eb72015-03-24 16:35:39 -04009029 RETURN_ON_EXCEPTION(
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00009030 isolate, EnqueueChangeRecord(object, type, it->GetName(), old_value),
9031 Object);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009032 }
9033
9034 return isolate->factory()->undefined_value();
Steve Blocka7e24c12009-10-30 11:49:00 +00009035}
9036
9037
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009038MaybeHandle<Object> JSObject::SetAccessor(Handle<JSObject> object,
9039 Handle<AccessorInfo> info) {
9040 Isolate* isolate = object->GetIsolate();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00009041 Handle<Name> name(Name::cast(info->name()), isolate);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009042
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00009043 LookupIterator it = LookupIterator::PropertyOrElement(
9044 isolate, object, name, LookupIterator::HIDDEN_SKIP_INTERCEPTOR);
Leon Clarkef7060e22010-06-03 12:02:55 +01009045
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00009046 // Duplicate ACCESS_CHECK outside of GetPropertyAttributes for the case that
9047 // the FailedAccessCheckCallbackFunction doesn't throw an exception.
9048 //
9049 // TODO(verwaest): Force throw an exception if the callback doesn't, so we can
9050 // remove reliance on default return values.
9051 if (it.state() == LookupIterator::ACCESS_CHECK) {
9052 if (!it.HasAccess()) {
9053 isolate->ReportFailedAccessCheck(object);
9054 RETURN_EXCEPTION_IF_SCHEDULED_EXCEPTION(isolate, Object);
9055 return it.factory()->undefined_value();
Leon Clarkef7060e22010-06-03 12:02:55 +01009056 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00009057 it.Next();
Leon Clarkef7060e22010-06-03 12:02:55 +01009058 }
9059
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00009060 // Ignore accessors on typed arrays.
9061 if (it.IsElement() && object->HasFixedTypedArrayElements()) {
9062 return it.factory()->undefined_value();
9063 }
9064
9065 CHECK(GetPropertyAttributes(&it).IsJust());
9066
9067 // ES5 forbids turning a property into an accessor if it's not
9068 // configurable. See 8.6.1 (Table 5).
9069 if (it.IsFound() && !it.IsConfigurable()) {
9070 return it.factory()->undefined_value();
9071 }
9072
9073 it.TransitionToAccessorPair(info, info->property_attributes());
9074
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009075 return object;
Leon Clarkef7060e22010-06-03 12:02:55 +01009076}
9077
9078
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009079MaybeHandle<Object> JSObject::GetAccessor(Handle<JSObject> object,
9080 Handle<Name> name,
9081 AccessorComponent component) {
9082 Isolate* isolate = object->GetIsolate();
Steve Block44f0eee2011-05-26 01:26:41 +01009083
Steve Blocka7e24c12009-10-30 11:49:00 +00009084 // Make sure that the top context does not change when doing callbacks or
9085 // interceptor calls.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009086 AssertNoContextChange ncc(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00009087
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00009088 LookupIterator it = LookupIterator::PropertyOrElement(
9089 isolate, object, name, LookupIterator::PROTOTYPE_CHAIN_SKIP_INTERCEPTOR);
9090
9091 for (; it.IsFound(); it.Next()) {
9092 switch (it.state()) {
9093 case LookupIterator::INTERCEPTOR:
9094 case LookupIterator::NOT_FOUND:
9095 case LookupIterator::TRANSITION:
9096 UNREACHABLE();
9097
9098 case LookupIterator::ACCESS_CHECK:
9099 if (it.HasAccess()) continue;
9100 isolate->ReportFailedAccessCheck(it.GetHolder<JSObject>());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009101 RETURN_EXCEPTION_IF_SCHEDULED_EXCEPTION(isolate, Object);
9102 return isolate->factory()->undefined_value();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009103
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00009104 case LookupIterator::JSPROXY:
9105 return isolate->factory()->undefined_value();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009106
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00009107 case LookupIterator::INTEGER_INDEXED_EXOTIC:
9108 return isolate->factory()->undefined_value();
9109 case LookupIterator::DATA:
9110 continue;
9111 case LookupIterator::ACCESSOR: {
9112 Handle<Object> maybe_pair = it.GetAccessors();
9113 if (maybe_pair->IsAccessorPair()) {
9114 return handle(
9115 AccessorPair::cast(*maybe_pair)->GetComponent(component),
9116 isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00009117 }
9118 }
9119 }
9120 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00009121
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009122 return isolate->factory()->undefined_value();
Steve Blocka7e24c12009-10-30 11:49:00 +00009123}
9124
9125
9126Object* JSObject::SlowReverseLookup(Object* value) {
9127 if (HasFastProperties()) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009128 int number_of_own_descriptors = map()->NumberOfOwnDescriptors();
Steve Blocka7e24c12009-10-30 11:49:00 +00009129 DescriptorArray* descs = map()->instance_descriptors();
Emily Bernierd0a1eb72015-03-24 16:35:39 -04009130 bool value_is_number = value->IsNumber();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009131 for (int i = 0; i < number_of_own_descriptors; i++) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00009132 if (descs->GetType(i) == DATA) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -04009133 FieldIndex field_index = FieldIndex::ForDescriptor(map(), i);
9134 if (IsUnboxedDoubleField(field_index)) {
9135 if (value_is_number) {
9136 double property = RawFastDoublePropertyAt(field_index);
9137 if (property == value->Number()) {
9138 return descs->GetKey(i);
9139 }
9140 }
9141 } else {
9142 Object* property = RawFastPropertyAt(field_index);
9143 if (field_index.is_double()) {
9144 DCHECK(property->IsMutableHeapNumber());
9145 if (value_is_number && property->Number() == value->Number()) {
9146 return descs->GetKey(i);
9147 }
9148 } else if (property == value) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009149 return descs->GetKey(i);
9150 }
Steve Blocka7e24c12009-10-30 11:49:00 +00009151 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00009152 } else if (descs->GetType(i) == DATA_CONSTANT) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009153 if (descs->GetConstant(i) == value) {
Steve Blocka7e24c12009-10-30 11:49:00 +00009154 return descs->GetKey(i);
9155 }
9156 }
9157 }
Ben Murdoch8b112d22011-06-08 16:22:53 +01009158 return GetHeap()->undefined_value();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00009159 } else if (IsJSGlobalObject()) {
9160 return global_dictionary()->SlowReverseLookup(value);
Steve Blocka7e24c12009-10-30 11:49:00 +00009161 } else {
9162 return property_dictionary()->SlowReverseLookup(value);
9163 }
9164}
9165
9166
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009167Handle<Map> Map::RawCopy(Handle<Map> map, int instance_size) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00009168 Isolate* isolate = map->GetIsolate();
9169 Handle<Map> result =
9170 isolate->factory()->NewMap(map->instance_type(), instance_size);
9171 Handle<Object> prototype(map->prototype(), isolate);
9172 Map::SetPrototype(result, prototype);
9173 result->set_constructor_or_backpointer(map->GetConstructor());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009174 result->set_bit_field(map->bit_field());
9175 result->set_bit_field2(map->bit_field2());
9176 int new_bit_field3 = map->bit_field3();
9177 new_bit_field3 = OwnsDescriptors::update(new_bit_field3, true);
9178 new_bit_field3 = NumberOfOwnDescriptorsBits::update(new_bit_field3, 0);
9179 new_bit_field3 = EnumLengthBits::update(new_bit_field3,
9180 kInvalidEnumCacheSentinel);
9181 new_bit_field3 = Deprecated::update(new_bit_field3, false);
9182 if (!map->is_dictionary_map()) {
9183 new_bit_field3 = IsUnstable::update(new_bit_field3, false);
John Reck59135872010-11-02 12:39:01 -07009184 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00009185 new_bit_field3 =
9186 ConstructionCounter::update(new_bit_field3, kNoSlackTracking);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009187 result->set_bit_field3(new_bit_field3);
Steve Blocka7e24c12009-10-30 11:49:00 +00009188 return result;
9189}
9190
9191
Emily Bernierd0a1eb72015-03-24 16:35:39 -04009192Handle<Map> Map::Normalize(Handle<Map> fast_map, PropertyNormalizationMode mode,
9193 const char* reason) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009194 DCHECK(!fast_map->is_dictionary_map());
9195
9196 Isolate* isolate = fast_map->GetIsolate();
9197 Handle<Object> maybe_cache(isolate->native_context()->normalized_map_cache(),
9198 isolate);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00009199 bool use_cache = !fast_map->is_prototype_map() && !maybe_cache->IsUndefined();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009200 Handle<NormalizedMapCache> cache;
9201 if (use_cache) cache = Handle<NormalizedMapCache>::cast(maybe_cache);
9202
9203 Handle<Map> new_map;
9204 if (use_cache && cache->Get(fast_map, mode).ToHandle(&new_map)) {
9205#ifdef VERIFY_HEAP
9206 if (FLAG_verify_heap) new_map->DictionaryMapVerify();
9207#endif
9208#ifdef ENABLE_SLOW_DCHECKS
9209 if (FLAG_enable_slow_asserts) {
9210 // The cached map should match newly created normalized map bit-by-bit,
9211 // except for the code cache, which can contain some ics which can be
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00009212 // applied to the shared map, dependent code and weak cell cache.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009213 Handle<Map> fresh = Map::CopyNormalized(fast_map, mode);
9214
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00009215 if (new_map->is_prototype_map()) {
9216 // For prototype maps, the PrototypeInfo is not copied.
9217 DCHECK(memcmp(fresh->address(), new_map->address(),
9218 kTransitionsOrPrototypeInfoOffset) == 0);
9219 DCHECK(fresh->raw_transitions() == Smi::FromInt(0));
9220 STATIC_ASSERT(kDescriptorsOffset ==
9221 kTransitionsOrPrototypeInfoOffset + kPointerSize);
9222 DCHECK(memcmp(HeapObject::RawField(*fresh, kDescriptorsOffset),
9223 HeapObject::RawField(*new_map, kDescriptorsOffset),
9224 kCodeCacheOffset - kDescriptorsOffset) == 0);
9225 } else {
9226 DCHECK(memcmp(fresh->address(), new_map->address(),
9227 Map::kCodeCacheOffset) == 0);
9228 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009229 STATIC_ASSERT(Map::kDependentCodeOffset ==
9230 Map::kCodeCacheOffset + kPointerSize);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00009231 STATIC_ASSERT(Map::kWeakCellCacheOffset ==
9232 Map::kDependentCodeOffset + kPointerSize);
9233 int offset = Map::kWeakCellCacheOffset + kPointerSize;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009234 DCHECK(memcmp(fresh->address() + offset,
9235 new_map->address() + offset,
9236 Map::kSize - offset) == 0);
9237 }
9238#endif
9239 } else {
9240 new_map = Map::CopyNormalized(fast_map, mode);
9241 if (use_cache) {
9242 cache->Set(fast_map, new_map);
9243 isolate->counters()->normalized_maps()->Increment();
9244 }
Emily Bernierd0a1eb72015-03-24 16:35:39 -04009245#if TRACE_MAPS
9246 if (FLAG_trace_maps) {
9247 PrintF("[TraceMaps: Normalize from= %p to= %p reason= %s ]\n",
9248 reinterpret_cast<void*>(*fast_map),
9249 reinterpret_cast<void*>(*new_map), reason);
9250 }
9251#endif
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009252 }
9253 fast_map->NotifyLeafMapLayoutChange();
9254 return new_map;
9255}
9256
9257
9258Handle<Map> Map::CopyNormalized(Handle<Map> map,
9259 PropertyNormalizationMode mode) {
9260 int new_instance_size = map->instance_size();
Kristian Monsen80d68ea2010-09-08 11:05:35 +01009261 if (mode == CLEAR_INOBJECT_PROPERTIES) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00009262 new_instance_size -= map->GetInObjectProperties() * kPointerSize;
Kristian Monsen80d68ea2010-09-08 11:05:35 +01009263 }
9264
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009265 Handle<Map> result = RawCopy(map, new_instance_size);
Kristian Monsen80d68ea2010-09-08 11:05:35 +01009266
9267 if (mode != CLEAR_INOBJECT_PROPERTIES) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00009268 result->SetInObjectProperties(map->GetInObjectProperties());
Kristian Monsen80d68ea2010-09-08 11:05:35 +01009269 }
9270
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009271 result->set_dictionary_map(true);
9272 result->set_migration_target(false);
Kristian Monsen80d68ea2010-09-08 11:05:35 +01009273
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009274#ifdef VERIFY_HEAP
9275 if (FLAG_verify_heap) result->DictionaryMapVerify();
Kristian Monsen80d68ea2010-09-08 11:05:35 +01009276#endif
9277
9278 return result;
9279}
9280
9281
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00009282Handle<Map> Map::CopyInitialMap(Handle<Map> map, int instance_size,
9283 int in_object_properties,
9284 int unused_property_fields) {
9285#ifdef DEBUG
9286 Isolate* isolate = map->GetIsolate();
9287 // Strict and strong function maps have Function as a constructor but the
9288 // Function's initial map is a sloppy function map. Same holds for
9289 // GeneratorFunction and its initial map.
9290 Object* constructor = map->GetConstructor();
9291 DCHECK(constructor->IsJSFunction());
9292 DCHECK(*map == JSFunction::cast(constructor)->initial_map() ||
9293 *map == *isolate->strict_function_map() ||
9294 *map == *isolate->strong_function_map() ||
9295 *map == *isolate->strict_generator_function_map() ||
9296 *map == *isolate->strong_generator_function_map());
9297#endif
9298 // Initial maps must always own their descriptors and it's descriptor array
9299 // does not contain descriptors that do not belong to the map.
9300 DCHECK(map->owns_descriptors());
9301 DCHECK_EQ(map->NumberOfOwnDescriptors(),
9302 map->instance_descriptors()->number_of_descriptors());
9303
9304 Handle<Map> result = RawCopy(map, instance_size);
9305
9306 // Please note instance_type and instance_size are set when allocated.
9307 result->SetInObjectProperties(in_object_properties);
9308 result->set_unused_property_fields(unused_property_fields);
9309
9310 int number_of_own_descriptors = map->NumberOfOwnDescriptors();
9311 if (number_of_own_descriptors > 0) {
9312 // The copy will use the same descriptors array.
9313 result->UpdateDescriptors(map->instance_descriptors(),
9314 map->GetLayoutDescriptor());
9315 result->SetNumberOfOwnDescriptors(number_of_own_descriptors);
9316
9317 DCHECK_EQ(result->NumberOfFields(),
9318 in_object_properties - unused_property_fields);
9319 }
9320
9321 return result;
9322}
9323
9324
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009325Handle<Map> Map::CopyDropDescriptors(Handle<Map> map) {
9326 Handle<Map> result = RawCopy(map, map->instance_size());
9327
9328 // Please note instance_type and instance_size are set when allocated.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00009329 if (map->IsJSObjectMap()) {
9330 result->SetInObjectProperties(map->GetInObjectProperties());
9331 result->set_unused_property_fields(map->unused_property_fields());
9332 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009333 result->ClearCodeCache(map->GetHeap());
9334 map->NotifyLeafMapLayoutChange();
9335 return result;
9336}
9337
9338
9339Handle<Map> Map::ShareDescriptor(Handle<Map> map,
9340 Handle<DescriptorArray> descriptors,
9341 Descriptor* descriptor) {
9342 // Sanity check. This path is only to be taken if the map owns its descriptor
9343 // array, implying that its NumberOfOwnDescriptors equals the number of
9344 // descriptors in the descriptor array.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00009345 DCHECK_EQ(map->NumberOfOwnDescriptors(),
9346 map->instance_descriptors()->number_of_descriptors());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009347
9348 Handle<Map> result = CopyDropDescriptors(map);
9349 Handle<Name> name = descriptor->GetKey();
9350
9351 // Ensure there's space for the new descriptor in the shared descriptor array.
9352 if (descriptors->NumberOfSlackDescriptors() == 0) {
9353 int old_size = descriptors->number_of_descriptors();
9354 if (old_size == 0) {
9355 descriptors = DescriptorArray::Allocate(map->GetIsolate(), 0, 1);
9356 } else {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00009357 int slack = SlackForArraySize(old_size, kMaxNumberOfDescriptors);
9358 EnsureDescriptorSlack(map, slack);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009359 descriptors = handle(map->instance_descriptors());
9360 }
John Reck59135872010-11-02 12:39:01 -07009361 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009362
Emily Bernierd0a1eb72015-03-24 16:35:39 -04009363 Handle<LayoutDescriptor> layout_descriptor =
9364 FLAG_unbox_double_fields
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00009365 ? LayoutDescriptor::ShareAppend(map, descriptor->GetDetails())
Emily Bernierd0a1eb72015-03-24 16:35:39 -04009366 : handle(LayoutDescriptor::FastPointerLayout(), map->GetIsolate());
9367
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009368 {
9369 DisallowHeapAllocation no_gc;
9370 descriptors->Append(descriptor);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04009371 result->InitializeDescriptors(*descriptors, *layout_descriptor);
John Reck59135872010-11-02 12:39:01 -07009372 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009373
9374 DCHECK(result->NumberOfOwnDescriptors() == map->NumberOfOwnDescriptors() + 1);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04009375 ConnectTransition(map, result, name, SIMPLE_PROPERTY_TRANSITION);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009376
9377 return result;
9378}
9379
9380
Emily Bernierd0a1eb72015-03-24 16:35:39 -04009381#if TRACE_MAPS
9382
9383// static
9384void Map::TraceTransition(const char* what, Map* from, Map* to, Name* name) {
9385 if (FLAG_trace_maps) {
9386 PrintF("[TraceMaps: %s from= %p to= %p name= ", what,
9387 reinterpret_cast<void*>(from), reinterpret_cast<void*>(to));
9388 name->NameShortPrint();
9389 PrintF(" ]\n");
9390 }
9391}
9392
9393
9394// static
9395void Map::TraceAllTransitions(Map* map) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00009396 Object* transitions = map->raw_transitions();
9397 int num_transitions = TransitionArray::NumberOfTransitions(transitions);
9398 for (int i = -0; i < num_transitions; ++i) {
9399 Map* target = TransitionArray::GetTarget(transitions, i);
9400 Name* key = TransitionArray::GetKey(transitions, i);
9401 Map::TraceTransition("Transition", map, target, key);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04009402 Map::TraceAllTransitions(target);
9403 }
9404}
9405
9406#endif // TRACE_MAPS
9407
9408
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009409void Map::ConnectTransition(Handle<Map> parent, Handle<Map> child,
9410 Handle<Name> name, SimpleTransitionFlag flag) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00009411 if (!parent->GetBackPointer()->IsUndefined()) {
9412 parent->set_owns_descriptors(false);
9413 } else {
9414 // |parent| is initial map and it must keep the ownership, there must be no
9415 // descriptors in the descriptors array that do not belong to the map.
9416 DCHECK(parent->owns_descriptors());
9417 DCHECK_EQ(parent->NumberOfOwnDescriptors(),
9418 parent->instance_descriptors()->number_of_descriptors());
9419 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009420 if (parent->is_prototype_map()) {
9421 DCHECK(child->is_prototype_map());
Emily Bernierd0a1eb72015-03-24 16:35:39 -04009422#if TRACE_MAPS
9423 Map::TraceTransition("NoTransition", *parent, *child, *name);
9424#endif
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009425 } else {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00009426 TransitionArray::Insert(parent, name, child, flag);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04009427#if TRACE_MAPS
9428 Map::TraceTransition("Transition", *parent, *child, *name);
9429#endif
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009430 }
9431}
9432
9433
Emily Bernierd0a1eb72015-03-24 16:35:39 -04009434Handle<Map> Map::CopyReplaceDescriptors(
9435 Handle<Map> map, Handle<DescriptorArray> descriptors,
9436 Handle<LayoutDescriptor> layout_descriptor, TransitionFlag flag,
9437 MaybeHandle<Name> maybe_name, const char* reason,
9438 SimpleTransitionFlag simple_flag) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009439 DCHECK(descriptors->IsSortedNoDuplicates());
9440
9441 Handle<Map> result = CopyDropDescriptors(map);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009442
9443 if (!map->is_prototype_map()) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00009444 if (flag == INSERT_TRANSITION &&
9445 TransitionArray::CanHaveMoreTransitions(map)) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -04009446 result->InitializeDescriptors(*descriptors, *layout_descriptor);
9447
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009448 Handle<Name> name;
9449 CHECK(maybe_name.ToHandle(&name));
9450 ConnectTransition(map, result, name, simple_flag);
9451 } else {
9452 int length = descriptors->number_of_descriptors();
9453 for (int i = 0; i < length; i++) {
9454 descriptors->SetRepresentation(i, Representation::Tagged());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00009455 if (descriptors->GetDetails(i).type() == DATA) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009456 descriptors->SetValue(i, HeapType::Any());
9457 }
9458 }
Emily Bernierd0a1eb72015-03-24 16:35:39 -04009459 result->InitializeDescriptors(*descriptors,
9460 LayoutDescriptor::FastPointerLayout());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009461 }
Emily Bernierd0a1eb72015-03-24 16:35:39 -04009462 } else {
9463 result->InitializeDescriptors(*descriptors, *layout_descriptor);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009464 }
Emily Bernierd0a1eb72015-03-24 16:35:39 -04009465#if TRACE_MAPS
9466 if (FLAG_trace_maps &&
9467 // Mirror conditions above that did not call ConnectTransition().
9468 (map->is_prototype_map() ||
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00009469 !(flag == INSERT_TRANSITION &&
9470 TransitionArray::CanHaveMoreTransitions(map)))) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -04009471 PrintF("[TraceMaps: ReplaceDescriptors from= %p to= %p reason= %s ]\n",
9472 reinterpret_cast<void*>(*map), reinterpret_cast<void*>(*result),
9473 reason);
9474 }
9475#endif
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009476
9477 return result;
9478}
9479
9480
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00009481// Creates transition tree starting from |split_map| and adding all descriptors
9482// starting from descriptor with index |split_map|.NumberOfOwnDescriptors().
9483// The way how it is done is tricky because of GC and special descriptors
9484// marking logic.
9485Handle<Map> Map::AddMissingTransitions(
9486 Handle<Map> split_map, Handle<DescriptorArray> descriptors,
Emily Bernierd0a1eb72015-03-24 16:35:39 -04009487 Handle<LayoutDescriptor> full_layout_descriptor) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009488 DCHECK(descriptors->IsSortedNoDuplicates());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00009489 int split_nof = split_map->NumberOfOwnDescriptors();
9490 int nof_descriptors = descriptors->number_of_descriptors();
9491 DCHECK_LT(split_nof, nof_descriptors);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009492
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00009493 // Start with creating last map which will own full descriptors array.
9494 // This is necessary to guarantee that GC will mark the whole descriptor
9495 // array if any of the allocations happening below fail.
9496 // Number of unused properties is temporarily incorrect and the layout
9497 // descriptor could unnecessarily be in slow mode but we will fix after
9498 // all the other intermediate maps are created.
9499 Handle<Map> last_map = CopyDropDescriptors(split_map);
9500 last_map->InitializeDescriptors(*descriptors, *full_layout_descriptor);
9501 last_map->set_unused_property_fields(0);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009502
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00009503 // During creation of intermediate maps we violate descriptors sharing
9504 // invariant since the last map is not yet connected to the transition tree
9505 // we create here. But it is safe because GC never trims map's descriptors
9506 // if there are no dead transitions from that map and this is exactly the
9507 // case for all the intermediate maps we create here.
9508 Handle<Map> map = split_map;
9509 for (int i = split_nof; i < nof_descriptors - 1; ++i) {
9510 Handle<Map> new_map = CopyDropDescriptors(map);
9511 InstallDescriptors(map, new_map, i, descriptors, full_layout_descriptor);
9512 map = new_map;
9513 }
9514 map->NotifyLeafMapLayoutChange();
9515 InstallDescriptors(map, last_map, nof_descriptors - 1, descriptors,
9516 full_layout_descriptor);
9517 return last_map;
9518}
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009519
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00009520
9521// Since this method is used to rewrite an existing transition tree, it can
9522// always insert transitions without checking.
9523void Map::InstallDescriptors(Handle<Map> parent, Handle<Map> child,
9524 int new_descriptor,
9525 Handle<DescriptorArray> descriptors,
9526 Handle<LayoutDescriptor> full_layout_descriptor) {
9527 DCHECK(descriptors->IsSortedNoDuplicates());
9528
9529 child->set_instance_descriptors(*descriptors);
9530 child->SetNumberOfOwnDescriptors(new_descriptor + 1);
9531
9532 int unused_property_fields = parent->unused_property_fields();
Emily Bernierd0a1eb72015-03-24 16:35:39 -04009533 PropertyDetails details = descriptors->GetDetails(new_descriptor);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00009534 if (details.location() == kField) {
9535 unused_property_fields = parent->unused_property_fields() - 1;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009536 if (unused_property_fields < 0) {
9537 unused_property_fields += JSObject::kFieldsAdded;
9538 }
9539 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00009540 child->set_unused_property_fields(unused_property_fields);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009541
Emily Bernierd0a1eb72015-03-24 16:35:39 -04009542 if (FLAG_unbox_double_fields) {
9543 Handle<LayoutDescriptor> layout_descriptor =
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00009544 LayoutDescriptor::AppendIfFastOrUseFull(parent, details,
Emily Bernierd0a1eb72015-03-24 16:35:39 -04009545 full_layout_descriptor);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00009546 child->set_layout_descriptor(*layout_descriptor);
9547#ifdef VERIFY_HEAP
9548 // TODO(ishell): remove these checks from VERIFY_HEAP mode.
9549 if (FLAG_verify_heap) {
9550 CHECK(child->layout_descriptor()->IsConsistentWithMap(*child));
9551 }
9552#else
9553 SLOW_DCHECK(child->layout_descriptor()->IsConsistentWithMap(*child));
9554#endif
9555 child->set_visitor_id(Heap::GetStaticVisitorIdForMap(*child));
Emily Bernierd0a1eb72015-03-24 16:35:39 -04009556 }
9557
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009558 Handle<Name> name = handle(descriptors->GetKey(new_descriptor));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00009559 ConnectTransition(parent, child, name, SIMPLE_PROPERTY_TRANSITION);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009560}
9561
9562
9563Handle<Map> Map::CopyAsElementsKind(Handle<Map> map, ElementsKind kind,
9564 TransitionFlag flag) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00009565 Map* maybe_elements_transition_map = NULL;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009566 if (flag == INSERT_TRANSITION) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00009567 maybe_elements_transition_map = map->ElementsTransitionMap();
9568 DCHECK(maybe_elements_transition_map == NULL ||
9569 (maybe_elements_transition_map->elements_kind() ==
9570 DICTIONARY_ELEMENTS &&
9571 kind == DICTIONARY_ELEMENTS));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009572 DCHECK(!IsFastElementsKind(kind) ||
9573 IsMoreGeneralElementsKindTransition(map->elements_kind(), kind));
9574 DCHECK(kind != map->elements_kind());
9575 }
9576
Emily Bernierd0a1eb72015-03-24 16:35:39 -04009577 bool insert_transition = flag == INSERT_TRANSITION &&
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00009578 TransitionArray::CanHaveMoreTransitions(map) &&
9579 maybe_elements_transition_map == NULL;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009580
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00009581 if (insert_transition) {
9582 Handle<Map> new_map = CopyForTransition(map, "CopyAsElementsKind");
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009583 new_map->set_elements_kind(kind);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00009584
9585 Isolate* isolate = map->GetIsolate();
9586 Handle<Name> name = isolate->factory()->elements_transition_symbol();
9587 ConnectTransition(map, new_map, name, SPECIAL_TRANSITION);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009588 return new_map;
9589 }
9590
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009591 // Create a new free-floating map only if we are not allowed to store it.
Emily Bernierd0a1eb72015-03-24 16:35:39 -04009592 Handle<Map> new_map = Copy(map, "CopyAsElementsKind");
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009593 new_map->set_elements_kind(kind);
Steve Block8defd9f2010-07-08 12:39:36 +01009594 return new_map;
Steve Blocka7e24c12009-10-30 11:49:00 +00009595}
9596
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009597
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00009598Handle<Map> Map::AsLanguageMode(Handle<Map> initial_map,
9599 LanguageMode language_mode, FunctionKind kind) {
9600 DCHECK_EQ(JS_FUNCTION_TYPE, initial_map->instance_type());
9601 // Initial map for sloppy mode function is stored in the function
9602 // constructor. Initial maps for strict and strong modes are cached as
9603 // special transitions using |strict_function_transition_symbol| and
9604 // |strong_function_transition_symbol| respectively as a key.
9605 if (language_mode == SLOPPY) return initial_map;
9606 Isolate* isolate = initial_map->GetIsolate();
9607 Factory* factory = isolate->factory();
9608 Handle<Symbol> transition_symbol;
9609
9610 int map_index = Context::FunctionMapIndex(language_mode, kind);
9611 Handle<Map> function_map(
9612 Map::cast(isolate->native_context()->get(map_index)));
9613
9614 STATIC_ASSERT(LANGUAGE_END == 3);
9615 switch (language_mode) {
9616 case STRICT:
9617 transition_symbol = factory->strict_function_transition_symbol();
9618 break;
9619 case STRONG:
9620 transition_symbol = factory->strong_function_transition_symbol();
9621 break;
9622 default:
9623 UNREACHABLE();
9624 break;
9625 }
9626 Map* maybe_transition =
9627 TransitionArray::SearchSpecial(*initial_map, *transition_symbol);
9628 if (maybe_transition != NULL) {
9629 return handle(maybe_transition, isolate);
9630 }
9631 initial_map->NotifyLeafMapLayoutChange();
9632
9633 // Create new map taking descriptors from the |function_map| and all
9634 // the other details from the |initial_map|.
9635 Handle<Map> map =
9636 Map::CopyInitialMap(function_map, initial_map->instance_size(),
9637 initial_map->GetInObjectProperties(),
9638 initial_map->unused_property_fields());
9639 map->SetConstructor(initial_map->GetConstructor());
9640 map->set_prototype(initial_map->prototype());
9641
9642 if (TransitionArray::CanHaveMoreTransitions(initial_map)) {
9643 Map::ConnectTransition(initial_map, map, transition_symbol,
9644 SPECIAL_TRANSITION);
9645 }
9646 return map;
9647}
9648
9649
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009650Handle<Map> Map::CopyForObserved(Handle<Map> map) {
9651 DCHECK(!map->is_observed());
9652
Ben Murdoch3ef787d2012-04-12 10:51:47 +01009653 Isolate* isolate = map->GetIsolate();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009654
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00009655 bool insert_transition =
9656 TransitionArray::CanHaveMoreTransitions(map) && !map->is_prototype_map();
9657
9658 if (insert_transition) {
9659 Handle<Map> new_map = CopyForTransition(map, "CopyForObserved");
9660 new_map->set_is_observed();
9661
9662 Handle<Name> name = isolate->factory()->observed_symbol();
9663 ConnectTransition(map, new_map, name, SPECIAL_TRANSITION);
9664 return new_map;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009665 }
9666
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00009667 // Create a new free-floating map only if we are not allowed to store it.
9668 Handle<Map> new_map = Map::Copy(map, "CopyForObserved");
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009669 new_map->set_is_observed();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00009670 return new_map;
9671}
9672
9673
9674Handle<Map> Map::CopyForTransition(Handle<Map> map, const char* reason) {
9675 DCHECK(!map->is_prototype_map());
9676 Handle<Map> new_map = CopyDropDescriptors(map);
9677
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009678 if (map->owns_descriptors()) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00009679 // In case the map owned its own descriptors, share the descriptors and
9680 // transfer ownership to the new map.
Emily Bernierd0a1eb72015-03-24 16:35:39 -04009681 // The properties did not change, so reuse descriptors.
9682 new_map->InitializeDescriptors(map->instance_descriptors(),
9683 map->GetLayoutDescriptor());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00009684 } else {
9685 // In case the map did not own its own descriptors, a split is forced by
9686 // copying the map; creating a new descriptor array cell.
9687 Handle<DescriptorArray> descriptors(map->instance_descriptors());
9688 int number_of_own_descriptors = map->NumberOfOwnDescriptors();
9689 Handle<DescriptorArray> new_descriptors =
9690 DescriptorArray::CopyUpTo(descriptors, number_of_own_descriptors);
9691 Handle<LayoutDescriptor> new_layout_descriptor(map->GetLayoutDescriptor(),
9692 map->GetIsolate());
9693 new_map->InitializeDescriptors(*new_descriptors, *new_layout_descriptor);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009694 }
9695
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00009696#if TRACE_MAPS
9697 if (FLAG_trace_maps) {
9698 PrintF("[TraceMaps: CopyForTransition from= %p to= %p reason= %s ]\n",
9699 reinterpret_cast<void*>(*map), reinterpret_cast<void*>(*new_map),
9700 reason);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04009701 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00009702#endif
9703
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009704 return new_map;
Ben Murdoch3ef787d2012-04-12 10:51:47 +01009705}
Steve Blocka7e24c12009-10-30 11:49:00 +00009706
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009707
Emily Bernierd0a1eb72015-03-24 16:35:39 -04009708Handle<Map> Map::Copy(Handle<Map> map, const char* reason) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009709 Handle<DescriptorArray> descriptors(map->instance_descriptors());
9710 int number_of_own_descriptors = map->NumberOfOwnDescriptors();
9711 Handle<DescriptorArray> new_descriptors =
9712 DescriptorArray::CopyUpTo(descriptors, number_of_own_descriptors);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04009713 Handle<LayoutDescriptor> new_layout_descriptor(map->GetLayoutDescriptor(),
9714 map->GetIsolate());
9715 return CopyReplaceDescriptors(map, new_descriptors, new_layout_descriptor,
9716 OMIT_TRANSITION, MaybeHandle<Name>(), reason,
9717 SPECIAL_TRANSITION);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009718}
9719
9720
9721Handle<Map> Map::Create(Isolate* isolate, int inobject_properties) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -04009722 Handle<Map> copy =
9723 Copy(handle(isolate->object_function()->initial_map()), "MapCreate");
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009724
9725 // Check that we do not overflow the instance size when adding the extra
9726 // inobject properties. If the instance size overflows, we allocate as many
9727 // properties as we can as inobject properties.
9728 int max_extra_properties =
9729 (JSObject::kMaxInstanceSize - JSObject::kHeaderSize) >> kPointerSizeLog2;
9730
9731 if (inobject_properties > max_extra_properties) {
9732 inobject_properties = max_extra_properties;
9733 }
9734
9735 int new_instance_size =
9736 JSObject::kHeaderSize + kPointerSize * inobject_properties;
9737
9738 // Adjust the map with the extra inobject properties.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00009739 copy->SetInObjectProperties(inobject_properties);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009740 copy->set_unused_property_fields(inobject_properties);
9741 copy->set_instance_size(new_instance_size);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00009742 copy->set_visitor_id(Heap::GetStaticVisitorIdForMap(*copy));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009743 return copy;
9744}
9745
9746
Emily Bernierd0a1eb72015-03-24 16:35:39 -04009747Handle<Map> Map::CopyForPreventExtensions(Handle<Map> map,
9748 PropertyAttributes attrs_to_add,
9749 Handle<Symbol> transition_marker,
9750 const char* reason) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009751 int num_descriptors = map->NumberOfOwnDescriptors();
9752 Isolate* isolate = map->GetIsolate();
9753 Handle<DescriptorArray> new_desc = DescriptorArray::CopyUpToAddAttributes(
Emily Bernierd0a1eb72015-03-24 16:35:39 -04009754 handle(map->instance_descriptors(), isolate), num_descriptors,
9755 attrs_to_add);
9756 Handle<LayoutDescriptor> new_layout_descriptor(map->GetLayoutDescriptor(),
9757 isolate);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009758 Handle<Map> new_map = CopyReplaceDescriptors(
Emily Bernierd0a1eb72015-03-24 16:35:39 -04009759 map, new_desc, new_layout_descriptor, INSERT_TRANSITION,
9760 transition_marker, reason, SPECIAL_TRANSITION);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009761 new_map->set_is_extensible(false);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00009762 if (!IsFixedTypedArrayElementsKind(map->elements_kind())) {
9763 new_map->set_elements_kind(DICTIONARY_ELEMENTS);
9764 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009765 return new_map;
9766}
9767
9768
9769bool DescriptorArray::CanHoldValue(int descriptor, Object* value) {
9770 PropertyDetails details = GetDetails(descriptor);
9771 switch (details.type()) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00009772 case DATA:
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009773 return value->FitsRepresentation(details.representation()) &&
9774 GetFieldType(descriptor)->NowContains(value);
9775
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00009776 case DATA_CONSTANT:
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009777 DCHECK(GetConstant(descriptor) != value ||
9778 value->FitsRepresentation(details.representation()));
9779 return GetConstant(descriptor) == value;
9780
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00009781 case ACCESSOR:
9782 case ACCESSOR_CONSTANT:
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009783 return false;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009784 }
9785
9786 UNREACHABLE();
9787 return false;
9788}
9789
9790
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00009791// static
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009792Handle<Map> Map::PrepareForDataProperty(Handle<Map> map, int descriptor,
9793 Handle<Object> value) {
9794 // Dictionaries can store any property value.
9795 if (map->is_dictionary_map()) return map;
9796
9797 // Migrate to the newest map before storing the property.
9798 map = Update(map);
9799
9800 Handle<DescriptorArray> descriptors(map->instance_descriptors());
9801
9802 if (descriptors->CanHoldValue(descriptor, *value)) return map;
9803
9804 Isolate* isolate = map->GetIsolate();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00009805 PropertyAttributes attributes =
9806 descriptors->GetDetails(descriptor).attributes();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009807 Representation representation = value->OptimalRepresentation();
9808 Handle<HeapType> type = value->OptimalType(isolate, representation);
9809
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00009810 return ReconfigureProperty(map, descriptor, kData, attributes, representation,
9811 type, FORCE_FIELD);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009812}
9813
9814
9815Handle<Map> Map::TransitionToDataProperty(Handle<Map> map, Handle<Name> name,
9816 Handle<Object> value,
9817 PropertyAttributes attributes,
9818 StoreFromKeyed store_mode) {
9819 // Dictionary maps can always have additional data properties.
9820 if (map->is_dictionary_map()) return map;
9821
9822 // Migrate to the newest map before storing the property.
9823 map = Update(map);
9824
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00009825 Map* maybe_transition =
9826 TransitionArray::SearchTransition(*map, kData, *name, attributes);
9827 if (maybe_transition != NULL) {
9828 Handle<Map> transition(maybe_transition);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009829 int descriptor = transition->LastAdded();
9830
Emily Bernierd0a1eb72015-03-24 16:35:39 -04009831 DCHECK_EQ(attributes, transition->instance_descriptors()
9832 ->GetDetails(descriptor)
9833 .attributes());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009834
9835 return Map::PrepareForDataProperty(transition, descriptor, value);
9836 }
9837
9838 TransitionFlag flag = INSERT_TRANSITION;
9839 MaybeHandle<Map> maybe_map;
9840 if (value->IsJSFunction()) {
9841 maybe_map = Map::CopyWithConstant(map, name, value, attributes, flag);
9842 } else if (!map->TooManyFastProperties(store_mode)) {
9843 Isolate* isolate = name->GetIsolate();
9844 Representation representation = value->OptimalRepresentation();
9845 Handle<HeapType> type = value->OptimalType(isolate, representation);
9846 maybe_map =
9847 Map::CopyWithField(map, name, type, attributes, representation, flag);
9848 }
9849
9850 Handle<Map> result;
9851 if (!maybe_map.ToHandle(&result)) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -04009852#if TRACE_MAPS
9853 if (FLAG_trace_maps) {
9854 Vector<char> name_buffer = Vector<char>::New(100);
9855 name->NameShortPrint(name_buffer);
9856 Vector<char> buffer = Vector<char>::New(128);
9857 SNPrintF(buffer, "TooManyFastProperties %s", name_buffer.start());
9858 return Map::Normalize(map, CLEAR_INOBJECT_PROPERTIES, buffer.start());
9859 }
9860#endif
9861 return Map::Normalize(map, CLEAR_INOBJECT_PROPERTIES,
9862 "TooManyFastProperties");
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009863 }
9864
9865 return result;
9866}
9867
9868
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00009869Handle<Map> Map::ReconfigureExistingProperty(Handle<Map> map, int descriptor,
9870 PropertyKind kind,
9871 PropertyAttributes attributes) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009872 // Dictionaries have to be reconfigured in-place.
9873 DCHECK(!map->is_dictionary_map());
9874
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00009875 if (!map->GetBackPointer()->IsMap()) {
9876 // There is no benefit from reconstructing transition tree for maps without
9877 // back pointers.
9878 return CopyGeneralizeAllRepresentations(
9879 map, descriptor, FORCE_FIELD, kind, attributes,
9880 "GenAll_AttributesMismatchProtoMap");
9881 }
9882
9883 if (FLAG_trace_generalization) {
9884 map->PrintReconfiguration(stdout, descriptor, kind, attributes);
9885 }
9886
9887 Isolate* isolate = map->GetIsolate();
9888 Handle<Map> new_map = ReconfigureProperty(
9889 map, descriptor, kind, attributes, Representation::None(),
9890 HeapType::None(isolate), FORCE_FIELD);
9891 return new_map;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009892}
9893
9894
9895Handle<Map> Map::TransitionToAccessorProperty(Handle<Map> map,
9896 Handle<Name> name,
9897 AccessorComponent component,
9898 Handle<Object> accessor,
9899 PropertyAttributes attributes) {
9900 Isolate* isolate = name->GetIsolate();
9901
9902 // Dictionary maps can always have additional data properties.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00009903 if (map->is_dictionary_map()) return map;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009904
9905 // Migrate to the newest map before transitioning to the new property.
9906 map = Update(map);
9907
9908 PropertyNormalizationMode mode = map->is_prototype_map()
9909 ? KEEP_INOBJECT_PROPERTIES
9910 : CLEAR_INOBJECT_PROPERTIES;
9911
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00009912 Map* maybe_transition =
9913 TransitionArray::SearchTransition(*map, kAccessor, *name, attributes);
9914 if (maybe_transition != NULL) {
9915 Handle<Map> transition(maybe_transition, isolate);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009916 DescriptorArray* descriptors = transition->instance_descriptors();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009917 int descriptor = transition->LastAdded();
Emily Bernierd0a1eb72015-03-24 16:35:39 -04009918 DCHECK(descriptors->GetKey(descriptor)->Equals(*name));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009919
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00009920 DCHECK_EQ(kAccessor, descriptors->GetDetails(descriptor).kind());
Emily Bernierd0a1eb72015-03-24 16:35:39 -04009921 DCHECK_EQ(attributes, descriptors->GetDetails(descriptor).attributes());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009922
9923 Handle<Object> maybe_pair(descriptors->GetValue(descriptor), isolate);
9924 if (!maybe_pair->IsAccessorPair()) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -04009925 return Map::Normalize(map, mode, "TransitionToAccessorFromNonPair");
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009926 }
9927
9928 Handle<AccessorPair> pair = Handle<AccessorPair>::cast(maybe_pair);
9929 if (pair->get(component) != *accessor) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -04009930 return Map::Normalize(map, mode, "TransitionToDifferentAccessor");
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009931 }
9932
9933 return transition;
9934 }
9935
9936 Handle<AccessorPair> pair;
9937 DescriptorArray* old_descriptors = map->instance_descriptors();
9938 int descriptor = old_descriptors->SearchWithCache(*name, *map);
9939 if (descriptor != DescriptorArray::kNotFound) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -04009940 if (descriptor != map->LastAdded()) {
9941 return Map::Normalize(map, mode, "AccessorsOverwritingNonLast");
9942 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009943 PropertyDetails old_details = old_descriptors->GetDetails(descriptor);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00009944 if (old_details.type() != ACCESSOR_CONSTANT) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -04009945 return Map::Normalize(map, mode, "AccessorsOverwritingNonAccessors");
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009946 }
9947
9948 if (old_details.attributes() != attributes) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -04009949 return Map::Normalize(map, mode, "AccessorsWithAttributes");
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009950 }
9951
9952 Handle<Object> maybe_pair(old_descriptors->GetValue(descriptor), isolate);
9953 if (!maybe_pair->IsAccessorPair()) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -04009954 return Map::Normalize(map, mode, "AccessorsOverwritingNonPair");
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009955 }
9956
9957 Object* current = Handle<AccessorPair>::cast(maybe_pair)->get(component);
9958 if (current == *accessor) return map;
9959
9960 if (!current->IsTheHole()) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -04009961 return Map::Normalize(map, mode, "AccessorsOverwritingAccessors");
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009962 }
9963
9964 pair = AccessorPair::Copy(Handle<AccessorPair>::cast(maybe_pair));
9965 } else if (map->NumberOfOwnDescriptors() >= kMaxNumberOfDescriptors ||
9966 map->TooManyFastProperties(CERTAINLY_NOT_STORE_FROM_KEYED)) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -04009967 return Map::Normalize(map, CLEAR_INOBJECT_PROPERTIES, "TooManyAccessors");
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009968 } else {
9969 pair = isolate->factory()->NewAccessorPair();
9970 }
9971
9972 pair->set(component, *accessor);
9973 TransitionFlag flag = INSERT_TRANSITION;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00009974 AccessorConstantDescriptor new_desc(name, pair, attributes);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009975 return Map::CopyInsertDescriptor(map, &new_desc, flag);
9976}
9977
9978
9979Handle<Map> Map::CopyAddDescriptor(Handle<Map> map,
9980 Descriptor* descriptor,
9981 TransitionFlag flag) {
9982 Handle<DescriptorArray> descriptors(map->instance_descriptors());
9983
9984 // Ensure the key is unique.
9985 descriptor->KeyToUniqueName();
9986
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00009987 // Share descriptors only if map owns descriptors and it not an initial map.
9988 if (flag == INSERT_TRANSITION && map->owns_descriptors() &&
9989 !map->GetBackPointer()->IsUndefined() &&
9990 TransitionArray::CanHaveMoreTransitions(map)) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009991 return ShareDescriptor(map, descriptors, descriptor);
9992 }
9993
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00009994 int nof = map->NumberOfOwnDescriptors();
9995 Handle<DescriptorArray> new_descriptors =
9996 DescriptorArray::CopyUpTo(descriptors, nof, 1);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009997 new_descriptors->Append(descriptor);
9998
Emily Bernierd0a1eb72015-03-24 16:35:39 -04009999 Handle<LayoutDescriptor> new_layout_descriptor =
10000 FLAG_unbox_double_fields
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000010001 ? LayoutDescriptor::New(map, new_descriptors, nof + 1)
Emily Bernierd0a1eb72015-03-24 16:35:39 -040010002 : handle(LayoutDescriptor::FastPointerLayout(), map->GetIsolate());
10003
10004 return CopyReplaceDescriptors(map, new_descriptors, new_layout_descriptor,
10005 flag, descriptor->GetKey(), "CopyAddDescriptor",
10006 SIMPLE_PROPERTY_TRANSITION);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010007}
10008
10009
10010Handle<Map> Map::CopyInsertDescriptor(Handle<Map> map,
10011 Descriptor* descriptor,
10012 TransitionFlag flag) {
10013 Handle<DescriptorArray> old_descriptors(map->instance_descriptors());
10014
10015 // Ensure the key is unique.
10016 descriptor->KeyToUniqueName();
10017
10018 // We replace the key if it is already present.
10019 int index = old_descriptors->SearchWithCache(*descriptor->GetKey(), *map);
10020 if (index != DescriptorArray::kNotFound) {
10021 return CopyReplaceDescriptor(map, old_descriptors, descriptor, index, flag);
10022 }
10023 return CopyAddDescriptor(map, descriptor, flag);
10024}
10025
10026
10027Handle<DescriptorArray> DescriptorArray::CopyUpTo(
10028 Handle<DescriptorArray> desc,
10029 int enumeration_index,
10030 int slack) {
10031 return DescriptorArray::CopyUpToAddAttributes(
10032 desc, enumeration_index, NONE, slack);
10033}
10034
10035
10036Handle<DescriptorArray> DescriptorArray::CopyUpToAddAttributes(
10037 Handle<DescriptorArray> desc,
10038 int enumeration_index,
10039 PropertyAttributes attributes,
10040 int slack) {
10041 if (enumeration_index + slack == 0) {
10042 return desc->GetIsolate()->factory()->empty_descriptor_array();
10043 }
10044
10045 int size = enumeration_index;
10046
10047 Handle<DescriptorArray> descriptors =
10048 DescriptorArray::Allocate(desc->GetIsolate(), size, slack);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010049
10050 if (attributes != NONE) {
10051 for (int i = 0; i < size; ++i) {
10052 Object* value = desc->GetValue(i);
10053 Name* key = desc->GetKey(i);
10054 PropertyDetails details = desc->GetDetails(i);
10055 // Bulk attribute changes never affect private properties.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000010056 if (!key->IsPrivate()) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010057 int mask = DONT_DELETE | DONT_ENUM;
10058 // READ_ONLY is an invalid attribute for JS setters/getters.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000010059 if (details.type() != ACCESSOR_CONSTANT || !value->IsAccessorPair()) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010060 mask |= READ_ONLY;
10061 }
10062 details = details.CopyAddAttributes(
10063 static_cast<PropertyAttributes>(attributes & mask));
10064 }
10065 Descriptor inner_desc(
10066 handle(key), handle(value, desc->GetIsolate()), details);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000010067 descriptors->SetDescriptor(i, &inner_desc);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010068 }
10069 } else {
10070 for (int i = 0; i < size; ++i) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000010071 descriptors->CopyFrom(i, *desc);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010072 }
10073 }
10074
10075 if (desc->number_of_descriptors() != enumeration_index) descriptors->Sort();
10076
10077 return descriptors;
10078}
10079
10080
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000010081bool DescriptorArray::IsEqualUpTo(DescriptorArray* desc, int nof_descriptors) {
10082 for (int i = 0; i < nof_descriptors; i++) {
10083 if (GetKey(i) != desc->GetKey(i) || GetValue(i) != desc->GetValue(i)) {
10084 return false;
10085 }
10086 PropertyDetails details = GetDetails(i);
10087 PropertyDetails other_details = desc->GetDetails(i);
10088 if (details.type() != other_details.type() ||
10089 !details.representation().Equals(other_details.representation())) {
10090 return false;
10091 }
10092 }
10093 return true;
10094}
10095
10096
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010097Handle<Map> Map::CopyReplaceDescriptor(Handle<Map> map,
10098 Handle<DescriptorArray> descriptors,
10099 Descriptor* descriptor,
10100 int insertion_index,
10101 TransitionFlag flag) {
10102 // Ensure the key is unique.
10103 descriptor->KeyToUniqueName();
10104
10105 Handle<Name> key = descriptor->GetKey();
10106 DCHECK(*key == descriptors->GetKey(insertion_index));
10107
10108 Handle<DescriptorArray> new_descriptors = DescriptorArray::CopyUpTo(
10109 descriptors, map->NumberOfOwnDescriptors());
10110
10111 new_descriptors->Replace(insertion_index, descriptor);
Emily Bernierd0a1eb72015-03-24 16:35:39 -040010112 Handle<LayoutDescriptor> new_layout_descriptor = LayoutDescriptor::New(
10113 map, new_descriptors, new_descriptors->number_of_descriptors());
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010114
10115 SimpleTransitionFlag simple_flag =
10116 (insertion_index == descriptors->number_of_descriptors() - 1)
Emily Bernierd0a1eb72015-03-24 16:35:39 -040010117 ? SIMPLE_PROPERTY_TRANSITION
10118 : PROPERTY_TRANSITION;
10119 return CopyReplaceDescriptors(map, new_descriptors, new_layout_descriptor,
10120 flag, key, "CopyReplaceDescriptor",
10121 simple_flag);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010122}
10123
10124
10125void Map::UpdateCodeCache(Handle<Map> map,
10126 Handle<Name> name,
10127 Handle<Code> code) {
10128 Isolate* isolate = map->GetIsolate();
10129 HandleScope scope(isolate);
10130 // Allocate the code cache if not present.
10131 if (map->code_cache()->IsFixedArray()) {
10132 Handle<Object> result = isolate->factory()->NewCodeCache();
10133 map->set_code_cache(*result);
Steve Block6ded16b2010-05-10 14:33:55 +010010134 }
Steve Blocka7e24c12009-10-30 11:49:00 +000010135
Steve Block6ded16b2010-05-10 14:33:55 +010010136 // Update the code cache.
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010137 Handle<CodeCache> code_cache(CodeCache::cast(map->code_cache()), isolate);
10138 CodeCache::Update(code_cache, name, code);
Steve Block6ded16b2010-05-10 14:33:55 +010010139}
10140
10141
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010142Object* Map::FindInCodeCache(Name* name, Code::Flags flags) {
Steve Block6ded16b2010-05-10 14:33:55 +010010143 // Do a lookup if a code cache exists.
10144 if (!code_cache()->IsFixedArray()) {
10145 return CodeCache::cast(code_cache())->Lookup(name, flags);
10146 } else {
Steve Block44f0eee2011-05-26 01:26:41 +010010147 return GetHeap()->undefined_value();
Steve Block6ded16b2010-05-10 14:33:55 +010010148 }
10149}
10150
10151
10152int Map::IndexInCodeCache(Object* name, Code* code) {
10153 // Get the internal index if a code cache exists.
10154 if (!code_cache()->IsFixedArray()) {
10155 return CodeCache::cast(code_cache())->GetIndex(name, code);
10156 }
10157 return -1;
10158}
10159
10160
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010161void Map::RemoveFromCodeCache(Name* name, Code* code, int index) {
Steve Block6ded16b2010-05-10 14:33:55 +010010162 // No GC is supposed to happen between a call to IndexInCodeCache and
10163 // RemoveFromCodeCache so the code cache must be there.
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010164 DCHECK(!code_cache()->IsFixedArray());
Steve Block6ded16b2010-05-10 14:33:55 +010010165 CodeCache::cast(code_cache())->RemoveByIndex(name, code, index);
10166}
10167
10168
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010169void CodeCache::Update(
10170 Handle<CodeCache> code_cache, Handle<Name> name, Handle<Code> code) {
Steve Block6ded16b2010-05-10 14:33:55 +010010171 // The number of monomorphic stubs for normal load/store/call IC's can grow to
10172 // a large number and therefore they need to go into a hash table. They are
10173 // used to load global properties from cells.
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010174 if (code->type() == Code::NORMAL) {
Steve Block6ded16b2010-05-10 14:33:55 +010010175 // Make sure that a hash table is allocated for the normal load code cache.
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010176 if (code_cache->normal_type_cache()->IsUndefined()) {
10177 Handle<Object> result =
10178 CodeCacheHashTable::New(code_cache->GetIsolate(),
10179 CodeCacheHashTable::kInitialSize);
10180 code_cache->set_normal_type_cache(*result);
Steve Block6ded16b2010-05-10 14:33:55 +010010181 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010182 UpdateNormalTypeCache(code_cache, name, code);
Steve Block6ded16b2010-05-10 14:33:55 +010010183 } else {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010184 DCHECK(code_cache->default_cache()->IsFixedArray());
10185 UpdateDefaultCache(code_cache, name, code);
Steve Block6ded16b2010-05-10 14:33:55 +010010186 }
10187}
10188
10189
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010190void CodeCache::UpdateDefaultCache(
10191 Handle<CodeCache> code_cache, Handle<Name> name, Handle<Code> code) {
Steve Block6ded16b2010-05-10 14:33:55 +010010192 // When updating the default code cache we disregard the type encoded in the
Steve Blocka7e24c12009-10-30 11:49:00 +000010193 // flags. This allows call constant stubs to overwrite call field
10194 // stubs, etc.
10195 Code::Flags flags = Code::RemoveTypeFromFlags(code->flags());
10196
10197 // First check whether we can update existing code cache without
10198 // extending it.
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010199 Handle<FixedArray> cache = handle(code_cache->default_cache());
Steve Blocka7e24c12009-10-30 11:49:00 +000010200 int length = cache->length();
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010201 {
10202 DisallowHeapAllocation no_alloc;
10203 int deleted_index = -1;
10204 for (int i = 0; i < length; i += kCodeCacheEntrySize) {
10205 Object* key = cache->get(i);
10206 if (key->IsNull()) {
10207 if (deleted_index < 0) deleted_index = i;
10208 continue;
10209 }
10210 if (key->IsUndefined()) {
10211 if (deleted_index >= 0) i = deleted_index;
10212 cache->set(i + kCodeCacheEntryNameOffset, *name);
10213 cache->set(i + kCodeCacheEntryCodeOffset, *code);
10214 return;
10215 }
10216 if (name->Equals(Name::cast(key))) {
10217 Code::Flags found =
10218 Code::cast(cache->get(i + kCodeCacheEntryCodeOffset))->flags();
10219 if (Code::RemoveTypeFromFlags(found) == flags) {
10220 cache->set(i + kCodeCacheEntryCodeOffset, *code);
10221 return;
10222 }
Steve Blocka7e24c12009-10-30 11:49:00 +000010223 }
10224 }
Steve Blocka7e24c12009-10-30 11:49:00 +000010225
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010226 // Reached the end of the code cache. If there were deleted
10227 // elements, reuse the space for the first of them.
10228 if (deleted_index >= 0) {
10229 cache->set(deleted_index + kCodeCacheEntryNameOffset, *name);
10230 cache->set(deleted_index + kCodeCacheEntryCodeOffset, *code);
10231 return;
10232 }
Steve Blocka7e24c12009-10-30 11:49:00 +000010233 }
10234
Steve Block6ded16b2010-05-10 14:33:55 +010010235 // Extend the code cache with some new entries (at least one). Must be a
10236 // multiple of the entry size.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000010237 Isolate* isolate = cache->GetIsolate();
10238 int new_length = length + (length >> 1) + kCodeCacheEntrySize;
Steve Block6ded16b2010-05-10 14:33:55 +010010239 new_length = new_length - new_length % kCodeCacheEntrySize;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010240 DCHECK((new_length % kCodeCacheEntrySize) == 0);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000010241 cache = isolate->factory()->CopyFixedArrayAndGrow(cache, new_length - length);
Steve Blocka7e24c12009-10-30 11:49:00 +000010242
10243 // Add the (name, code) pair to the new cache.
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010244 cache->set(length + kCodeCacheEntryNameOffset, *name);
10245 cache->set(length + kCodeCacheEntryCodeOffset, *code);
10246 code_cache->set_default_cache(*cache);
Steve Blocka7e24c12009-10-30 11:49:00 +000010247}
10248
10249
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010250void CodeCache::UpdateNormalTypeCache(
10251 Handle<CodeCache> code_cache, Handle<Name> name, Handle<Code> code) {
Steve Block6ded16b2010-05-10 14:33:55 +010010252 // Adding a new entry can cause a new cache to be allocated.
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010253 Handle<CodeCacheHashTable> cache(
10254 CodeCacheHashTable::cast(code_cache->normal_type_cache()));
10255 Handle<Object> new_cache = CodeCacheHashTable::Put(cache, name, code);
10256 code_cache->set_normal_type_cache(*new_cache);
Steve Block6ded16b2010-05-10 14:33:55 +010010257}
10258
10259
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010260Object* CodeCache::Lookup(Name* name, Code::Flags flags) {
10261 Object* result = LookupDefaultCache(name, Code::RemoveTypeFromFlags(flags));
10262 if (result->IsCode()) {
10263 if (Code::cast(result)->flags() == flags) return result;
10264 return GetHeap()->undefined_value();
Steve Block6ded16b2010-05-10 14:33:55 +010010265 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010266 return LookupNormalTypeCache(name, flags);
Steve Block6ded16b2010-05-10 14:33:55 +010010267}
10268
10269
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010270Object* CodeCache::LookupDefaultCache(Name* name, Code::Flags flags) {
Steve Block6ded16b2010-05-10 14:33:55 +010010271 FixedArray* cache = default_cache();
Steve Blocka7e24c12009-10-30 11:49:00 +000010272 int length = cache->length();
Steve Block6ded16b2010-05-10 14:33:55 +010010273 for (int i = 0; i < length; i += kCodeCacheEntrySize) {
10274 Object* key = cache->get(i + kCodeCacheEntryNameOffset);
Steve Blocka7e24c12009-10-30 11:49:00 +000010275 // Skip deleted elements.
10276 if (key->IsNull()) continue;
10277 if (key->IsUndefined()) return key;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010278 if (name->Equals(Name::cast(key))) {
Steve Block6ded16b2010-05-10 14:33:55 +010010279 Code* code = Code::cast(cache->get(i + kCodeCacheEntryCodeOffset));
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010280 if (Code::RemoveTypeFromFlags(code->flags()) == flags) {
Steve Block6ded16b2010-05-10 14:33:55 +010010281 return code;
10282 }
Steve Blocka7e24c12009-10-30 11:49:00 +000010283 }
10284 }
Ben Murdoch8b112d22011-06-08 16:22:53 +010010285 return GetHeap()->undefined_value();
Steve Blocka7e24c12009-10-30 11:49:00 +000010286}
10287
10288
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010289Object* CodeCache::LookupNormalTypeCache(Name* name, Code::Flags flags) {
Steve Block6ded16b2010-05-10 14:33:55 +010010290 if (!normal_type_cache()->IsUndefined()) {
10291 CodeCacheHashTable* cache = CodeCacheHashTable::cast(normal_type_cache());
10292 return cache->Lookup(name, flags);
10293 } else {
Steve Block44f0eee2011-05-26 01:26:41 +010010294 return GetHeap()->undefined_value();
Steve Block6ded16b2010-05-10 14:33:55 +010010295 }
10296}
10297
10298
10299int CodeCache::GetIndex(Object* name, Code* code) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010300 if (code->type() == Code::NORMAL) {
Steve Block6ded16b2010-05-10 14:33:55 +010010301 if (normal_type_cache()->IsUndefined()) return -1;
10302 CodeCacheHashTable* cache = CodeCacheHashTable::cast(normal_type_cache());
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010303 return cache->GetIndex(Name::cast(name), code->flags());
Steve Block6ded16b2010-05-10 14:33:55 +010010304 }
10305
10306 FixedArray* array = default_cache();
Steve Blocka7e24c12009-10-30 11:49:00 +000010307 int len = array->length();
Steve Block6ded16b2010-05-10 14:33:55 +010010308 for (int i = 0; i < len; i += kCodeCacheEntrySize) {
10309 if (array->get(i + kCodeCacheEntryCodeOffset) == code) return i + 1;
Steve Blocka7e24c12009-10-30 11:49:00 +000010310 }
10311 return -1;
10312}
10313
10314
Steve Block6ded16b2010-05-10 14:33:55 +010010315void CodeCache::RemoveByIndex(Object* name, Code* code, int index) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010316 if (code->type() == Code::NORMAL) {
10317 DCHECK(!normal_type_cache()->IsUndefined());
Steve Block6ded16b2010-05-10 14:33:55 +010010318 CodeCacheHashTable* cache = CodeCacheHashTable::cast(normal_type_cache());
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010319 DCHECK(cache->GetIndex(Name::cast(name), code->flags()) == index);
Steve Block6ded16b2010-05-10 14:33:55 +010010320 cache->RemoveByIndex(index);
10321 } else {
10322 FixedArray* array = default_cache();
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010323 DCHECK(array->length() >= index && array->get(index)->IsCode());
Steve Block6ded16b2010-05-10 14:33:55 +010010324 // Use null instead of undefined for deleted elements to distinguish
10325 // deleted elements from unused elements. This distinction is used
10326 // when looking up in the cache and when updating the cache.
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010327 DCHECK_EQ(1, kCodeCacheEntryCodeOffset - kCodeCacheEntryNameOffset);
Steve Block6ded16b2010-05-10 14:33:55 +010010328 array->set_null(index - 1); // Name.
10329 array->set_null(index); // Code.
10330 }
10331}
10332
10333
10334// The key in the code cache hash table consists of the property name and the
10335// code object. The actual match is on the name and the code flags. If a key
10336// is created using the flags and not a code object it can only be used for
10337// lookup not to create a new entry.
10338class CodeCacheHashTableKey : public HashTableKey {
10339 public:
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010340 CodeCacheHashTableKey(Handle<Name> name, Code::Flags flags)
10341 : name_(name), flags_(flags), code_() { }
Steve Block6ded16b2010-05-10 14:33:55 +010010342
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010343 CodeCacheHashTableKey(Handle<Name> name, Handle<Code> code)
10344 : name_(name), flags_(code->flags()), code_(code) { }
Steve Block6ded16b2010-05-10 14:33:55 +010010345
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000010346 bool IsMatch(Object* other) override {
Steve Block6ded16b2010-05-10 14:33:55 +010010347 if (!other->IsFixedArray()) return false;
10348 FixedArray* pair = FixedArray::cast(other);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010349 Name* name = Name::cast(pair->get(0));
Steve Block6ded16b2010-05-10 14:33:55 +010010350 Code::Flags flags = Code::cast(pair->get(1))->flags();
10351 if (flags != flags_) {
10352 return false;
10353 }
10354 return name_->Equals(name);
10355 }
10356
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010357 static uint32_t NameFlagsHashHelper(Name* name, Code::Flags flags) {
Steve Block6ded16b2010-05-10 14:33:55 +010010358 return name->Hash() ^ flags;
10359 }
10360
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000010361 uint32_t Hash() override { return NameFlagsHashHelper(*name_, flags_); }
Steve Block6ded16b2010-05-10 14:33:55 +010010362
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000010363 uint32_t HashForObject(Object* obj) override {
Steve Block6ded16b2010-05-10 14:33:55 +010010364 FixedArray* pair = FixedArray::cast(obj);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010365 Name* name = Name::cast(pair->get(0));
Steve Block6ded16b2010-05-10 14:33:55 +010010366 Code* code = Code::cast(pair->get(1));
10367 return NameFlagsHashHelper(name, code->flags());
10368 }
10369
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000010370 MUST_USE_RESULT Handle<Object> AsHandle(Isolate* isolate) override {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010371 Handle<Code> code = code_.ToHandleChecked();
10372 Handle<FixedArray> pair = isolate->factory()->NewFixedArray(2);
10373 pair->set(0, *name_);
10374 pair->set(1, *code);
Steve Block6ded16b2010-05-10 14:33:55 +010010375 return pair;
10376 }
10377
10378 private:
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010379 Handle<Name> name_;
Steve Block6ded16b2010-05-10 14:33:55 +010010380 Code::Flags flags_;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000010381 // TODO(jkummerow): We should be able to get by without this.
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010382 MaybeHandle<Code> code_;
Steve Block6ded16b2010-05-10 14:33:55 +010010383};
10384
10385
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010386Object* CodeCacheHashTable::Lookup(Name* name, Code::Flags flags) {
10387 DisallowHeapAllocation no_alloc;
10388 CodeCacheHashTableKey key(handle(name), flags);
Steve Block6ded16b2010-05-10 14:33:55 +010010389 int entry = FindEntry(&key);
Steve Block44f0eee2011-05-26 01:26:41 +010010390 if (entry == kNotFound) return GetHeap()->undefined_value();
Steve Block6ded16b2010-05-10 14:33:55 +010010391 return get(EntryToIndex(entry) + 1);
10392}
10393
10394
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010395Handle<CodeCacheHashTable> CodeCacheHashTable::Put(
10396 Handle<CodeCacheHashTable> cache, Handle<Name> name, Handle<Code> code) {
Steve Block6ded16b2010-05-10 14:33:55 +010010397 CodeCacheHashTableKey key(name, code);
Steve Block6ded16b2010-05-10 14:33:55 +010010398
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010399 Handle<CodeCacheHashTable> new_cache = EnsureCapacity(cache, 1, &key);
Steve Block6ded16b2010-05-10 14:33:55 +010010400
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010401 int entry = new_cache->FindInsertionEntry(key.Hash());
10402 Handle<Object> k = key.AsHandle(cache->GetIsolate());
Steve Block6ded16b2010-05-10 14:33:55 +010010403
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010404 new_cache->set(EntryToIndex(entry), *k);
10405 new_cache->set(EntryToIndex(entry) + 1, *code);
10406 new_cache->ElementAdded();
10407 return new_cache;
Steve Block6ded16b2010-05-10 14:33:55 +010010408}
10409
10410
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010411int CodeCacheHashTable::GetIndex(Name* name, Code::Flags flags) {
10412 DisallowHeapAllocation no_alloc;
10413 CodeCacheHashTableKey key(handle(name), flags);
Steve Block6ded16b2010-05-10 14:33:55 +010010414 int entry = FindEntry(&key);
10415 return (entry == kNotFound) ? -1 : entry;
10416}
10417
10418
10419void CodeCacheHashTable::RemoveByIndex(int index) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010420 DCHECK(index >= 0);
Steve Block44f0eee2011-05-26 01:26:41 +010010421 Heap* heap = GetHeap();
Ben Murdoch3ef787d2012-04-12 10:51:47 +010010422 set(EntryToIndex(index), heap->the_hole_value());
10423 set(EntryToIndex(index) + 1, heap->the_hole_value());
Steve Block6ded16b2010-05-10 14:33:55 +010010424 ElementRemoved();
Steve Blocka7e24c12009-10-30 11:49:00 +000010425}
10426
10427
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010428void PolymorphicCodeCache::Update(Handle<PolymorphicCodeCache> code_cache,
Ben Murdoch3ef787d2012-04-12 10:51:47 +010010429 MapHandleList* maps,
10430 Code::Flags flags,
10431 Handle<Code> code) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010432 Isolate* isolate = code_cache->GetIsolate();
10433 if (code_cache->cache()->IsUndefined()) {
10434 Handle<PolymorphicCodeCacheHashTable> result =
10435 PolymorphicCodeCacheHashTable::New(
10436 isolate,
10437 PolymorphicCodeCacheHashTable::kInitialSize);
10438 code_cache->set_cache(*result);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000010439 } else {
10440 // This entry shouldn't be contained in the cache yet.
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010441 DCHECK(PolymorphicCodeCacheHashTable::cast(code_cache->cache())
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000010442 ->Lookup(maps, flags)->IsUndefined());
10443 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010444 Handle<PolymorphicCodeCacheHashTable> hash_table =
10445 handle(PolymorphicCodeCacheHashTable::cast(code_cache->cache()));
10446 Handle<PolymorphicCodeCacheHashTable> new_cache =
10447 PolymorphicCodeCacheHashTable::Put(hash_table, maps, flags, code);
10448 code_cache->set_cache(*new_cache);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000010449}
10450
10451
Ben Murdoch3ef787d2012-04-12 10:51:47 +010010452Handle<Object> PolymorphicCodeCache::Lookup(MapHandleList* maps,
10453 Code::Flags flags) {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000010454 if (!cache()->IsUndefined()) {
10455 PolymorphicCodeCacheHashTable* hash_table =
10456 PolymorphicCodeCacheHashTable::cast(cache());
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010457 return Handle<Object>(hash_table->Lookup(maps, flags), GetIsolate());
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000010458 } else {
Ben Murdoch3ef787d2012-04-12 10:51:47 +010010459 return GetIsolate()->factory()->undefined_value();
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000010460 }
10461}
10462
10463
10464// Despite their name, object of this class are not stored in the actual
10465// hash table; instead they're temporarily used for lookups. It is therefore
10466// safe to have a weak (non-owning) pointer to a MapList as a member field.
10467class PolymorphicCodeCacheHashTableKey : public HashTableKey {
10468 public:
10469 // Callers must ensure that |maps| outlives the newly constructed object.
Ben Murdoch3ef787d2012-04-12 10:51:47 +010010470 PolymorphicCodeCacheHashTableKey(MapHandleList* maps, int code_flags)
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000010471 : maps_(maps),
10472 code_flags_(code_flags) {}
10473
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000010474 bool IsMatch(Object* other) override {
Ben Murdoch3ef787d2012-04-12 10:51:47 +010010475 MapHandleList other_maps(kDefaultListAllocationSize);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000010476 int other_flags;
10477 FromObject(other, &other_flags, &other_maps);
10478 if (code_flags_ != other_flags) return false;
10479 if (maps_->length() != other_maps.length()) return false;
10480 // Compare just the hashes first because it's faster.
10481 int this_hash = MapsHashHelper(maps_, code_flags_);
10482 int other_hash = MapsHashHelper(&other_maps, other_flags);
10483 if (this_hash != other_hash) return false;
10484
10485 // Full comparison: for each map in maps_, look for an equivalent map in
10486 // other_maps. This implementation is slow, but probably good enough for
10487 // now because the lists are short (<= 4 elements currently).
10488 for (int i = 0; i < maps_->length(); ++i) {
10489 bool match_found = false;
10490 for (int j = 0; j < other_maps.length(); ++j) {
Ben Murdoch3ef787d2012-04-12 10:51:47 +010010491 if (*(maps_->at(i)) == *(other_maps.at(j))) {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000010492 match_found = true;
10493 break;
10494 }
10495 }
10496 if (!match_found) return false;
10497 }
10498 return true;
10499 }
10500
Ben Murdoch3ef787d2012-04-12 10:51:47 +010010501 static uint32_t MapsHashHelper(MapHandleList* maps, int code_flags) {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000010502 uint32_t hash = code_flags;
10503 for (int i = 0; i < maps->length(); ++i) {
10504 hash ^= maps->at(i)->Hash();
10505 }
10506 return hash;
10507 }
10508
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000010509 uint32_t Hash() override { return MapsHashHelper(maps_, code_flags_); }
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000010510
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000010511 uint32_t HashForObject(Object* obj) override {
Ben Murdoch3ef787d2012-04-12 10:51:47 +010010512 MapHandleList other_maps(kDefaultListAllocationSize);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000010513 int other_flags;
10514 FromObject(obj, &other_flags, &other_maps);
10515 return MapsHashHelper(&other_maps, other_flags);
10516 }
10517
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000010518 MUST_USE_RESULT Handle<Object> AsHandle(Isolate* isolate) override {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000010519 // The maps in |maps_| must be copied to a newly allocated FixedArray,
10520 // both because the referenced MapList is short-lived, and because C++
10521 // objects can't be stored in the heap anyway.
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010522 Handle<FixedArray> list =
10523 isolate->factory()->NewUninitializedFixedArray(maps_->length() + 1);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000010524 list->set(0, Smi::FromInt(code_flags_));
10525 for (int i = 0; i < maps_->length(); ++i) {
Ben Murdoch3ef787d2012-04-12 10:51:47 +010010526 list->set(i + 1, *maps_->at(i));
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000010527 }
10528 return list;
10529 }
10530
10531 private:
Ben Murdoch3ef787d2012-04-12 10:51:47 +010010532 static MapHandleList* FromObject(Object* obj,
10533 int* code_flags,
10534 MapHandleList* maps) {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000010535 FixedArray* list = FixedArray::cast(obj);
10536 maps->Rewind(0);
10537 *code_flags = Smi::cast(list->get(0))->value();
10538 for (int i = 1; i < list->length(); ++i) {
Ben Murdoch3ef787d2012-04-12 10:51:47 +010010539 maps->Add(Handle<Map>(Map::cast(list->get(i))));
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000010540 }
10541 return maps;
10542 }
10543
Ben Murdoch3ef787d2012-04-12 10:51:47 +010010544 MapHandleList* maps_; // weak.
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000010545 int code_flags_;
10546 static const int kDefaultListAllocationSize = kMaxKeyedPolymorphism + 1;
10547};
10548
10549
Ben Murdoch3ef787d2012-04-12 10:51:47 +010010550Object* PolymorphicCodeCacheHashTable::Lookup(MapHandleList* maps,
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010551 int code_kind) {
10552 DisallowHeapAllocation no_alloc;
10553 PolymorphicCodeCacheHashTableKey key(maps, code_kind);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000010554 int entry = FindEntry(&key);
10555 if (entry == kNotFound) return GetHeap()->undefined_value();
10556 return get(EntryToIndex(entry) + 1);
10557}
10558
10559
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010560Handle<PolymorphicCodeCacheHashTable> PolymorphicCodeCacheHashTable::Put(
10561 Handle<PolymorphicCodeCacheHashTable> hash_table,
10562 MapHandleList* maps,
10563 int code_kind,
10564 Handle<Code> code) {
10565 PolymorphicCodeCacheHashTableKey key(maps, code_kind);
10566 Handle<PolymorphicCodeCacheHashTable> cache =
10567 EnsureCapacity(hash_table, 1, &key);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000010568 int entry = cache->FindInsertionEntry(key.Hash());
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010569
10570 Handle<Object> obj = key.AsHandle(hash_table->GetIsolate());
10571 cache->set(EntryToIndex(entry), *obj);
10572 cache->set(EntryToIndex(entry) + 1, *code);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000010573 cache->ElementAdded();
10574 return cache;
10575}
10576
10577
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010578void FixedArray::Shrink(int new_length) {
10579 DCHECK(0 <= new_length && new_length <= length());
10580 if (new_length < length()) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000010581 GetHeap()->RightTrimFixedArray<Heap::CONCURRENT_TO_SWEEPER>(
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010582 this, length() - new_length);
10583 }
10584}
10585
10586
Steve Blocka7e24c12009-10-30 11:49:00 +000010587void FixedArray::CopyTo(int pos, FixedArray* dest, int dest_pos, int len) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010588 DisallowHeapAllocation no_gc;
Leon Clarke4515c472010-02-03 11:58:03 +000010589 WriteBarrierMode mode = dest->GetWriteBarrierMode(no_gc);
Steve Blocka7e24c12009-10-30 11:49:00 +000010590 for (int index = 0; index < len; index++) {
10591 dest->set(dest_pos+index, get(pos+index), mode);
10592 }
10593}
10594
10595
10596#ifdef DEBUG
10597bool FixedArray::IsEqualTo(FixedArray* other) {
10598 if (length() != other->length()) return false;
10599 for (int i = 0 ; i < length(); ++i) {
10600 if (get(i) != other->get(i)) return false;
10601 }
10602 return true;
10603}
10604#endif
10605
10606
Emily Bernierd0a1eb72015-03-24 16:35:39 -040010607// static
10608void WeakFixedArray::Set(Handle<WeakFixedArray> array, int index,
10609 Handle<HeapObject> value) {
10610 DCHECK(array->IsEmptySlot(index)); // Don't overwrite anything.
10611 Handle<WeakCell> cell =
10612 value->IsMap() ? Map::WeakCellForMap(Handle<Map>::cast(value))
10613 : array->GetIsolate()->factory()->NewWeakCell(value);
10614 Handle<FixedArray>::cast(array)->set(index + kFirstIndex, *cell);
10615 if (FLAG_trace_weak_arrays) {
10616 PrintF("[WeakFixedArray: storing at index %d ]\n", index);
10617 }
10618 array->set_last_used_index(index);
10619}
10620
10621
10622// static
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000010623Handle<WeakFixedArray> WeakFixedArray::Add(Handle<Object> maybe_array,
10624 Handle<HeapObject> value,
10625 int* assigned_index) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -040010626 Handle<WeakFixedArray> array =
10627 (maybe_array.is_null() || !maybe_array->IsWeakFixedArray())
10628 ? Allocate(value->GetIsolate(), 1, Handle<WeakFixedArray>::null())
10629 : Handle<WeakFixedArray>::cast(maybe_array);
Emily Bernierd0a1eb72015-03-24 16:35:39 -040010630 // Try to store the new entry if there's room. Optimize for consecutive
10631 // accesses.
10632 int first_index = array->last_used_index();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000010633 int length = array->Length();
10634 if (length > 0) {
10635 for (int i = first_index;;) {
10636 if (array->IsEmptySlot((i))) {
10637 WeakFixedArray::Set(array, i, value);
10638 if (assigned_index != NULL) *assigned_index = i;
10639 return array;
10640 }
10641 if (FLAG_trace_weak_arrays) {
10642 PrintF("[WeakFixedArray: searching for free slot]\n");
10643 }
10644 i = (i + 1) % length;
10645 if (i == first_index) break;
Emily Bernierd0a1eb72015-03-24 16:35:39 -040010646 }
Emily Bernierd0a1eb72015-03-24 16:35:39 -040010647 }
10648
10649 // No usable slot found, grow the array.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000010650 int new_length = length == 0 ? 1 : length + (length >> 1) + 4;
Emily Bernierd0a1eb72015-03-24 16:35:39 -040010651 Handle<WeakFixedArray> new_array =
10652 Allocate(array->GetIsolate(), new_length, array);
10653 if (FLAG_trace_weak_arrays) {
10654 PrintF("[WeakFixedArray: growing to size %d ]\n", new_length);
10655 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000010656 WeakFixedArray::Set(new_array, length, value);
10657 if (assigned_index != NULL) *assigned_index = length;
Emily Bernierd0a1eb72015-03-24 16:35:39 -040010658 return new_array;
10659}
10660
10661
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000010662template <class CompactionCallback>
10663void WeakFixedArray::Compact() {
10664 FixedArray* array = FixedArray::cast(this);
10665 int new_length = kFirstIndex;
10666 for (int i = kFirstIndex; i < array->length(); i++) {
10667 Object* element = array->get(i);
10668 if (element->IsSmi()) continue;
10669 if (WeakCell::cast(element)->cleared()) continue;
10670 Object* value = WeakCell::cast(element)->value();
10671 CompactionCallback::Callback(value, i - kFirstIndex,
10672 new_length - kFirstIndex);
10673 array->set(new_length++, element);
10674 }
10675 array->Shrink(new_length);
10676 set_last_used_index(0);
10677}
10678
10679
10680void WeakFixedArray::Iterator::Reset(Object* maybe_array) {
10681 if (maybe_array->IsWeakFixedArray()) {
10682 list_ = WeakFixedArray::cast(maybe_array);
10683 index_ = 0;
10684#ifdef DEBUG
10685 last_used_index_ = list_->last_used_index();
10686#endif // DEBUG
10687 }
10688}
10689
10690
10691void JSObject::PrototypeRegistryCompactionCallback::Callback(Object* value,
10692 int old_index,
10693 int new_index) {
10694 DCHECK(value->IsMap() && Map::cast(value)->is_prototype_map());
10695 Map* map = Map::cast(value);
10696 DCHECK(map->prototype_info()->IsPrototypeInfo());
10697 PrototypeInfo* proto_info = PrototypeInfo::cast(map->prototype_info());
10698 DCHECK_EQ(old_index, proto_info->registry_slot());
10699 proto_info->set_registry_slot(new_index);
10700}
10701
10702
10703template void WeakFixedArray::Compact<WeakFixedArray::NullCallback>();
10704template void
10705WeakFixedArray::Compact<JSObject::PrototypeRegistryCompactionCallback>();
10706
10707
10708bool WeakFixedArray::Remove(Handle<HeapObject> value) {
10709 if (Length() == 0) return false;
Emily Bernierd0a1eb72015-03-24 16:35:39 -040010710 // Optimize for the most recently added element to be removed again.
10711 int first_index = last_used_index();
10712 for (int i = first_index;;) {
10713 if (Get(i) == *value) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000010714 Clear(i);
10715 // Users of WeakFixedArray should make sure that there are no duplicates.
10716 return true;
Emily Bernierd0a1eb72015-03-24 16:35:39 -040010717 }
10718 i = (i + 1) % Length();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000010719 if (i == first_index) return false;
Emily Bernierd0a1eb72015-03-24 16:35:39 -040010720 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000010721 UNREACHABLE();
Emily Bernierd0a1eb72015-03-24 16:35:39 -040010722}
10723
10724
10725// static
10726Handle<WeakFixedArray> WeakFixedArray::Allocate(
10727 Isolate* isolate, int size, Handle<WeakFixedArray> initialize_from) {
10728 DCHECK(0 <= size);
10729 Handle<FixedArray> result =
10730 isolate->factory()->NewUninitializedFixedArray(size + kFirstIndex);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000010731 int index = 0;
10732 if (!initialize_from.is_null()) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -040010733 DCHECK(initialize_from->Length() <= size);
10734 Handle<FixedArray> raw_source = Handle<FixedArray>::cast(initialize_from);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000010735 // Copy the entries without compacting, since the PrototypeInfo relies on
10736 // the index of the entries not to change.
10737 while (index < raw_source->length()) {
10738 result->set(index, raw_source->get(index));
10739 index++;
Emily Bernierd0a1eb72015-03-24 16:35:39 -040010740 }
10741 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000010742 while (index < result->length()) {
10743 result->set(index, Smi::FromInt(0));
10744 index++;
10745 }
10746 return Handle<WeakFixedArray>::cast(result);
10747}
10748
10749
10750Handle<ArrayList> ArrayList::Add(Handle<ArrayList> array, Handle<Object> obj,
10751 AddMode mode) {
10752 int length = array->Length();
10753 array = EnsureSpace(array, length + 1);
10754 if (mode == kReloadLengthAfterAllocation) {
10755 DCHECK(array->Length() <= length);
10756 length = array->Length();
10757 }
10758 array->Set(length, *obj);
10759 array->SetLength(length + 1);
10760 return array;
10761}
10762
10763
10764Handle<ArrayList> ArrayList::Add(Handle<ArrayList> array, Handle<Object> obj1,
10765 Handle<Object> obj2, AddMode mode) {
10766 int length = array->Length();
10767 array = EnsureSpace(array, length + 2);
10768 if (mode == kReloadLengthAfterAllocation) {
10769 length = array->Length();
10770 }
10771 array->Set(length, *obj1);
10772 array->Set(length + 1, *obj2);
10773 array->SetLength(length + 2);
10774 return array;
10775}
10776
10777
10778bool ArrayList::IsFull() {
10779 int capacity = length();
10780 return kFirstIndex + Length() == capacity;
10781}
10782
10783
10784Handle<ArrayList> ArrayList::EnsureSpace(Handle<ArrayList> array, int length) {
10785 int capacity = array->length();
10786 bool empty = (capacity == 0);
10787 if (capacity < kFirstIndex + length) {
10788 Isolate* isolate = array->GetIsolate();
10789 int new_capacity = kFirstIndex + length;
10790 new_capacity = new_capacity + Max(new_capacity / 2, 2);
10791 int grow_by = new_capacity - capacity;
10792 array = Handle<ArrayList>::cast(
10793 isolate->factory()->CopyFixedArrayAndGrow(array, grow_by));
10794 if (empty) array->SetLength(0);
10795 }
10796 return array;
Emily Bernierd0a1eb72015-03-24 16:35:39 -040010797}
10798
10799
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010800Handle<DescriptorArray> DescriptorArray::Allocate(Isolate* isolate,
10801 int number_of_descriptors,
10802 int slack) {
10803 DCHECK(0 <= number_of_descriptors);
10804 Factory* factory = isolate->factory();
Steve Blocka7e24c12009-10-30 11:49:00 +000010805 // Do not use DescriptorArray::cast on incomplete object.
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010806 int size = number_of_descriptors + slack;
10807 if (size == 0) return factory->empty_descriptor_array();
10808 // Allocate the array of keys.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000010809 Handle<FixedArray> result = factory->NewFixedArray(LengthFor(size), TENURED);
Steve Blocka7e24c12009-10-30 11:49:00 +000010810
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010811 result->set(kDescriptorLengthIndex, Smi::FromInt(number_of_descriptors));
10812 result->set(kEnumCacheIndex, Smi::FromInt(0));
10813 return Handle<DescriptorArray>::cast(result);
10814}
10815
10816
10817void DescriptorArray::ClearEnumCache() {
10818 set(kEnumCacheIndex, Smi::FromInt(0));
10819}
10820
10821
10822void DescriptorArray::Replace(int index, Descriptor* descriptor) {
10823 descriptor->SetSortedKeyIndex(GetSortedKeyIndex(index));
10824 Set(index, descriptor);
Steve Blocka7e24c12009-10-30 11:49:00 +000010825}
10826
10827
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000010828// static
10829void DescriptorArray::SetEnumCache(Handle<DescriptorArray> descriptors,
10830 Isolate* isolate,
10831 Handle<FixedArray> new_cache,
10832 Handle<FixedArray> new_index_cache) {
10833 DCHECK(!descriptors->IsEmpty());
10834 FixedArray* bridge_storage;
10835 bool needs_new_enum_cache = !descriptors->HasEnumCache();
10836 if (needs_new_enum_cache) {
10837 bridge_storage = *isolate->factory()->NewFixedArray(
10838 DescriptorArray::kEnumCacheBridgeLength);
10839 } else {
10840 bridge_storage = FixedArray::cast(descriptors->get(kEnumCacheIndex));
10841 }
10842 bridge_storage->set(kEnumCacheBridgeCacheIndex, *new_cache);
10843 bridge_storage->set(kEnumCacheBridgeIndicesCacheIndex,
10844 new_index_cache.is_null() ? Object::cast(Smi::FromInt(0))
10845 : *new_index_cache);
10846 if (needs_new_enum_cache) {
10847 descriptors->set(kEnumCacheIndex, bridge_storage);
10848 }
Steve Blocka7e24c12009-10-30 11:49:00 +000010849}
10850
10851
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000010852void DescriptorArray::CopyFrom(int index, DescriptorArray* src) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010853 Object* value = src->GetValue(index);
10854 PropertyDetails details = src->GetDetails(index);
10855 Descriptor desc(handle(src->GetKey(index)),
10856 handle(value, src->GetIsolate()),
10857 details);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000010858 SetDescriptor(index, &desc);
Ben Murdoch3ef787d2012-04-12 10:51:47 +010010859}
10860
10861
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010862void DescriptorArray::Sort() {
Steve Blocka7e24c12009-10-30 11:49:00 +000010863 // In-place heap sort.
10864 int len = number_of_descriptors();
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010865 // Reset sorting since the descriptor array might contain invalid pointers.
10866 for (int i = 0; i < len; ++i) SetSortedKey(i, i);
Steve Blocka7e24c12009-10-30 11:49:00 +000010867 // Bottom-up max-heap construction.
Steve Block6ded16b2010-05-10 14:33:55 +010010868 // Index of the last node with children
10869 const int max_parent_index = (len / 2) - 1;
10870 for (int i = max_parent_index; i >= 0; --i) {
10871 int parent_index = i;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010872 const uint32_t parent_hash = GetSortedKey(i)->Hash();
Steve Block6ded16b2010-05-10 14:33:55 +010010873 while (parent_index <= max_parent_index) {
10874 int child_index = 2 * parent_index + 1;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010875 uint32_t child_hash = GetSortedKey(child_index)->Hash();
Steve Block6ded16b2010-05-10 14:33:55 +010010876 if (child_index + 1 < len) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010877 uint32_t right_child_hash = GetSortedKey(child_index + 1)->Hash();
Steve Block6ded16b2010-05-10 14:33:55 +010010878 if (right_child_hash > child_hash) {
10879 child_index++;
10880 child_hash = right_child_hash;
10881 }
Steve Blocka7e24c12009-10-30 11:49:00 +000010882 }
Steve Block6ded16b2010-05-10 14:33:55 +010010883 if (child_hash <= parent_hash) break;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010884 SwapSortedKeys(parent_index, child_index);
Steve Block6ded16b2010-05-10 14:33:55 +010010885 // Now element at child_index could be < its children.
10886 parent_index = child_index; // parent_hash remains correct.
Steve Blocka7e24c12009-10-30 11:49:00 +000010887 }
10888 }
10889
10890 // Extract elements and create sorted array.
10891 for (int i = len - 1; i > 0; --i) {
10892 // Put max element at the back of the array.
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010893 SwapSortedKeys(0, i);
Ben Murdoch3ef787d2012-04-12 10:51:47 +010010894 // Shift down the new top element.
Steve Blocka7e24c12009-10-30 11:49:00 +000010895 int parent_index = 0;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010896 const uint32_t parent_hash = GetSortedKey(parent_index)->Hash();
Steve Block6ded16b2010-05-10 14:33:55 +010010897 const int max_parent_index = (i / 2) - 1;
10898 while (parent_index <= max_parent_index) {
10899 int child_index = parent_index * 2 + 1;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010900 uint32_t child_hash = GetSortedKey(child_index)->Hash();
Steve Block6ded16b2010-05-10 14:33:55 +010010901 if (child_index + 1 < i) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010902 uint32_t right_child_hash = GetSortedKey(child_index + 1)->Hash();
Steve Block6ded16b2010-05-10 14:33:55 +010010903 if (right_child_hash > child_hash) {
10904 child_index++;
10905 child_hash = right_child_hash;
10906 }
Steve Blocka7e24c12009-10-30 11:49:00 +000010907 }
Steve Block6ded16b2010-05-10 14:33:55 +010010908 if (child_hash <= parent_hash) break;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010909 SwapSortedKeys(parent_index, child_index);
Steve Block6ded16b2010-05-10 14:33:55 +010010910 parent_index = child_index;
Steve Blocka7e24c12009-10-30 11:49:00 +000010911 }
10912 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010913 DCHECK(IsSortedNoDuplicates());
Kristian Monsen0d5e1162010-09-30 15:31:59 +010010914}
Steve Blocka7e24c12009-10-30 11:49:00 +000010915
Kristian Monsen0d5e1162010-09-30 15:31:59 +010010916
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010917Handle<AccessorPair> AccessorPair::Copy(Handle<AccessorPair> pair) {
10918 Handle<AccessorPair> copy = pair->GetIsolate()->factory()->NewAccessorPair();
10919 copy->set_getter(pair->getter());
10920 copy->set_setter(pair->setter());
Ben Murdoch3ef787d2012-04-12 10:51:47 +010010921 return copy;
10922}
10923
10924
10925Object* AccessorPair::GetComponent(AccessorComponent component) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010926 Object* accessor = get(component);
10927 return accessor->IsTheHole() ? GetHeap()->undefined_value() : accessor;
Ben Murdoch3ef787d2012-04-12 10:51:47 +010010928}
10929
10930
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010931Handle<DeoptimizationInputData> DeoptimizationInputData::New(
10932 Isolate* isolate, int deopt_entry_count, PretenureFlag pretenure) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010933 return Handle<DeoptimizationInputData>::cast(
10934 isolate->factory()->NewFixedArray(LengthFor(deopt_entry_count),
10935 pretenure));
Ben Murdochb0fe1622011-05-05 13:52:32 +010010936}
10937
10938
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010939Handle<DeoptimizationOutputData> DeoptimizationOutputData::New(
10940 Isolate* isolate,
10941 int number_of_deopt_points,
10942 PretenureFlag pretenure) {
10943 Handle<FixedArray> result;
10944 if (number_of_deopt_points == 0) {
10945 result = isolate->factory()->empty_fixed_array();
10946 } else {
10947 result = isolate->factory()->NewFixedArray(
10948 LengthOfFixedArray(number_of_deopt_points), pretenure);
10949 }
10950 return Handle<DeoptimizationOutputData>::cast(result);
Ben Murdochb0fe1622011-05-05 13:52:32 +010010951}
10952
10953
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000010954// static
10955Handle<LiteralsArray> LiteralsArray::New(Isolate* isolate,
10956 Handle<TypeFeedbackVector> vector,
10957 int number_of_literals,
10958 PretenureFlag pretenure) {
10959 Handle<FixedArray> literals = isolate->factory()->NewFixedArray(
10960 number_of_literals + kFirstLiteralIndex, pretenure);
10961 Handle<LiteralsArray> casted_literals = Handle<LiteralsArray>::cast(literals);
10962 casted_literals->set_feedback_vector(*vector);
10963 return casted_literals;
10964}
10965
10966
10967int HandlerTable::LookupRange(int pc_offset, int* stack_depth_out,
10968 CatchPrediction* prediction_out) {
10969 int innermost_handler = -1, innermost_start = -1;
10970 for (int i = 0; i < length(); i += kRangeEntrySize) {
10971 int start_offset = Smi::cast(get(i + kRangeStartIndex))->value();
10972 int end_offset = Smi::cast(get(i + kRangeEndIndex))->value();
10973 int handler_field = Smi::cast(get(i + kRangeHandlerIndex))->value();
10974 int handler_offset = HandlerOffsetField::decode(handler_field);
10975 CatchPrediction prediction = HandlerPredictionField::decode(handler_field);
10976 int stack_depth = Smi::cast(get(i + kRangeDepthIndex))->value();
10977 if (pc_offset > start_offset && pc_offset <= end_offset) {
10978 DCHECK_NE(start_offset, innermost_start);
10979 if (start_offset < innermost_start) continue;
10980 innermost_handler = handler_offset;
10981 innermost_start = start_offset;
10982 *stack_depth_out = stack_depth;
10983 if (prediction_out) *prediction_out = prediction;
10984 }
10985 }
10986 return innermost_handler;
10987}
10988
10989
10990// TODO(turbofan): Make sure table is sorted and use binary search.
10991int HandlerTable::LookupReturn(int pc_offset, CatchPrediction* prediction_out) {
10992 for (int i = 0; i < length(); i += kReturnEntrySize) {
10993 int return_offset = Smi::cast(get(i + kReturnOffsetIndex))->value();
10994 int handler_field = Smi::cast(get(i + kReturnHandlerIndex))->value();
10995 if (pc_offset == return_offset) {
10996 if (prediction_out) {
10997 *prediction_out = HandlerPredictionField::decode(handler_field);
10998 }
10999 return HandlerOffsetField::decode(handler_field);
11000 }
11001 }
11002 return -1;
11003}
11004
11005
Steve Blocka7e24c12009-10-30 11:49:00 +000011006#ifdef DEBUG
11007bool DescriptorArray::IsEqualTo(DescriptorArray* other) {
11008 if (IsEmpty()) return other->IsEmpty();
11009 if (other->IsEmpty()) return false;
11010 if (length() != other->length()) return false;
11011 for (int i = 0; i < length(); ++i) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011012 if (get(i) != other->get(i)) return false;
Steve Blocka7e24c12009-10-30 11:49:00 +000011013 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011014 return true;
Steve Blocka7e24c12009-10-30 11:49:00 +000011015}
11016#endif
11017
11018
Steve Blocka7e24c12009-10-30 11:49:00 +000011019bool String::LooksValid() {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011020 if (!GetIsolate()->heap()->Contains(this)) return false;
Steve Blocka7e24c12009-10-30 11:49:00 +000011021 return true;
11022}
11023
11024
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000011025// static
11026MaybeHandle<String> Name::ToFunctionName(Handle<Name> name) {
11027 if (name->IsString()) return Handle<String>::cast(name);
11028 // ES6 section 9.2.11 SetFunctionName, step 4.
11029 Isolate* const isolate = name->GetIsolate();
11030 Handle<Object> description(Handle<Symbol>::cast(name)->name(), isolate);
11031 if (description->IsUndefined()) return isolate->factory()->empty_string();
11032 IncrementalStringBuilder builder(isolate);
11033 builder.AppendCharacter('[');
11034 builder.AppendString(Handle<String>::cast(description));
11035 builder.AppendCharacter(']');
11036 return builder.Finish();
11037}
11038
11039
11040namespace {
11041
11042bool AreDigits(const uint8_t* s, int from, int to) {
11043 for (int i = from; i < to; i++) {
11044 if (s[i] < '0' || s[i] > '9') return false;
11045 }
11046
11047 return true;
11048}
11049
11050
11051int ParseDecimalInteger(const uint8_t* s, int from, int to) {
11052 DCHECK(to - from < 10); // Overflow is not possible.
11053 DCHECK(from < to);
11054 int d = s[from] - '0';
11055
11056 for (int i = from + 1; i < to; i++) {
11057 d = 10 * d + (s[i] - '0');
11058 }
11059
11060 return d;
11061}
11062
11063} // namespace
11064
11065
11066// static
11067Handle<Object> String::ToNumber(Handle<String> subject) {
11068 Isolate* const isolate = subject->GetIsolate();
11069
11070 // Flatten {subject} string first.
11071 subject = String::Flatten(subject);
11072
11073 // Fast array index case.
11074 uint32_t index;
11075 if (subject->AsArrayIndex(&index)) {
11076 return isolate->factory()->NewNumberFromUint(index);
11077 }
11078
11079 // Fast case: short integer or some sorts of junk values.
11080 if (subject->IsSeqOneByteString()) {
11081 int len = subject->length();
11082 if (len == 0) return handle(Smi::FromInt(0), isolate);
11083
11084 DisallowHeapAllocation no_gc;
11085 uint8_t const* data = Handle<SeqOneByteString>::cast(subject)->GetChars();
11086 bool minus = (data[0] == '-');
11087 int start_pos = (minus ? 1 : 0);
11088
11089 if (start_pos == len) {
11090 return isolate->factory()->nan_value();
11091 } else if (data[start_pos] > '9') {
11092 // Fast check for a junk value. A valid string may start from a
11093 // whitespace, a sign ('+' or '-'), the decimal point, a decimal digit
11094 // or the 'I' character ('Infinity'). All of that have codes not greater
11095 // than '9' except 'I' and &nbsp;.
11096 if (data[start_pos] != 'I' && data[start_pos] != 0xa0) {
11097 return isolate->factory()->nan_value();
11098 }
11099 } else if (len - start_pos < 10 && AreDigits(data, start_pos, len)) {
11100 // The maximal/minimal smi has 10 digits. If the string has less digits
11101 // we know it will fit into the smi-data type.
11102 int d = ParseDecimalInteger(data, start_pos, len);
11103 if (minus) {
11104 if (d == 0) return isolate->factory()->minus_zero_value();
11105 d = -d;
11106 } else if (!subject->HasHashCode() && len <= String::kMaxArrayIndexSize &&
11107 (len == 1 || data[0] != '0')) {
11108 // String hash is not calculated yet but all the data are present.
11109 // Update the hash field to speed up sequential convertions.
11110 uint32_t hash = StringHasher::MakeArrayIndexHash(d, len);
11111#ifdef DEBUG
11112 subject->Hash(); // Force hash calculation.
11113 DCHECK_EQ(static_cast<int>(subject->hash_field()),
11114 static_cast<int>(hash));
11115#endif
11116 subject->set_hash_field(hash);
11117 }
11118 return handle(Smi::FromInt(d), isolate);
11119 }
11120 }
11121
11122 // Slower case.
11123 int flags = ALLOW_HEX | ALLOW_OCTAL | ALLOW_BINARY;
11124 return isolate->factory()->NewNumber(
11125 StringToDouble(isolate->unicode_cache(), subject, flags));
11126}
11127
11128
Ben Murdoch69a99ed2011-11-30 16:03:39 +000011129String::FlatContent String::GetFlatContent() {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011130 DCHECK(!AllowHeapAllocation::IsAllowed());
Steve Blocka7e24c12009-10-30 11:49:00 +000011131 int length = this->length();
Ben Murdoch69a99ed2011-11-30 16:03:39 +000011132 StringShape shape(this);
Steve Blocka7e24c12009-10-30 11:49:00 +000011133 String* string = this;
Steve Blocka7e24c12009-10-30 11:49:00 +000011134 int offset = 0;
Ben Murdoch69a99ed2011-11-30 16:03:39 +000011135 if (shape.representation_tag() == kConsStringTag) {
Steve Blocka7e24c12009-10-30 11:49:00 +000011136 ConsString* cons = ConsString::cast(string);
Ben Murdoch69a99ed2011-11-30 16:03:39 +000011137 if (cons->second()->length() != 0) {
11138 return FlatContent();
11139 }
Steve Blocka7e24c12009-10-30 11:49:00 +000011140 string = cons->first();
Ben Murdoch69a99ed2011-11-30 16:03:39 +000011141 shape = StringShape(string);
Steve Blocka7e24c12009-10-30 11:49:00 +000011142 }
Ben Murdoch69a99ed2011-11-30 16:03:39 +000011143 if (shape.representation_tag() == kSlicedStringTag) {
11144 SlicedString* slice = SlicedString::cast(string);
11145 offset = slice->offset();
11146 string = slice->parent();
11147 shape = StringShape(string);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011148 DCHECK(shape.representation_tag() != kConsStringTag &&
Ben Murdoch69a99ed2011-11-30 16:03:39 +000011149 shape.representation_tag() != kSlicedStringTag);
Steve Blocka7e24c12009-10-30 11:49:00 +000011150 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011151 if (shape.encoding_tag() == kOneByteStringTag) {
11152 const uint8_t* start;
Ben Murdoch69a99ed2011-11-30 16:03:39 +000011153 if (shape.representation_tag() == kSeqStringTag) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011154 start = SeqOneByteString::cast(string)->GetChars();
Ben Murdoch69a99ed2011-11-30 16:03:39 +000011155 } else {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011156 start = ExternalOneByteString::cast(string)->GetChars();
Ben Murdoch69a99ed2011-11-30 16:03:39 +000011157 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011158 return FlatContent(start + offset, length);
Ben Murdoch69a99ed2011-11-30 16:03:39 +000011159 } else {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011160 DCHECK(shape.encoding_tag() == kTwoByteStringTag);
Ben Murdoch69a99ed2011-11-30 16:03:39 +000011161 const uc16* start;
11162 if (shape.representation_tag() == kSeqStringTag) {
11163 start = SeqTwoByteString::cast(string)->GetChars();
11164 } else {
Ben Murdoch3ef787d2012-04-12 10:51:47 +010011165 start = ExternalTwoByteString::cast(string)->GetChars();
Ben Murdoch69a99ed2011-11-30 16:03:39 +000011166 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011167 return FlatContent(start + offset, length);
Ben Murdoch69a99ed2011-11-30 16:03:39 +000011168 }
Steve Blocka7e24c12009-10-30 11:49:00 +000011169}
11170
11171
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000011172base::SmartArrayPointer<char> String::ToCString(AllowNullsFlag allow_nulls,
11173 RobustnessFlag robust_flag,
11174 int offset, int length,
11175 int* length_return) {
Steve Blocka7e24c12009-10-30 11:49:00 +000011176 if (robust_flag == ROBUST_STRING_TRAVERSAL && !LooksValid()) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000011177 return base::SmartArrayPointer<char>(NULL);
Steve Blocka7e24c12009-10-30 11:49:00 +000011178 }
Steve Blocka7e24c12009-10-30 11:49:00 +000011179 // Negative length means the to the end of the string.
11180 if (length < 0) length = kMaxInt - offset;
11181
11182 // Compute the size of the UTF-8 string. Start at the specified offset.
Emily Bernierd0a1eb72015-03-24 16:35:39 -040011183 StringCharacterStream stream(this, offset);
Steve Blocka7e24c12009-10-30 11:49:00 +000011184 int character_position = offset;
11185 int utf8_bytes = 0;
Ben Murdoch3ef787d2012-04-12 10:51:47 +010011186 int last = unibrow::Utf16::kNoPreviousCharacter;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011187 while (stream.HasMore() && character_position++ < offset + length) {
11188 uint16_t character = stream.GetNext();
Ben Murdoch3ef787d2012-04-12 10:51:47 +010011189 utf8_bytes += unibrow::Utf8::Length(character, last);
11190 last = character;
Steve Blocka7e24c12009-10-30 11:49:00 +000011191 }
11192
11193 if (length_return) {
11194 *length_return = utf8_bytes;
11195 }
11196
11197 char* result = NewArray<char>(utf8_bytes + 1);
11198
11199 // Convert the UTF-16 string to a UTF-8 buffer. Start at the specified offset.
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011200 stream.Reset(this, offset);
Steve Blocka7e24c12009-10-30 11:49:00 +000011201 character_position = offset;
11202 int utf8_byte_position = 0;
Ben Murdoch3ef787d2012-04-12 10:51:47 +010011203 last = unibrow::Utf16::kNoPreviousCharacter;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011204 while (stream.HasMore() && character_position++ < offset + length) {
11205 uint16_t character = stream.GetNext();
Ben Murdoch3ef787d2012-04-12 10:51:47 +010011206 if (allow_nulls == DISALLOW_NULLS && character == 0) {
11207 character = ' ';
Steve Blocka7e24c12009-10-30 11:49:00 +000011208 }
Ben Murdoch3ef787d2012-04-12 10:51:47 +010011209 utf8_byte_position +=
11210 unibrow::Utf8::Encode(result + utf8_byte_position, character, last);
11211 last = character;
Steve Blocka7e24c12009-10-30 11:49:00 +000011212 }
11213 result[utf8_byte_position] = 0;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000011214 return base::SmartArrayPointer<char>(result);
Steve Blocka7e24c12009-10-30 11:49:00 +000011215}
11216
11217
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000011218base::SmartArrayPointer<char> String::ToCString(AllowNullsFlag allow_nulls,
11219 RobustnessFlag robust_flag,
11220 int* length_return) {
Steve Blocka7e24c12009-10-30 11:49:00 +000011221 return ToCString(allow_nulls, robust_flag, 0, -1, length_return);
11222}
11223
11224
Steve Blocka7e24c12009-10-30 11:49:00 +000011225const uc16* String::GetTwoByteData(unsigned start) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011226 DCHECK(!IsOneByteRepresentationUnderneath());
Steve Blocka7e24c12009-10-30 11:49:00 +000011227 switch (StringShape(this).representation_tag()) {
11228 case kSeqStringTag:
11229 return SeqTwoByteString::cast(this)->SeqTwoByteStringGetData(start);
11230 case kExternalStringTag:
11231 return ExternalTwoByteString::cast(this)->
11232 ExternalTwoByteStringGetData(start);
Ben Murdoch69a99ed2011-11-30 16:03:39 +000011233 case kSlicedStringTag: {
11234 SlicedString* slice = SlicedString::cast(this);
11235 return slice->parent()->GetTwoByteData(start + slice->offset());
11236 }
Steve Blocka7e24c12009-10-30 11:49:00 +000011237 case kConsStringTag:
11238 UNREACHABLE();
11239 return NULL;
11240 }
11241 UNREACHABLE();
11242 return NULL;
11243}
11244
11245
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000011246base::SmartArrayPointer<uc16> String::ToWideCString(
11247 RobustnessFlag robust_flag) {
Steve Blocka7e24c12009-10-30 11:49:00 +000011248 if (robust_flag == ROBUST_STRING_TRAVERSAL && !LooksValid()) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000011249 return base::SmartArrayPointer<uc16>();
Steve Blocka7e24c12009-10-30 11:49:00 +000011250 }
Emily Bernierd0a1eb72015-03-24 16:35:39 -040011251 StringCharacterStream stream(this);
Steve Blocka7e24c12009-10-30 11:49:00 +000011252
11253 uc16* result = NewArray<uc16>(length() + 1);
11254
11255 int i = 0;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011256 while (stream.HasMore()) {
11257 uint16_t character = stream.GetNext();
Steve Blocka7e24c12009-10-30 11:49:00 +000011258 result[i++] = character;
11259 }
11260 result[i] = 0;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000011261 return base::SmartArrayPointer<uc16>(result);
Steve Blocka7e24c12009-10-30 11:49:00 +000011262}
11263
11264
11265const uc16* SeqTwoByteString::SeqTwoByteStringGetData(unsigned start) {
11266 return reinterpret_cast<uc16*>(
11267 reinterpret_cast<char*>(this) - kHeapObjectTag + kHeaderSize) + start;
11268}
11269
11270
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011271void Relocatable::PostGarbageCollectionProcessing(Isolate* isolate) {
Steve Block44f0eee2011-05-26 01:26:41 +010011272 Relocatable* current = isolate->relocatable_top();
Steve Blocka7e24c12009-10-30 11:49:00 +000011273 while (current != NULL) {
11274 current->PostGarbageCollection();
11275 current = current->prev_;
11276 }
11277}
11278
11279
11280// Reserve space for statics needing saving and restoring.
11281int Relocatable::ArchiveSpacePerThread() {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011282 return sizeof(Relocatable*); // NOLINT
Steve Blocka7e24c12009-10-30 11:49:00 +000011283}
11284
11285
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011286// Archive statics that are thread-local.
Ben Murdoch257744e2011-11-30 15:57:28 +000011287char* Relocatable::ArchiveState(Isolate* isolate, char* to) {
Steve Block44f0eee2011-05-26 01:26:41 +010011288 *reinterpret_cast<Relocatable**>(to) = isolate->relocatable_top();
11289 isolate->set_relocatable_top(NULL);
Steve Blocka7e24c12009-10-30 11:49:00 +000011290 return to + ArchiveSpacePerThread();
11291}
11292
11293
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011294// Restore statics that are thread-local.
Ben Murdoch257744e2011-11-30 15:57:28 +000011295char* Relocatable::RestoreState(Isolate* isolate, char* from) {
Steve Block44f0eee2011-05-26 01:26:41 +010011296 isolate->set_relocatable_top(*reinterpret_cast<Relocatable**>(from));
Steve Blocka7e24c12009-10-30 11:49:00 +000011297 return from + ArchiveSpacePerThread();
11298}
11299
11300
11301char* Relocatable::Iterate(ObjectVisitor* v, char* thread_storage) {
11302 Relocatable* top = *reinterpret_cast<Relocatable**>(thread_storage);
11303 Iterate(v, top);
11304 return thread_storage + ArchiveSpacePerThread();
11305}
11306
11307
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011308void Relocatable::Iterate(Isolate* isolate, ObjectVisitor* v) {
Steve Block44f0eee2011-05-26 01:26:41 +010011309 Iterate(v, isolate->relocatable_top());
Steve Blocka7e24c12009-10-30 11:49:00 +000011310}
11311
11312
11313void Relocatable::Iterate(ObjectVisitor* v, Relocatable* top) {
11314 Relocatable* current = top;
11315 while (current != NULL) {
11316 current->IterateInstance(v);
11317 current = current->prev_;
11318 }
11319}
11320
11321
Steve Block44f0eee2011-05-26 01:26:41 +010011322FlatStringReader::FlatStringReader(Isolate* isolate, Handle<String> str)
11323 : Relocatable(isolate),
11324 str_(str.location()),
Steve Blocka7e24c12009-10-30 11:49:00 +000011325 length_(str->length()) {
11326 PostGarbageCollection();
11327}
11328
11329
Steve Block44f0eee2011-05-26 01:26:41 +010011330FlatStringReader::FlatStringReader(Isolate* isolate, Vector<const char> input)
11331 : Relocatable(isolate),
11332 str_(0),
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011333 is_one_byte_(true),
Steve Blocka7e24c12009-10-30 11:49:00 +000011334 length_(input.length()),
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011335 start_(input.start()) {}
Steve Blocka7e24c12009-10-30 11:49:00 +000011336
11337
11338void FlatStringReader::PostGarbageCollection() {
11339 if (str_ == NULL) return;
11340 Handle<String> str(str_);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011341 DCHECK(str->IsFlat());
11342 DisallowHeapAllocation no_gc;
11343 // This does not actually prevent the vector from being relocated later.
Ben Murdoch69a99ed2011-11-30 16:03:39 +000011344 String::FlatContent content = str->GetFlatContent();
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011345 DCHECK(content.IsFlat());
11346 is_one_byte_ = content.IsOneByte();
11347 if (is_one_byte_) {
11348 start_ = content.ToOneByteVector().start();
Steve Blocka7e24c12009-10-30 11:49:00 +000011349 } else {
Ben Murdoch69a99ed2011-11-30 16:03:39 +000011350 start_ = content.ToUC16Vector().start();
Steve Blocka7e24c12009-10-30 11:49:00 +000011351 }
11352}
11353
11354
Emily Bernierd0a1eb72015-03-24 16:35:39 -040011355void ConsStringIterator::Initialize(ConsString* cons_string, int offset) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011356 DCHECK(cons_string != NULL);
11357 root_ = cons_string;
11358 consumed_ = offset;
11359 // Force stack blown condition to trigger restart.
11360 depth_ = 1;
11361 maximum_depth_ = kStackSize + depth_;
11362 DCHECK(StackBlown());
Steve Blocka7e24c12009-10-30 11:49:00 +000011363}
11364
11365
Emily Bernierd0a1eb72015-03-24 16:35:39 -040011366String* ConsStringIterator::Continue(int* offset_out) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011367 DCHECK(depth_ != 0);
11368 DCHECK_EQ(0, *offset_out);
11369 bool blew_stack = StackBlown();
11370 String* string = NULL;
11371 // Get the next leaf if there is one.
11372 if (!blew_stack) string = NextLeaf(&blew_stack);
11373 // Restart search from root.
11374 if (blew_stack) {
11375 DCHECK(string == NULL);
11376 string = Search(offset_out);
Steve Blocka7e24c12009-10-30 11:49:00 +000011377 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011378 // Ensure future calls return null immediately.
11379 if (string == NULL) Reset(NULL);
11380 return string;
Steve Blocka7e24c12009-10-30 11:49:00 +000011381}
11382
11383
Emily Bernierd0a1eb72015-03-24 16:35:39 -040011384String* ConsStringIterator::Search(int* offset_out) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011385 ConsString* cons_string = root_;
11386 // Reset the stack, pushing the root string.
11387 depth_ = 1;
11388 maximum_depth_ = 1;
11389 frames_[0] = cons_string;
11390 const int consumed = consumed_;
11391 int offset = 0;
Steve Blocka7e24c12009-10-30 11:49:00 +000011392 while (true) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011393 // Loop until the string is found which contains the target offset.
11394 String* string = cons_string->first();
11395 int length = string->length();
11396 int32_t type;
11397 if (consumed < offset + length) {
11398 // Target offset is in the left branch.
11399 // Keep going if we're still in a ConString.
11400 type = string->map()->instance_type();
11401 if ((type & kStringRepresentationMask) == kConsStringTag) {
11402 cons_string = ConsString::cast(string);
11403 PushLeft(cons_string);
Steve Blocka7e24c12009-10-30 11:49:00 +000011404 continue;
Steve Blocka7e24c12009-10-30 11:49:00 +000011405 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011406 // Tell the stack we're done descending.
11407 AdjustMaximumDepth();
Steve Blocka7e24c12009-10-30 11:49:00 +000011408 } else {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011409 // Descend right.
11410 // Update progress through the string.
11411 offset += length;
11412 // Keep going if we're still in a ConString.
11413 string = cons_string->second();
11414 type = string->map()->instance_type();
11415 if ((type & kStringRepresentationMask) == kConsStringTag) {
11416 cons_string = ConsString::cast(string);
11417 PushRight(cons_string);
11418 continue;
Steve Blocka7e24c12009-10-30 11:49:00 +000011419 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011420 // Need this to be updated for the current string.
11421 length = string->length();
11422 // Account for the possibility of an empty right leaf.
11423 // This happens only if we have asked for an offset outside the string.
11424 if (length == 0) {
11425 // Reset so future operations will return null immediately.
11426 Reset(NULL);
11427 return NULL;
11428 }
11429 // Tell the stack we're done descending.
11430 AdjustMaximumDepth();
11431 // Pop stack so next iteration is in correct place.
11432 Pop();
11433 }
11434 DCHECK(length != 0);
11435 // Adjust return values and exit.
11436 consumed_ = offset + length;
11437 *offset_out = consumed - offset;
11438 return string;
11439 }
11440 UNREACHABLE();
11441 return NULL;
11442}
11443
11444
Emily Bernierd0a1eb72015-03-24 16:35:39 -040011445String* ConsStringIterator::NextLeaf(bool* blew_stack) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011446 while (true) {
11447 // Tree traversal complete.
11448 if (depth_ == 0) {
11449 *blew_stack = false;
11450 return NULL;
11451 }
11452 // We've lost track of higher nodes.
11453 if (StackBlown()) {
11454 *blew_stack = true;
11455 return NULL;
11456 }
11457 // Go right.
11458 ConsString* cons_string = frames_[OffsetForDepth(depth_ - 1)];
11459 String* string = cons_string->second();
11460 int32_t type = string->map()->instance_type();
11461 if ((type & kStringRepresentationMask) != kConsStringTag) {
11462 // Pop stack so next iteration is in correct place.
11463 Pop();
11464 int length = string->length();
11465 // Could be a flattened ConsString.
11466 if (length == 0) continue;
11467 consumed_ += length;
11468 return string;
11469 }
11470 cons_string = ConsString::cast(string);
11471 PushRight(cons_string);
11472 // Need to traverse all the way left.
11473 while (true) {
11474 // Continue left.
11475 string = cons_string->first();
11476 type = string->map()->instance_type();
11477 if ((type & kStringRepresentationMask) != kConsStringTag) {
11478 AdjustMaximumDepth();
11479 int length = string->length();
11480 DCHECK(length != 0);
11481 consumed_ += length;
11482 return string;
11483 }
11484 cons_string = ConsString::cast(string);
11485 PushLeft(cons_string);
Steve Blocka7e24c12009-10-30 11:49:00 +000011486 }
11487 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011488 UNREACHABLE();
11489 return NULL;
Steve Blocka7e24c12009-10-30 11:49:00 +000011490}
11491
11492
Steve Blocka7e24c12009-10-30 11:49:00 +000011493uint16_t ConsString::ConsStringGet(int index) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011494 DCHECK(index >= 0 && index < this->length());
Steve Blocka7e24c12009-10-30 11:49:00 +000011495
11496 // Check for a flattened cons string
11497 if (second()->length() == 0) {
11498 String* left = first();
11499 return left->Get(index);
11500 }
11501
11502 String* string = String::cast(this);
11503
11504 while (true) {
11505 if (StringShape(string).IsCons()) {
11506 ConsString* cons_string = ConsString::cast(string);
11507 String* left = cons_string->first();
11508 if (left->length() > index) {
11509 string = left;
11510 } else {
11511 index -= left->length();
11512 string = cons_string->second();
11513 }
11514 } else {
11515 return string->Get(index);
11516 }
11517 }
11518
11519 UNREACHABLE();
11520 return 0;
11521}
11522
11523
Ben Murdoch69a99ed2011-11-30 16:03:39 +000011524uint16_t SlicedString::SlicedStringGet(int index) {
11525 return parent()->Get(offset() + index);
11526}
11527
11528
Steve Blocka7e24c12009-10-30 11:49:00 +000011529template <typename sinkchar>
11530void String::WriteToFlat(String* src,
11531 sinkchar* sink,
11532 int f,
11533 int t) {
11534 String* source = src;
11535 int from = f;
11536 int to = t;
11537 while (true) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011538 DCHECK(0 <= from && from <= to && to <= source->length());
Steve Blocka7e24c12009-10-30 11:49:00 +000011539 switch (StringShape(source).full_representation_tag()) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011540 case kOneByteStringTag | kExternalStringTag: {
11541 CopyChars(sink, ExternalOneByteString::cast(source)->GetChars() + from,
Steve Blocka7e24c12009-10-30 11:49:00 +000011542 to - from);
11543 return;
11544 }
11545 case kTwoByteStringTag | kExternalStringTag: {
11546 const uc16* data =
Ben Murdoch3ef787d2012-04-12 10:51:47 +010011547 ExternalTwoByteString::cast(source)->GetChars();
Steve Blocka7e24c12009-10-30 11:49:00 +000011548 CopyChars(sink,
11549 data + from,
11550 to - from);
11551 return;
11552 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011553 case kOneByteStringTag | kSeqStringTag: {
Steve Blocka7e24c12009-10-30 11:49:00 +000011554 CopyChars(sink,
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011555 SeqOneByteString::cast(source)->GetChars() + from,
Steve Blocka7e24c12009-10-30 11:49:00 +000011556 to - from);
11557 return;
11558 }
11559 case kTwoByteStringTag | kSeqStringTag: {
11560 CopyChars(sink,
11561 SeqTwoByteString::cast(source)->GetChars() + from,
11562 to - from);
11563 return;
11564 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011565 case kOneByteStringTag | kConsStringTag:
Steve Blocka7e24c12009-10-30 11:49:00 +000011566 case kTwoByteStringTag | kConsStringTag: {
11567 ConsString* cons_string = ConsString::cast(source);
11568 String* first = cons_string->first();
11569 int boundary = first->length();
11570 if (to - boundary >= boundary - from) {
11571 // Right hand side is longer. Recurse over left.
11572 if (from < boundary) {
11573 WriteToFlat(first, sink, from, boundary);
11574 sink += boundary - from;
11575 from = 0;
11576 } else {
11577 from -= boundary;
11578 }
11579 to -= boundary;
11580 source = cons_string->second();
11581 } else {
11582 // Left hand side is longer. Recurse over right.
11583 if (to > boundary) {
11584 String* second = cons_string->second();
Ben Murdoch3ef787d2012-04-12 10:51:47 +010011585 // When repeatedly appending to a string, we get a cons string that
11586 // is unbalanced to the left, a list, essentially. We inline the
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011587 // common case of sequential one-byte right child.
Ben Murdoch3ef787d2012-04-12 10:51:47 +010011588 if (to - boundary == 1) {
11589 sink[boundary - from] = static_cast<sinkchar>(second->Get(0));
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011590 } else if (second->IsSeqOneByteString()) {
Ben Murdoch3ef787d2012-04-12 10:51:47 +010011591 CopyChars(sink + boundary - from,
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011592 SeqOneByteString::cast(second)->GetChars(),
Steve Blocka7e24c12009-10-30 11:49:00 +000011593 to - boundary);
Ben Murdoch3ef787d2012-04-12 10:51:47 +010011594 } else {
11595 WriteToFlat(second,
11596 sink + boundary - from,
11597 0,
11598 to - boundary);
11599 }
Steve Blocka7e24c12009-10-30 11:49:00 +000011600 to = boundary;
11601 }
11602 source = first;
11603 }
11604 break;
11605 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011606 case kOneByteStringTag | kSlicedStringTag:
Ben Murdoch69a99ed2011-11-30 16:03:39 +000011607 case kTwoByteStringTag | kSlicedStringTag: {
11608 SlicedString* slice = SlicedString::cast(source);
11609 unsigned offset = slice->offset();
11610 WriteToFlat(slice->parent(), sink, from + offset, to + offset);
11611 return;
11612 }
Steve Blocka7e24c12009-10-30 11:49:00 +000011613 }
11614 }
11615}
11616
11617
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011618
11619template <typename SourceChar>
11620static void CalculateLineEndsImpl(Isolate* isolate,
11621 List<int>* line_ends,
11622 Vector<const SourceChar> src,
11623 bool include_ending_line) {
11624 const int src_len = src.length();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000011625 UnicodeCache* cache = isolate->unicode_cache();
11626 for (int i = 0; i < src_len - 1; i++) {
11627 SourceChar current = src[i];
11628 SourceChar next = src[i + 1];
11629 if (cache->IsLineTerminatorSequence(current, next)) line_ends->Add(i);
11630 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011631
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000011632 if (src_len > 0 && cache->IsLineTerminatorSequence(src[src_len - 1], 0)) {
11633 line_ends->Add(src_len - 1);
11634 }
11635 if (include_ending_line) {
11636 // Include one character beyond the end of script. The rewriter uses that
11637 // position for the implicit return statement.
11638 line_ends->Add(src_len);
Steve Blocka7e24c12009-10-30 11:49:00 +000011639 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011640}
11641
11642
11643Handle<FixedArray> String::CalculateLineEnds(Handle<String> src,
11644 bool include_ending_line) {
11645 src = Flatten(src);
11646 // Rough estimate of line count based on a roughly estimated average
11647 // length of (unpacked) code.
11648 int line_count_estimate = src->length() >> 4;
11649 List<int> line_ends(line_count_estimate);
11650 Isolate* isolate = src->GetIsolate();
11651 { DisallowHeapAllocation no_allocation; // ensure vectors stay valid.
11652 // Dispatch on type of strings.
11653 String::FlatContent content = src->GetFlatContent();
11654 DCHECK(content.IsFlat());
11655 if (content.IsOneByte()) {
11656 CalculateLineEndsImpl(isolate,
11657 &line_ends,
11658 content.ToOneByteVector(),
11659 include_ending_line);
11660 } else {
11661 CalculateLineEndsImpl(isolate,
11662 &line_ends,
11663 content.ToUC16Vector(),
11664 include_ending_line);
11665 }
11666 }
11667 int line_count = line_ends.length();
11668 Handle<FixedArray> array = isolate->factory()->NewFixedArray(line_count);
11669 for (int i = 0; i < line_count; i++) {
11670 array->set(i, Smi::FromInt(line_ends[i]));
11671 }
11672 return array;
Steve Blocka7e24c12009-10-30 11:49:00 +000011673}
11674
11675
11676// Compares the contents of two strings by reading and comparing
11677// int-sized blocks of characters.
11678template <typename Char>
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011679static inline bool CompareRawStringContents(const Char* const a,
11680 const Char* const b,
11681 int length) {
11682 return CompareChars(a, b, length) == 0;
11683}
11684
11685
11686template<typename Chars1, typename Chars2>
11687class RawStringComparator : public AllStatic {
11688 public:
11689 static inline bool compare(const Chars1* a, const Chars2* b, int len) {
11690 DCHECK(sizeof(Chars1) != sizeof(Chars2));
11691 for (int i = 0; i < len; i++) {
11692 if (a[i] != b[i]) {
Steve Blocka7e24c12009-10-30 11:49:00 +000011693 return false;
11694 }
11695 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011696 return true;
Steve Blocka7e24c12009-10-30 11:49:00 +000011697 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011698};
Steve Blocka7e24c12009-10-30 11:49:00 +000011699
11700
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011701template<>
11702class RawStringComparator<uint16_t, uint16_t> {
11703 public:
11704 static inline bool compare(const uint16_t* a, const uint16_t* b, int len) {
11705 return CompareRawStringContents(a, b, len);
Steve Blocka7e24c12009-10-30 11:49:00 +000011706 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011707};
11708
11709
11710template<>
11711class RawStringComparator<uint8_t, uint8_t> {
11712 public:
11713 static inline bool compare(const uint8_t* a, const uint8_t* b, int len) {
11714 return CompareRawStringContents(a, b, len);
11715 }
11716};
11717
11718
11719class StringComparator {
11720 class State {
11721 public:
Emily Bernierd0a1eb72015-03-24 16:35:39 -040011722 State() : is_one_byte_(true), length_(0), buffer8_(NULL) {}
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011723
Emily Bernierd0a1eb72015-03-24 16:35:39 -040011724 void Init(String* string) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011725 ConsString* cons_string = String::VisitFlat(this, string);
Emily Bernierd0a1eb72015-03-24 16:35:39 -040011726 iter_.Reset(cons_string);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011727 if (cons_string != NULL) {
11728 int offset;
Emily Bernierd0a1eb72015-03-24 16:35:39 -040011729 string = iter_.Next(&offset);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011730 String::VisitFlat(this, string, offset);
11731 }
11732 }
11733
11734 inline void VisitOneByteString(const uint8_t* chars, int length) {
11735 is_one_byte_ = true;
11736 buffer8_ = chars;
11737 length_ = length;
11738 }
11739
11740 inline void VisitTwoByteString(const uint16_t* chars, int length) {
11741 is_one_byte_ = false;
11742 buffer16_ = chars;
11743 length_ = length;
11744 }
11745
11746 void Advance(int consumed) {
11747 DCHECK(consumed <= length_);
11748 // Still in buffer.
11749 if (length_ != consumed) {
11750 if (is_one_byte_) {
11751 buffer8_ += consumed;
11752 } else {
11753 buffer16_ += consumed;
11754 }
11755 length_ -= consumed;
11756 return;
11757 }
11758 // Advance state.
11759 int offset;
Emily Bernierd0a1eb72015-03-24 16:35:39 -040011760 String* next = iter_.Next(&offset);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011761 DCHECK_EQ(0, offset);
11762 DCHECK(next != NULL);
11763 String::VisitFlat(this, next);
11764 }
11765
Emily Bernierd0a1eb72015-03-24 16:35:39 -040011766 ConsStringIterator iter_;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011767 bool is_one_byte_;
11768 int length_;
11769 union {
11770 const uint8_t* buffer8_;
11771 const uint16_t* buffer16_;
11772 };
11773
11774 private:
Emily Bernierd0a1eb72015-03-24 16:35:39 -040011775 DISALLOW_COPY_AND_ASSIGN(State);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011776 };
11777
11778 public:
Emily Bernierd0a1eb72015-03-24 16:35:39 -040011779 inline StringComparator() {}
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011780
11781 template<typename Chars1, typename Chars2>
11782 static inline bool Equals(State* state_1, State* state_2, int to_check) {
11783 const Chars1* a = reinterpret_cast<const Chars1*>(state_1->buffer8_);
11784 const Chars2* b = reinterpret_cast<const Chars2*>(state_2->buffer8_);
11785 return RawStringComparator<Chars1, Chars2>::compare(a, b, to_check);
11786 }
11787
11788 bool Equals(String* string_1, String* string_2) {
11789 int length = string_1->length();
11790 state_1_.Init(string_1);
11791 state_2_.Init(string_2);
11792 while (true) {
11793 int to_check = Min(state_1_.length_, state_2_.length_);
11794 DCHECK(to_check > 0 && to_check <= length);
11795 bool is_equal;
11796 if (state_1_.is_one_byte_) {
11797 if (state_2_.is_one_byte_) {
11798 is_equal = Equals<uint8_t, uint8_t>(&state_1_, &state_2_, to_check);
11799 } else {
11800 is_equal = Equals<uint8_t, uint16_t>(&state_1_, &state_2_, to_check);
11801 }
11802 } else {
11803 if (state_2_.is_one_byte_) {
11804 is_equal = Equals<uint16_t, uint8_t>(&state_1_, &state_2_, to_check);
11805 } else {
11806 is_equal = Equals<uint16_t, uint16_t>(&state_1_, &state_2_, to_check);
11807 }
11808 }
11809 // Looping done.
11810 if (!is_equal) return false;
11811 length -= to_check;
11812 // Exit condition. Strings are equal.
11813 if (length == 0) return true;
11814 state_1_.Advance(to_check);
11815 state_2_.Advance(to_check);
11816 }
11817 }
11818
11819 private:
11820 State state_1_;
11821 State state_2_;
Emily Bernierd0a1eb72015-03-24 16:35:39 -040011822
11823 DISALLOW_COPY_AND_ASSIGN(StringComparator);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011824};
Steve Blocka7e24c12009-10-30 11:49:00 +000011825
11826
Steve Blocka7e24c12009-10-30 11:49:00 +000011827bool String::SlowEquals(String* other) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011828 DisallowHeapAllocation no_gc;
Steve Blocka7e24c12009-10-30 11:49:00 +000011829 // Fast check: negative check with lengths.
11830 int len = length();
11831 if (len != other->length()) return false;
11832 if (len == 0) return true;
11833
11834 // Fast check: if hash code is computed for both strings
11835 // a fast negative check can be performed.
11836 if (HasHashCode() && other->HasHashCode()) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011837#ifdef ENABLE_SLOW_DCHECKS
Ben Murdochc7cc0282012-03-05 14:35:55 +000011838 if (FLAG_enable_slow_asserts) {
11839 if (Hash() != other->Hash()) {
11840 bool found_difference = false;
11841 for (int i = 0; i < len; i++) {
11842 if (Get(i) != other->Get(i)) {
11843 found_difference = true;
11844 break;
11845 }
11846 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011847 DCHECK(found_difference);
Ben Murdochc7cc0282012-03-05 14:35:55 +000011848 }
11849 }
11850#endif
Steve Blocka7e24c12009-10-30 11:49:00 +000011851 if (Hash() != other->Hash()) return false;
11852 }
11853
Leon Clarkef7060e22010-06-03 12:02:55 +010011854 // We know the strings are both non-empty. Compare the first chars
11855 // before we try to flatten the strings.
11856 if (this->Get(0) != other->Get(0)) return false;
11857
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011858 if (IsSeqOneByteString() && other->IsSeqOneByteString()) {
11859 const uint8_t* str1 = SeqOneByteString::cast(this)->GetChars();
11860 const uint8_t* str2 = SeqOneByteString::cast(other)->GetChars();
11861 return CompareRawStringContents(str1, str2, len);
Steve Blocka7e24c12009-10-30 11:49:00 +000011862 }
11863
Emily Bernierd0a1eb72015-03-24 16:35:39 -040011864 StringComparator comparator;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011865 return comparator.Equals(this, other);
11866}
11867
11868
11869bool String::SlowEquals(Handle<String> one, Handle<String> two) {
11870 // Fast check: negative check with lengths.
11871 int one_length = one->length();
11872 if (one_length != two->length()) return false;
11873 if (one_length == 0) return true;
11874
11875 // Fast check: if hash code is computed for both strings
11876 // a fast negative check can be performed.
11877 if (one->HasHashCode() && two->HasHashCode()) {
11878#ifdef ENABLE_SLOW_DCHECKS
11879 if (FLAG_enable_slow_asserts) {
11880 if (one->Hash() != two->Hash()) {
11881 bool found_difference = false;
11882 for (int i = 0; i < one_length; i++) {
11883 if (one->Get(i) != two->Get(i)) {
11884 found_difference = true;
11885 break;
11886 }
Steve Blocka7e24c12009-10-30 11:49:00 +000011887 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011888 DCHECK(found_difference);
Steve Blocka7e24c12009-10-30 11:49:00 +000011889 }
11890 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011891#endif
11892 if (one->Hash() != two->Hash()) return false;
11893 }
11894
11895 // We know the strings are both non-empty. Compare the first chars
11896 // before we try to flatten the strings.
11897 if (one->Get(0) != two->Get(0)) return false;
11898
11899 one = String::Flatten(one);
11900 two = String::Flatten(two);
11901
11902 DisallowHeapAllocation no_gc;
11903 String::FlatContent flat1 = one->GetFlatContent();
11904 String::FlatContent flat2 = two->GetFlatContent();
11905
11906 if (flat1.IsOneByte() && flat2.IsOneByte()) {
11907 return CompareRawStringContents(flat1.ToOneByteVector().start(),
11908 flat2.ToOneByteVector().start(),
11909 one_length);
Steve Blocka7e24c12009-10-30 11:49:00 +000011910 } else {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011911 for (int i = 0; i < one_length; i++) {
11912 if (flat1.Get(i) != flat2.Get(i)) return false;
11913 }
11914 return true;
Steve Blocka7e24c12009-10-30 11:49:00 +000011915 }
11916}
11917
11918
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000011919// static
11920ComparisonResult String::Compare(Handle<String> x, Handle<String> y) {
11921 // A few fast case tests before we flatten.
11922 if (x.is_identical_to(y)) {
11923 return ComparisonResult::kEqual;
11924 } else if (y->length() == 0) {
11925 return x->length() == 0 ? ComparisonResult::kEqual
11926 : ComparisonResult::kGreaterThan;
11927 } else if (x->length() == 0) {
11928 return ComparisonResult::kLessThan;
Steve Blocka7e24c12009-10-30 11:49:00 +000011929 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000011930
11931 int const d = x->Get(0) - y->Get(0);
11932 if (d < 0) {
11933 return ComparisonResult::kLessThan;
11934 } else if (d > 0) {
11935 return ComparisonResult::kGreaterThan;
11936 }
11937
11938 // Slow case.
11939 x = String::Flatten(x);
11940 y = String::Flatten(y);
11941
11942 DisallowHeapAllocation no_gc;
11943 ComparisonResult result = ComparisonResult::kEqual;
11944 int prefix_length = x->length();
11945 if (y->length() < prefix_length) {
11946 prefix_length = y->length();
11947 result = ComparisonResult::kGreaterThan;
11948 } else if (y->length() > prefix_length) {
11949 result = ComparisonResult::kLessThan;
11950 }
11951 int r;
11952 String::FlatContent x_content = x->GetFlatContent();
11953 String::FlatContent y_content = y->GetFlatContent();
11954 if (x_content.IsOneByte()) {
11955 Vector<const uint8_t> x_chars = x_content.ToOneByteVector();
11956 if (y_content.IsOneByte()) {
11957 Vector<const uint8_t> y_chars = y_content.ToOneByteVector();
11958 r = CompareChars(x_chars.start(), y_chars.start(), prefix_length);
11959 } else {
11960 Vector<const uc16> y_chars = y_content.ToUC16Vector();
11961 r = CompareChars(x_chars.start(), y_chars.start(), prefix_length);
11962 }
11963 } else {
11964 Vector<const uc16> x_chars = x_content.ToUC16Vector();
11965 if (y_content.IsOneByte()) {
11966 Vector<const uint8_t> y_chars = y_content.ToOneByteVector();
11967 r = CompareChars(x_chars.start(), y_chars.start(), prefix_length);
11968 } else {
11969 Vector<const uc16> y_chars = y_content.ToUC16Vector();
11970 r = CompareChars(x_chars.start(), y_chars.start(), prefix_length);
11971 }
11972 }
11973 if (r < 0) {
11974 result = ComparisonResult::kLessThan;
11975 } else if (r > 0) {
11976 result = ComparisonResult::kGreaterThan;
11977 }
11978 return result;
Steve Blocka7e24c12009-10-30 11:49:00 +000011979}
11980
11981
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011982bool String::IsUtf8EqualTo(Vector<const char> str, bool allow_prefix_match) {
Steve Blocka7e24c12009-10-30 11:49:00 +000011983 int slen = length();
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011984 // Can't check exact length equality, but we can check bounds.
11985 int str_len = str.length();
11986 if (!allow_prefix_match &&
11987 (str_len < slen ||
11988 str_len > slen*static_cast<int>(unibrow::Utf8::kMaxEncodedSize))) {
11989 return false;
11990 }
Steve Blocka7e24c12009-10-30 11:49:00 +000011991 int i;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000011992 size_t remaining_in_str = static_cast<size_t>(str_len);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011993 const uint8_t* utf8_data = reinterpret_cast<const uint8_t*>(str.start());
11994 for (i = 0; i < slen && remaining_in_str > 0; i++) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000011995 size_t cursor = 0;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011996 uint32_t r = unibrow::Utf8::ValueOf(utf8_data, remaining_in_str, &cursor);
11997 DCHECK(cursor > 0 && cursor <= remaining_in_str);
Ben Murdoch3ef787d2012-04-12 10:51:47 +010011998 if (r > unibrow::Utf16::kMaxNonSurrogateCharCode) {
11999 if (i > slen - 1) return false;
12000 if (Get(i++) != unibrow::Utf16::LeadSurrogate(r)) return false;
12001 if (Get(i) != unibrow::Utf16::TrailSurrogate(r)) return false;
12002 } else {
12003 if (Get(i) != r) return false;
12004 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012005 utf8_data += cursor;
12006 remaining_in_str -= cursor;
Steve Blocka7e24c12009-10-30 11:49:00 +000012007 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012008 return (allow_prefix_match || i == slen) && remaining_in_str == 0;
Steve Blocka7e24c12009-10-30 11:49:00 +000012009}
12010
12011
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012012bool String::IsOneByteEqualTo(Vector<const uint8_t> str) {
Steve Block9fac8402011-05-12 15:51:54 +010012013 int slen = length();
12014 if (str.length() != slen) return false;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012015 DisallowHeapAllocation no_gc;
Ben Murdoch69a99ed2011-11-30 16:03:39 +000012016 FlatContent content = GetFlatContent();
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012017 if (content.IsOneByte()) {
12018 return CompareChars(content.ToOneByteVector().start(),
Ben Murdoch69a99ed2011-11-30 16:03:39 +000012019 str.start(), slen) == 0;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000012020 }
12021 for (int i = 0; i < slen; i++) {
12022 if (Get(i) != static_cast<uint16_t>(str[i])) return false;
Steve Block9fac8402011-05-12 15:51:54 +010012023 }
12024 return true;
12025}
12026
12027
12028bool String::IsTwoByteEqualTo(Vector<const uc16> str) {
12029 int slen = length();
12030 if (str.length() != slen) return false;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012031 DisallowHeapAllocation no_gc;
Ben Murdoch69a99ed2011-11-30 16:03:39 +000012032 FlatContent content = GetFlatContent();
12033 if (content.IsTwoByte()) {
12034 return CompareChars(content.ToUC16Vector().start(), str.start(), slen) == 0;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000012035 }
Steve Block9fac8402011-05-12 15:51:54 +010012036 for (int i = 0; i < slen; i++) {
12037 if (Get(i) != str[i]) return false;
12038 }
12039 return true;
12040}
12041
12042
Steve Blocka7e24c12009-10-30 11:49:00 +000012043uint32_t String::ComputeAndSetHash() {
12044 // Should only be called if hash code has not yet been computed.
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012045 DCHECK(!HasHashCode());
Steve Blocka7e24c12009-10-30 11:49:00 +000012046
12047 // Store the hash code in the object.
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012048 uint32_t field = IteratingStringHasher::Hash(this, GetHeap()->HashSeed());
Steve Blockd0582a62009-12-15 09:54:21 +000012049 set_hash_field(field);
Steve Blocka7e24c12009-10-30 11:49:00 +000012050
12051 // Check the hash code is there.
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012052 DCHECK(HasHashCode());
Steve Blocka7e24c12009-10-30 11:49:00 +000012053 uint32_t result = field >> kHashShift;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012054 DCHECK(result != 0); // Ensure that the hash value of 0 is never computed.
Steve Blocka7e24c12009-10-30 11:49:00 +000012055 return result;
12056}
12057
12058
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012059bool String::ComputeArrayIndex(uint32_t* index) {
12060 int length = this->length();
Steve Blocka7e24c12009-10-30 11:49:00 +000012061 if (length == 0 || length > kMaxArrayIndexSize) return false;
Emily Bernierd0a1eb72015-03-24 16:35:39 -040012062 StringCharacterStream stream(this);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012063 return StringToArrayIndex(&stream, index);
Steve Blocka7e24c12009-10-30 11:49:00 +000012064}
12065
12066
12067bool String::SlowAsArrayIndex(uint32_t* index) {
12068 if (length() <= kMaxCachedArrayIndexLength) {
12069 Hash(); // force computation of hash code
Steve Blockd0582a62009-12-15 09:54:21 +000012070 uint32_t field = hash_field();
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +010012071 if ((field & kIsNotArrayIndexMask) != 0) return false;
Steve Blockd0582a62009-12-15 09:54:21 +000012072 // Isolate the array index form the full hash field.
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012073 *index = ArrayIndexValueBits::decode(field);
Steve Blocka7e24c12009-10-30 11:49:00 +000012074 return true;
12075 } else {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012076 return ComputeArrayIndex(index);
Steve Blocka7e24c12009-10-30 11:49:00 +000012077 }
12078}
12079
12080
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012081Handle<String> SeqString::Truncate(Handle<SeqString> string, int new_length) {
12082 int new_size, old_size;
12083 int old_length = string->length();
12084 if (old_length <= new_length) return string;
12085
12086 if (string->IsSeqOneByteString()) {
12087 old_size = SeqOneByteString::SizeFor(old_length);
12088 new_size = SeqOneByteString::SizeFor(new_length);
12089 } else {
12090 DCHECK(string->IsSeqTwoByteString());
12091 old_size = SeqTwoByteString::SizeFor(old_length);
12092 new_size = SeqTwoByteString::SizeFor(new_length);
12093 }
12094
12095 int delta = old_size - new_size;
12096
12097 Address start_of_string = string->address();
12098 DCHECK_OBJECT_ALIGNED(start_of_string);
12099 DCHECK_OBJECT_ALIGNED(start_of_string + new_size);
12100
12101 Heap* heap = string->GetHeap();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000012102 // Sizes are pointer size aligned, so that we can use filler objects
12103 // that are a multiple of pointer size.
12104 heap->CreateFillerObjectAt(start_of_string + new_size, delta);
12105 heap->AdjustLiveBytes(*string, -delta, Heap::CONCURRENT_TO_SWEEPER);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012106
12107 // We are storing the new length using release store after creating a filler
12108 // for the left-over space to avoid races with the sweeper thread.
12109 string->synchronized_set_length(new_length);
12110
12111 if (new_length == 0) return heap->isolate()->factory()->empty_string();
12112 return string;
12113}
12114
12115
Iain Merrick9ac36c92010-09-13 15:29:50 +010012116uint32_t StringHasher::MakeArrayIndexHash(uint32_t value, int length) {
Kristian Monsen80d68ea2010-09-08 11:05:35 +010012117 // For array indexes mix the length into the hash as an array index could
12118 // be zero.
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012119 DCHECK(length > 0);
12120 DCHECK(length <= String::kMaxArrayIndexSize);
12121 DCHECK(TenToThe(String::kMaxCachedArrayIndexLength) <
Kristian Monsen80d68ea2010-09-08 11:05:35 +010012122 (1 << String::kArrayIndexValueBits));
Iain Merrick9ac36c92010-09-13 15:29:50 +010012123
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012124 value <<= String::ArrayIndexValueBits::kShift;
12125 value |= length << String::ArrayIndexLengthBits::kShift;
Iain Merrick9ac36c92010-09-13 15:29:50 +010012126
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012127 DCHECK((value & String::kIsNotArrayIndexMask) == 0);
12128 DCHECK((length > String::kMaxCachedArrayIndexLength) ||
Iain Merrick9ac36c92010-09-13 15:29:50 +010012129 (value & String::kContainsCachedArrayIndexMask) == 0);
Kristian Monsen80d68ea2010-09-08 11:05:35 +010012130 return value;
Steve Blocka7e24c12009-10-30 11:49:00 +000012131}
12132
12133
12134uint32_t StringHasher::GetHashField() {
Steve Blockd0582a62009-12-15 09:54:21 +000012135 if (length_ <= String::kMaxHashCalcLength) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012136 if (is_array_index_) {
12137 return MakeArrayIndexHash(array_index_, length_);
Steve Blocka7e24c12009-10-30 11:49:00 +000012138 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012139 return (GetHashCore(raw_running_hash_) << String::kHashShift) |
12140 String::kIsNotArrayIndexMask;
Steve Blocka7e24c12009-10-30 11:49:00 +000012141 } else {
Kristian Monsen80d68ea2010-09-08 11:05:35 +010012142 return (length_ << String::kHashShift) | String::kIsNotArrayIndexMask;
Steve Blocka7e24c12009-10-30 11:49:00 +000012143 }
12144}
12145
12146
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012147uint32_t StringHasher::ComputeUtf8Hash(Vector<const char> chars,
12148 uint32_t seed,
12149 int* utf16_length_out) {
12150 int vector_length = chars.length();
12151 // Handle some edge cases
12152 if (vector_length <= 1) {
12153 DCHECK(vector_length == 0 ||
12154 static_cast<uint8_t>(chars.start()[0]) <=
12155 unibrow::Utf8::kMaxOneByteChar);
12156 *utf16_length_out = vector_length;
12157 return HashSequentialString(chars.start(), vector_length, seed);
Steve Blocka7e24c12009-10-30 11:49:00 +000012158 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012159 // Start with a fake length which won't affect computation.
12160 // It will be updated later.
12161 StringHasher hasher(String::kMaxArrayIndexSize, seed);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000012162 size_t remaining = static_cast<size_t>(vector_length);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012163 const uint8_t* stream = reinterpret_cast<const uint8_t*>(chars.start());
12164 int utf16_length = 0;
12165 bool is_index = true;
12166 DCHECK(hasher.is_array_index_);
12167 while (remaining > 0) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000012168 size_t consumed = 0;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012169 uint32_t c = unibrow::Utf8::ValueOf(stream, remaining, &consumed);
12170 DCHECK(consumed > 0 && consumed <= remaining);
12171 stream += consumed;
12172 remaining -= consumed;
12173 bool is_two_characters = c > unibrow::Utf16::kMaxNonSurrogateCharCode;
12174 utf16_length += is_two_characters ? 2 : 1;
12175 // No need to keep hashing. But we do need to calculate utf16_length.
12176 if (utf16_length > String::kMaxHashCalcLength) continue;
12177 if (is_two_characters) {
12178 uint16_t c1 = unibrow::Utf16::LeadSurrogate(c);
12179 uint16_t c2 = unibrow::Utf16::TrailSurrogate(c);
12180 hasher.AddCharacter(c1);
12181 hasher.AddCharacter(c2);
12182 if (is_index) is_index = hasher.UpdateIndex(c1);
12183 if (is_index) is_index = hasher.UpdateIndex(c2);
12184 } else {
12185 hasher.AddCharacter(c);
12186 if (is_index) is_index = hasher.UpdateIndex(c);
12187 }
Steve Blocka7e24c12009-10-30 11:49:00 +000012188 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012189 *utf16_length_out = static_cast<int>(utf16_length);
12190 // Must set length here so that hash computation is correct.
12191 hasher.length_ = utf16_length;
Steve Blocka7e24c12009-10-30 11:49:00 +000012192 return hasher.GetHashField();
12193}
12194
12195
Emily Bernierd0a1eb72015-03-24 16:35:39 -040012196void IteratingStringHasher::VisitConsString(ConsString* cons_string) {
12197 // Run small ConsStrings through ConsStringIterator.
12198 if (cons_string->length() < 64) {
12199 ConsStringIterator iter(cons_string);
12200 int offset;
12201 String* string;
12202 while (nullptr != (string = iter.Next(&offset))) {
12203 DCHECK_EQ(0, offset);
12204 String::VisitFlat(this, string, 0);
12205 }
12206 return;
12207 }
12208 // Slow case.
12209 const int max_length = String::kMaxHashCalcLength;
12210 int length = std::min(cons_string->length(), max_length);
12211 if (cons_string->HasOnlyOneByteChars()) {
12212 uint8_t* buffer = new uint8_t[length];
12213 String::WriteToFlat(cons_string, buffer, 0, length);
12214 AddCharacters(buffer, length);
12215 delete[] buffer;
12216 } else {
12217 uint16_t* buffer = new uint16_t[length];
12218 String::WriteToFlat(cons_string, buffer, 0, length);
12219 AddCharacters(buffer, length);
12220 delete[] buffer;
12221 }
12222}
12223
12224
Steve Blocka7e24c12009-10-30 11:49:00 +000012225void String::PrintOn(FILE* file) {
12226 int length = this->length();
12227 for (int i = 0; i < length; i++) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012228 PrintF(file, "%c", Get(i));
Steve Blocka7e24c12009-10-30 11:49:00 +000012229 }
12230}
12231
12232
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000012233int Map::Hash() {
12234 // For performance reasons we only hash the 3 most variable fields of a map:
Emily Bernierd0a1eb72015-03-24 16:35:39 -040012235 // constructor, prototype and bit_field2. For predictability reasons we
12236 // use objects' offsets in respective pages for hashing instead of raw
12237 // addresses.
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000012238
12239 // Shift away the tag.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000012240 int hash = ObjectAddressForHashing(GetConstructor()) >> 2;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000012241
12242 // XOR-ing the prototype and constructor directly yields too many zero bits
12243 // when the two pointers are close (which is fairly common).
Emily Bernierd0a1eb72015-03-24 16:35:39 -040012244 // To avoid this we shift the prototype bits relatively to the constructor.
12245 hash ^= ObjectAddressForHashing(prototype()) << (32 - kPageSizeBits);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000012246
12247 return hash ^ (hash >> 16) ^ bit_field2();
12248}
12249
12250
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000012251namespace {
12252
12253bool CheckEquivalent(Map* first, Map* second) {
12254 return first->GetConstructor() == second->GetConstructor() &&
12255 first->prototype() == second->prototype() &&
12256 first->instance_type() == second->instance_type() &&
12257 first->bit_field() == second->bit_field() &&
12258 first->is_extensible() == second->is_extensible() &&
12259 first->is_strong() == second->is_strong() &&
12260 first->is_hidden_prototype() == second->is_hidden_prototype();
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012261}
12262
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000012263} // namespace
12264
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012265
12266bool Map::EquivalentToForTransition(Map* other) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000012267 if (!CheckEquivalent(this, other)) return false;
12268 if (instance_type() == JS_FUNCTION_TYPE) {
12269 // JSFunctions require more checks to ensure that sloppy function is
12270 // not equvalent to strict function.
12271 int nof = Min(NumberOfOwnDescriptors(), other->NumberOfOwnDescriptors());
12272 return instance_descriptors()->IsEqualUpTo(other->instance_descriptors(),
12273 nof);
12274 }
12275 return true;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012276}
12277
12278
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000012279bool Map::EquivalentToForNormalization(Map* other,
12280 PropertyNormalizationMode mode) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000012281 int properties =
12282 mode == CLEAR_INOBJECT_PROPERTIES ? 0 : other->GetInObjectProperties();
12283 return CheckEquivalent(this, other) && bit_field2() == other->bit_field2() &&
12284 GetInObjectProperties() == properties;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012285}
12286
12287
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000012288bool JSFunction::Inlines(SharedFunctionInfo* candidate) {
12289 DisallowHeapAllocation no_gc;
12290 if (shared() == candidate) return true;
12291 if (code()->kind() != Code::OPTIMIZED_FUNCTION) return false;
12292 DeoptimizationInputData* const data =
12293 DeoptimizationInputData::cast(code()->deoptimization_data());
12294 if (data->length() == 0) return false;
12295 FixedArray* const literals = data->LiteralArray();
12296 int const inlined_count = data->InlinedFunctionCount()->value();
12297 for (int i = 0; i < inlined_count; ++i) {
12298 if (SharedFunctionInfo::cast(literals->get(i)) == candidate) {
12299 return true;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012300 }
12301 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000012302 return false;
Steve Block791712a2010-08-27 10:21:07 +010012303}
12304
12305
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012306void JSFunction::MarkForOptimization() {
Emily Bernierd0a1eb72015-03-24 16:35:39 -040012307 Isolate* isolate = GetIsolate();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000012308 // Do not optimize if function contains break points.
12309 if (shared()->HasDebugInfo()) return;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012310 DCHECK(!IsOptimized());
12311 DCHECK(shared()->allows_lazy_compilation() ||
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000012312 !shared()->optimization_disabled());
12313 DCHECK(!shared()->HasDebugInfo());
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012314 set_code_no_write_barrier(
Emily Bernierd0a1eb72015-03-24 16:35:39 -040012315 isolate->builtins()->builtin(Builtins::kCompileOptimized));
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012316 // No write barrier required, since the builtin is part of the root set.
Ben Murdochb0fe1622011-05-05 13:52:32 +010012317}
12318
12319
Emily Bernierd0a1eb72015-03-24 16:35:39 -040012320void JSFunction::AttemptConcurrentOptimization() {
12321 Isolate* isolate = GetIsolate();
12322 if (!isolate->concurrent_recompilation_enabled() ||
12323 isolate->bootstrapper()->IsActive()) {
12324 MarkForOptimization();
12325 return;
12326 }
12327 if (isolate->concurrent_osr_enabled() &&
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000012328 isolate->optimizing_compile_dispatcher()->IsQueuedForOSR(this)) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -040012329 // Do not attempt regular recompilation if we already queued this for OSR.
12330 // TODO(yangguo): This is necessary so that we don't install optimized
12331 // code on a function that is already optimized, since OSR and regular
12332 // recompilation race. This goes away as soon as OSR becomes one-shot.
12333 return;
12334 }
Emily Bernierd0a1eb72015-03-24 16:35:39 -040012335 DCHECK(!IsInOptimizationQueue());
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012336 DCHECK(!IsOptimized());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000012337 DCHECK(shared()->allows_lazy_compilation() ||
12338 !shared()->optimization_disabled());
Emily Bernierd0a1eb72015-03-24 16:35:39 -040012339 DCHECK(isolate->concurrent_recompilation_enabled());
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012340 if (FLAG_trace_concurrent_recompilation) {
12341 PrintF(" ** Marking ");
12342 ShortPrint();
12343 PrintF(" for concurrent recompilation.\n");
Ben Murdoch3ef787d2012-04-12 10:51:47 +010012344 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012345 set_code_no_write_barrier(
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000012346 isolate->builtins()->builtin(Builtins::kCompileOptimizedConcurrent));
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012347 // No write barrier required, since the builtin is part of the root set.
Ben Murdoch3ef787d2012-04-12 10:51:47 +010012348}
12349
12350
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000012351void SharedFunctionInfo::AddSharedCodeToOptimizedCodeMap(
12352 Handle<SharedFunctionInfo> shared, Handle<Code> code) {
12353 Isolate* isolate = shared->GetIsolate();
12354 if (isolate->serializer_enabled()) return;
12355 DCHECK(code->kind() == Code::OPTIMIZED_FUNCTION);
12356 // Empty code maps are unsupported.
12357 if (!shared->OptimizedCodeMapIsCleared()) {
12358 Handle<WeakCell> cell = isolate->factory()->NewWeakCell(code);
12359 // A collection may have occured and cleared the optimized code map in the
12360 // allocation above.
12361 if (!shared->OptimizedCodeMapIsCleared()) {
12362 shared->optimized_code_map()->set(kSharedCodeIndex, *cell);
12363 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012364 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012365}
12366
12367
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000012368void SharedFunctionInfo::AddToOptimizedCodeMapInternal(
12369 Handle<SharedFunctionInfo> shared, Handle<Context> native_context,
12370 Handle<HeapObject> code, Handle<LiteralsArray> literals,
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012371 BailoutId osr_ast_id) {
12372 Isolate* isolate = shared->GetIsolate();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000012373 if (isolate->serializer_enabled()) return;
12374 DCHECK(*code == isolate->heap()->undefined_value() ||
12375 !shared->SearchOptimizedCodeMap(*native_context, osr_ast_id).code);
12376 DCHECK(*code == isolate->heap()->undefined_value() ||
12377 Code::cast(*code)->kind() == Code::OPTIMIZED_FUNCTION);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012378 DCHECK(native_context->IsNativeContext());
12379 STATIC_ASSERT(kEntryLength == 4);
12380 Handle<FixedArray> new_code_map;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000012381 int entry;
12382
12383 if (shared->OptimizedCodeMapIsCleared()) {
12384 new_code_map = isolate->factory()->NewFixedArray(kInitialLength, TENURED);
12385 new_code_map->set(kSharedCodeIndex, *isolate->factory()->empty_weak_cell(),
12386 SKIP_WRITE_BARRIER);
12387 entry = kEntriesStart;
Ben Murdoch3ef787d2012-04-12 10:51:47 +010012388 } else {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000012389 Handle<FixedArray> old_code_map(shared->optimized_code_map(), isolate);
12390 entry = shared->SearchOptimizedCodeMapEntry(*native_context, osr_ast_id);
12391 if (entry > kSharedCodeIndex) {
12392 // Found an existing context-specific entry. If the user provided valid
12393 // code, it must not contain any code.
12394 DCHECK(code->IsUndefined() ||
12395 WeakCell::cast(old_code_map->get(entry + kCachedCodeOffset))
12396 ->cleared());
12397
12398 // Just set the code and literals to the entry.
12399 if (!code->IsUndefined()) {
12400 Handle<WeakCell> code_cell = isolate->factory()->NewWeakCell(code);
12401 old_code_map->set(entry + kCachedCodeOffset, *code_cell);
12402 }
12403 Handle<WeakCell> literals_cell =
12404 isolate->factory()->NewWeakCell(literals);
12405 old_code_map->set(entry + kLiteralsOffset, *literals_cell);
12406 return;
12407 }
12408
12409 // Can we reuse an entry?
12410 DCHECK(entry < kEntriesStart);
12411 int length = old_code_map->length();
12412 for (int i = kEntriesStart; i < length; i += kEntryLength) {
12413 if (WeakCell::cast(old_code_map->get(i + kContextOffset))->cleared()) {
12414 new_code_map = old_code_map;
12415 entry = i;
12416 break;
12417 }
12418 }
12419
12420 if (entry < kEntriesStart) {
12421 // Copy old optimized code map and append one new entry.
12422 new_code_map = isolate->factory()->CopyFixedArrayAndGrow(
12423 old_code_map, kEntryLength, TENURED);
12424 // TODO(mstarzinger): Temporary workaround. The allocation above might
12425 // have flushed the optimized code map and the copy we created is full of
12426 // holes. For now we just give up on adding the entry and pretend it got
12427 // flushed.
12428 if (shared->OptimizedCodeMapIsCleared()) return;
12429 entry = old_code_map->length();
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012430 }
Ben Murdoch3ef787d2012-04-12 10:51:47 +010012431 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000012432
12433 Handle<WeakCell> code_cell = code->IsUndefined()
12434 ? isolate->factory()->empty_weak_cell()
12435 : isolate->factory()->NewWeakCell(code);
12436 Handle<WeakCell> literals_cell = isolate->factory()->NewWeakCell(literals);
12437 WeakCell* context_cell = native_context->self_weak_cell();
12438
12439 new_code_map->set(entry + kContextOffset, context_cell);
12440 new_code_map->set(entry + kCachedCodeOffset, *code_cell);
12441 new_code_map->set(entry + kLiteralsOffset, *literals_cell);
12442 new_code_map->set(entry + kOsrAstIdOffset, Smi::FromInt(osr_ast_id.ToInt()));
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012443
12444#ifdef DEBUG
12445 for (int i = kEntriesStart; i < new_code_map->length(); i += kEntryLength) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000012446 WeakCell* cell = WeakCell::cast(new_code_map->get(i + kContextOffset));
12447 DCHECK(cell->cleared() || cell->value()->IsNativeContext());
12448 cell = WeakCell::cast(new_code_map->get(i + kCachedCodeOffset));
12449 DCHECK(cell->cleared() ||
12450 (cell->value()->IsCode() &&
12451 Code::cast(cell->value())->kind() == Code::OPTIMIZED_FUNCTION));
12452 cell = WeakCell::cast(new_code_map->get(i + kLiteralsOffset));
12453 DCHECK(cell->cleared() || cell->value()->IsFixedArray());
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012454 DCHECK(new_code_map->get(i + kOsrAstIdOffset)->IsSmi());
12455 }
12456#endif
Ben Murdoch3ef787d2012-04-12 10:51:47 +010012457
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000012458 FixedArray* old_code_map = shared->optimized_code_map();
12459 if (old_code_map != *new_code_map) {
12460 shared->set_optimized_code_map(*new_code_map);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012461 }
Ben Murdochb0fe1622011-05-05 13:52:32 +010012462}
12463
12464
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012465void SharedFunctionInfo::ClearOptimizedCodeMap() {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000012466 FixedArray* cleared_map = GetHeap()->cleared_optimized_code_map();
12467 set_optimized_code_map(cleared_map, SKIP_WRITE_BARRIER);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012468}
12469
12470
12471void SharedFunctionInfo::EvictFromOptimizedCodeMap(Code* optimized_code,
12472 const char* reason) {
12473 DisallowHeapAllocation no_gc;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000012474 if (OptimizedCodeMapIsCleared()) return;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012475
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000012476 Heap* heap = GetHeap();
12477 FixedArray* code_map = optimized_code_map();
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012478 int dst = kEntriesStart;
12479 int length = code_map->length();
12480 for (int src = kEntriesStart; src < length; src += kEntryLength) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000012481 DCHECK(WeakCell::cast(code_map->get(src))->cleared() ||
12482 WeakCell::cast(code_map->get(src))->value()->IsNativeContext());
12483 if (WeakCell::cast(code_map->get(src + kCachedCodeOffset))->value() ==
12484 optimized_code) {
12485 BailoutId osr(Smi::cast(code_map->get(src + kOsrAstIdOffset))->value());
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012486 if (FLAG_trace_opt) {
12487 PrintF("[evicting entry from optimizing code map (%s) for ", reason);
12488 ShortPrint();
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012489 if (osr.IsNone()) {
12490 PrintF("]\n");
12491 } else {
12492 PrintF(" (osr ast id %d)]\n", osr.ToInt());
12493 }
12494 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000012495 if (!osr.IsNone()) {
12496 // Evict the src entry by not copying it to the dst entry.
12497 continue;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012498 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000012499 // In case of non-OSR entry just clear the code in order to proceed
12500 // sharing literals.
12501 code_map->set(src + kCachedCodeOffset, heap->empty_weak_cell(),
12502 SKIP_WRITE_BARRIER);
12503 }
12504
12505 // Keep the src entry by copying it to the dst entry.
12506 if (dst != src) {
12507 code_map->set(dst + kContextOffset, code_map->get(src + kContextOffset));
12508 code_map->set(dst + kCachedCodeOffset,
12509 code_map->get(src + kCachedCodeOffset));
12510 code_map->set(dst + kLiteralsOffset,
12511 code_map->get(src + kLiteralsOffset));
12512 code_map->set(dst + kOsrAstIdOffset,
12513 code_map->get(src + kOsrAstIdOffset));
12514 }
12515 dst += kEntryLength;
12516 }
12517 if (WeakCell::cast(code_map->get(kSharedCodeIndex))->value() ==
12518 optimized_code) {
12519 // Evict context-independent code as well.
12520 code_map->set(kSharedCodeIndex, heap->empty_weak_cell(),
12521 SKIP_WRITE_BARRIER);
12522 if (FLAG_trace_opt) {
12523 PrintF("[evicting entry from optimizing code map (%s) for ", reason);
12524 ShortPrint();
12525 PrintF(" (context-independent code)]\n");
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012526 }
12527 }
12528 if (dst != length) {
12529 // Always trim even when array is cleared because of heap verifier.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000012530 heap->RightTrimFixedArray<Heap::CONCURRENT_TO_SWEEPER>(code_map,
12531 length - dst);
12532 if (code_map->length() == kEntriesStart &&
12533 WeakCell::cast(code_map->get(kSharedCodeIndex))->cleared()) {
12534 ClearOptimizedCodeMap();
12535 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012536 }
12537}
12538
12539
12540void SharedFunctionInfo::TrimOptimizedCodeMap(int shrink_by) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000012541 FixedArray* code_map = optimized_code_map();
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012542 DCHECK(shrink_by % kEntryLength == 0);
12543 DCHECK(shrink_by <= code_map->length() - kEntriesStart);
12544 // Always trim even when array is cleared because of heap verifier.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000012545 GetHeap()->RightTrimFixedArray<Heap::SEQUENTIAL_TO_SWEEPER>(code_map,
12546 shrink_by);
12547 if (code_map->length() == kEntriesStart &&
12548 WeakCell::cast(code_map->get(kSharedCodeIndex))->cleared()) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012549 ClearOptimizedCodeMap();
12550 }
12551}
12552
12553
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000012554static void GetMinInobjectSlack(Map* map, void* data) {
12555 int slack = map->unused_property_fields();
12556 if (*reinterpret_cast<int*>(data) > slack) {
12557 *reinterpret_cast<int*>(data) = slack;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012558 }
12559}
12560
12561
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000012562static void ShrinkInstanceSize(Map* map, void* data) {
12563 int slack = *reinterpret_cast<int*>(data);
12564 map->SetInObjectProperties(map->GetInObjectProperties() - slack);
12565 map->set_unused_property_fields(map->unused_property_fields() - slack);
12566 map->set_instance_size(map->instance_size() - slack * kPointerSize);
12567
12568 // Visitor id might depend on the instance size, recalculate it.
12569 map->set_visitor_id(Heap::GetStaticVisitorIdForMap(map));
12570}
12571
12572
12573void Map::CompleteInobjectSlackTracking() {
12574 // Has to be an initial map.
12575 DCHECK(GetBackPointer()->IsUndefined());
12576
12577 set_construction_counter(kNoSlackTracking);
12578
12579 int slack = unused_property_fields();
12580 TransitionArray::TraverseTransitionTree(this, &GetMinInobjectSlack, &slack);
12581 if (slack != 0) {
12582 // Resize the initial map and all maps in its transition tree.
12583 TransitionArray::TraverseTransitionTree(this, &ShrinkInstanceSize, &slack);
12584 }
12585}
12586
12587
12588static bool PrototypeBenefitsFromNormalization(Handle<JSObject> object) {
12589 DisallowHeapAllocation no_gc;
12590 if (!object->HasFastProperties()) return false;
12591 Map* map = object->map();
12592 if (map->is_prototype_map()) return false;
12593 DescriptorArray* descriptors = map->instance_descriptors();
12594 for (int i = 0; i < map->NumberOfOwnDescriptors(); i++) {
12595 PropertyDetails details = descriptors->GetDetails(i);
12596 if (details.location() == kDescriptor) continue;
12597 if (details.representation().IsHeapObject() ||
12598 details.representation().IsTagged()) {
12599 FieldIndex index = FieldIndex::ForDescriptor(map, i);
12600 if (object->RawFastPropertyAt(index)->IsJSFunction()) return true;
12601 }
12602 }
12603 return false;
12604}
12605
12606
12607// static
12608void JSObject::OptimizeAsPrototype(Handle<JSObject> object,
12609 PrototypeOptimizationMode mode) {
12610 if (object->IsJSGlobalObject()) return;
12611 if (mode == FAST_PROTOTYPE && PrototypeBenefitsFromNormalization(object)) {
12612 // First normalize to ensure all JSFunctions are DATA_CONSTANT.
12613 JSObject::NormalizeProperties(object, KEEP_INOBJECT_PROPERTIES, 0,
12614 "NormalizeAsPrototype");
12615 }
12616 Handle<Map> previous_map(object->map());
12617 if (!object->HasFastProperties()) {
12618 JSObject::MigrateSlowToFast(object, 0, "OptimizeAsPrototype");
12619 }
12620 if (!object->map()->is_prototype_map()) {
12621 if (object->map() == *previous_map) {
12622 Handle<Map> new_map = Map::Copy(handle(object->map()), "CopyAsPrototype");
12623 JSObject::MigrateToMap(object, new_map);
12624 }
12625 object->map()->set_is_prototype_map(true);
12626
12627 // Replace the pointer to the exact constructor with the Object function
12628 // from the same context if undetectable from JS. This is to avoid keeping
12629 // memory alive unnecessarily.
12630 Object* maybe_constructor = object->map()->GetConstructor();
12631 if (maybe_constructor->IsJSFunction()) {
12632 JSFunction* constructor = JSFunction::cast(maybe_constructor);
12633 Isolate* isolate = object->GetIsolate();
12634 if (!constructor->shared()->IsApiFunction() &&
12635 object->class_name() == isolate->heap()->Object_string()) {
12636 Context* context = constructor->context()->native_context();
12637 JSFunction* object_function = context->object_function();
12638 object->map()->SetConstructor(object_function);
12639 }
12640 }
12641 }
12642}
12643
12644
12645// static
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012646void JSObject::ReoptimizeIfPrototype(Handle<JSObject> object) {
12647 if (!object->map()->is_prototype_map()) return;
12648 OptimizeAsPrototype(object, FAST_PROTOTYPE);
12649}
12650
12651
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000012652// static
12653void JSObject::LazyRegisterPrototypeUser(Handle<Map> user, Isolate* isolate) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -040012654 DCHECK(FLAG_track_prototype_users);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000012655 // Contract: In line with InvalidatePrototypeChains()'s requirements,
12656 // leaf maps don't need to register as users, only prototypes do.
12657 DCHECK(user->is_prototype_map());
Emily Bernierd0a1eb72015-03-24 16:35:39 -040012658
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000012659 Handle<Map> current_user = user;
12660 Handle<PrototypeInfo> current_user_info =
12661 Map::GetOrCreatePrototypeInfo(user, isolate);
12662 for (PrototypeIterator iter(user); !iter.IsAtEnd(); iter.Advance()) {
12663 // Walk up the prototype chain as far as links haven't been registered yet.
12664 if (current_user_info->registry_slot() != PrototypeInfo::UNREGISTERED) {
12665 break;
12666 }
12667 Handle<Object> maybe_proto = PrototypeIterator::GetCurrent(iter);
12668 // Proxies on the prototype chain are not supported. They make it
12669 // impossible to make any assumptions about the prototype chain anyway.
12670 if (maybe_proto->IsJSProxy()) return;
12671 Handle<JSObject> proto = Handle<JSObject>::cast(maybe_proto);
12672 Handle<PrototypeInfo> proto_info =
12673 Map::GetOrCreatePrototypeInfo(proto, isolate);
12674 Handle<Object> maybe_registry(proto_info->prototype_users(), isolate);
12675 int slot = 0;
12676 Handle<WeakFixedArray> new_array =
12677 WeakFixedArray::Add(maybe_registry, current_user, &slot);
12678 current_user_info->set_registry_slot(slot);
12679 if (!maybe_registry.is_identical_to(new_array)) {
12680 proto_info->set_prototype_users(*new_array);
12681 }
12682 if (FLAG_trace_prototype_users) {
12683 PrintF("Registering %p as a user of prototype %p (map=%p).\n",
12684 reinterpret_cast<void*>(*current_user),
12685 reinterpret_cast<void*>(*proto),
12686 reinterpret_cast<void*>(proto->map()));
12687 }
Emily Bernierd0a1eb72015-03-24 16:35:39 -040012688
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000012689 current_user = handle(proto->map(), isolate);
12690 current_user_info = proto_info;
Emily Bernierd0a1eb72015-03-24 16:35:39 -040012691 }
12692}
12693
12694
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000012695// Can be called regardless of whether |user| was actually registered with
12696// |prototype|. Returns true when there was a registration.
12697// static
12698bool JSObject::UnregisterPrototypeUser(Handle<Map> user, Isolate* isolate) {
12699 DCHECK(user->is_prototype_map());
12700 // If it doesn't have a PrototypeInfo, it was never registered.
12701 if (!user->prototype_info()->IsPrototypeInfo()) return false;
12702 // If it had no prototype before, see if it had users that might expect
12703 // registration.
12704 if (!user->prototype()->IsJSObject()) {
12705 Object* users =
12706 PrototypeInfo::cast(user->prototype_info())->prototype_users();
12707 return users->IsWeakFixedArray();
12708 }
12709 Handle<JSObject> prototype(JSObject::cast(user->prototype()), isolate);
12710 Handle<PrototypeInfo> user_info =
12711 Map::GetOrCreatePrototypeInfo(user, isolate);
12712 int slot = user_info->registry_slot();
12713 if (slot == PrototypeInfo::UNREGISTERED) return false;
12714 DCHECK(prototype->map()->is_prototype_map());
12715 Object* maybe_proto_info = prototype->map()->prototype_info();
12716 // User knows its registry slot, prototype info and user registry must exist.
12717 DCHECK(maybe_proto_info->IsPrototypeInfo());
12718 Handle<PrototypeInfo> proto_info(PrototypeInfo::cast(maybe_proto_info),
12719 isolate);
12720 Object* maybe_registry = proto_info->prototype_users();
12721 DCHECK(maybe_registry->IsWeakFixedArray());
12722 DCHECK(WeakFixedArray::cast(maybe_registry)->Get(slot) == *user);
12723 WeakFixedArray::cast(maybe_registry)->Clear(slot);
12724 if (FLAG_trace_prototype_users) {
12725 PrintF("Unregistering %p as a user of prototype %p.\n",
12726 reinterpret_cast<void*>(*user), reinterpret_cast<void*>(*prototype));
12727 }
12728 return true;
Emily Bernierd0a1eb72015-03-24 16:35:39 -040012729}
12730
12731
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000012732static void InvalidatePrototypeChainsInternal(Map* map) {
12733 if (!map->is_prototype_map()) return;
12734 if (FLAG_trace_prototype_users) {
12735 PrintF("Invalidating prototype map %p 's cell\n",
12736 reinterpret_cast<void*>(map));
12737 }
12738 Object* maybe_proto_info = map->prototype_info();
12739 if (!maybe_proto_info->IsPrototypeInfo()) return;
12740 PrototypeInfo* proto_info = PrototypeInfo::cast(maybe_proto_info);
12741 Object* maybe_cell = proto_info->validity_cell();
12742 if (maybe_cell->IsCell()) {
12743 // Just set the value; the cell will be replaced lazily.
12744 Cell* cell = Cell::cast(maybe_cell);
12745 cell->set_value(Smi::FromInt(Map::kPrototypeChainInvalid));
12746 }
12747
12748 WeakFixedArray::Iterator iterator(proto_info->prototype_users());
12749 // For now, only maps register themselves as users.
12750 Map* user;
12751 while ((user = iterator.Next<Map>())) {
12752 // Walk the prototype chain (backwards, towards leaf objects) if necessary.
12753 InvalidatePrototypeChainsInternal(user);
12754 }
12755}
12756
12757
12758// static
12759void JSObject::InvalidatePrototypeChains(Map* map) {
12760 if (!FLAG_eliminate_prototype_chain_checks) return;
12761 DisallowHeapAllocation no_gc;
12762 InvalidatePrototypeChainsInternal(map);
12763}
12764
12765
12766// static
12767Handle<PrototypeInfo> Map::GetOrCreatePrototypeInfo(Handle<JSObject> prototype,
12768 Isolate* isolate) {
12769 Object* maybe_proto_info = prototype->map()->prototype_info();
12770 if (maybe_proto_info->IsPrototypeInfo()) {
12771 return handle(PrototypeInfo::cast(maybe_proto_info), isolate);
12772 }
12773 Handle<PrototypeInfo> proto_info = isolate->factory()->NewPrototypeInfo();
12774 prototype->map()->set_prototype_info(*proto_info);
12775 return proto_info;
12776}
12777
12778
12779// static
12780Handle<PrototypeInfo> Map::GetOrCreatePrototypeInfo(Handle<Map> prototype_map,
12781 Isolate* isolate) {
12782 Object* maybe_proto_info = prototype_map->prototype_info();
12783 if (maybe_proto_info->IsPrototypeInfo()) {
12784 return handle(PrototypeInfo::cast(maybe_proto_info), isolate);
12785 }
12786 Handle<PrototypeInfo> proto_info = isolate->factory()->NewPrototypeInfo();
12787 prototype_map->set_prototype_info(*proto_info);
12788 return proto_info;
12789}
12790
12791
12792// static
12793Handle<Cell> Map::GetOrCreatePrototypeChainValidityCell(Handle<Map> map,
12794 Isolate* isolate) {
12795 Handle<Object> maybe_prototype(map->prototype(), isolate);
12796 if (!maybe_prototype->IsJSObject()) return Handle<Cell>::null();
12797 Handle<JSObject> prototype = Handle<JSObject>::cast(maybe_prototype);
12798 // Ensure the prototype is registered with its own prototypes so its cell
12799 // will be invalidated when necessary.
12800 JSObject::LazyRegisterPrototypeUser(handle(prototype->map(), isolate),
12801 isolate);
12802 Handle<PrototypeInfo> proto_info =
12803 GetOrCreatePrototypeInfo(prototype, isolate);
12804 Object* maybe_cell = proto_info->validity_cell();
12805 // Return existing cell if it's still valid.
12806 if (maybe_cell->IsCell()) {
12807 Handle<Cell> cell(Cell::cast(maybe_cell), isolate);
12808 if (cell->value() == Smi::FromInt(Map::kPrototypeChainValid)) {
12809 return cell;
12810 }
12811 }
12812 // Otherwise create a new cell.
12813 Handle<Cell> cell = isolate->factory()->NewCell(
12814 handle(Smi::FromInt(Map::kPrototypeChainValid), isolate));
12815 proto_info->set_validity_cell(*cell);
12816 return cell;
12817}
12818
12819
12820// static
12821void Map::SetPrototype(Handle<Map> map, Handle<Object> prototype,
Emily Bernierd0a1eb72015-03-24 16:35:39 -040012822 PrototypeOptimizationMode proto_mode) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -040012823 if (prototype->IsJSObject()) {
12824 Handle<JSObject> prototype_jsobj = Handle<JSObject>::cast(prototype);
Emily Bernierd0a1eb72015-03-24 16:35:39 -040012825 JSObject::OptimizeAsPrototype(prototype_jsobj, proto_mode);
12826 }
12827 WriteBarrierMode wb_mode =
12828 prototype->IsNull() ? SKIP_WRITE_BARRIER : UPDATE_WRITE_BARRIER;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000012829 map->set_prototype(*prototype, wb_mode);
Emily Bernierd0a1eb72015-03-24 16:35:39 -040012830}
12831
12832
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012833Handle<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.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000012837 Strength strength =
12838 initial_map->is_strong() ? Strength::STRONG : Strength::WEAK;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012839 Handle<Map> current_map = initial_map;
12840 ElementsKind kind = current_map->elements_kind();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000012841 DCHECK_EQ(GetInitialFastElementsKind(), kind);
12842 native_context->set(Context::ArrayMapIndex(kind, strength), *current_map);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012843 for (int i = GetSequenceIndexFromFastElementsKind(kind) + 1;
12844 i < kFastElementsKindCount; ++i) {
12845 Handle<Map> new_map;
12846 ElementsKind next_kind = GetFastElementsKindFromSequenceIndex(i);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000012847 if (Map* maybe_elements_transition = current_map->ElementsTransitionMap()) {
12848 new_map = handle(maybe_elements_transition);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012849 } else {
12850 new_map = Map::CopyAsElementsKind(
12851 current_map, next_kind, INSERT_TRANSITION);
12852 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000012853 DCHECK_EQ(next_kind, new_map->elements_kind());
12854 native_context->set(Context::ArrayMapIndex(next_kind, strength), *new_map);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012855 current_map = new_map;
12856 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012857 return initial_map;
12858}
12859
12860
12861void JSFunction::SetInstancePrototype(Handle<JSFunction> function,
12862 Handle<Object> value) {
12863 Isolate* isolate = function->GetIsolate();
12864
12865 DCHECK(value->IsJSReceiver());
12866
12867 // Now some logic for the maps of the objects that are created by using this
12868 // function as a constructor.
12869 if (function->has_initial_map()) {
12870 // If the function has allocated the initial map replace it with a
12871 // copy containing the new prototype. Also complete any in-object
12872 // slack tracking that is in progress at this point because it is
12873 // still tracking the old copy.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000012874 function->CompleteInobjectSlackTrackingIfActive();
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012875
12876 Handle<Map> initial_map(function->initial_map(), isolate);
12877
12878 if (!initial_map->GetIsolate()->bootstrapper()->IsActive() &&
12879 initial_map->instance_type() == JS_OBJECT_TYPE) {
12880 // Put the value in the initial map field until an initial map is needed.
12881 // At that point, a new initial map is created and the prototype is put
12882 // into the initial map where it belongs.
12883 function->set_prototype_or_initial_map(*value);
12884 } else {
Emily Bernierd0a1eb72015-03-24 16:35:39 -040012885 Handle<Map> new_map = Map::Copy(initial_map, "SetInstancePrototype");
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000012886 if (function->map()->is_strong()) {
12887 new_map->set_is_strong();
12888 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012889 JSFunction::SetInitialMap(function, new_map, value);
12890
12891 // If the function is used as the global Array function, cache the
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000012892 // updated initial maps (and transitioned versions) in the native context.
12893 Handle<Context> native_context(function->context()->native_context(),
12894 isolate);
12895 Handle<Object> array_function(
12896 native_context->get(Context::ARRAY_FUNCTION_INDEX), isolate);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012897 if (array_function->IsJSFunction() &&
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000012898 *function == JSFunction::cast(*array_function)) {
12899 CacheInitialJSArrayMaps(native_context, new_map);
12900 Handle<Map> new_strong_map = Map::Copy(new_map, "SetInstancePrototype");
12901 new_strong_map->set_is_strong();
12902 CacheInitialJSArrayMaps(native_context, new_strong_map);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012903 }
12904 }
12905
12906 // Deoptimize all code that embeds the previous initial map.
12907 initial_map->dependent_code()->DeoptimizeDependentCodeGroup(
12908 isolate, DependentCode::kInitialMapChangedGroup);
Steve Blocka7e24c12009-10-30 11:49:00 +000012909 } else {
12910 // Put the value in the initial map field until an initial map is
12911 // needed. At that point, a new initial map is created and the
12912 // prototype is put into the initial map where it belongs.
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012913 function->set_prototype_or_initial_map(*value);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000012914 if (value->IsJSObject()) {
12915 // Optimize as prototype to detach it from its transition tree.
12916 JSObject::OptimizeAsPrototype(Handle<JSObject>::cast(value),
12917 FAST_PROTOTYPE);
12918 }
Steve Blocka7e24c12009-10-30 11:49:00 +000012919 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012920 isolate->heap()->ClearInstanceofCache();
Steve Blocka7e24c12009-10-30 11:49:00 +000012921}
12922
12923
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012924void JSFunction::SetPrototype(Handle<JSFunction> function,
12925 Handle<Object> value) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000012926 DCHECK(function->IsConstructor());
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012927 Handle<Object> construct_prototype = value;
Steve Blocka7e24c12009-10-30 11:49:00 +000012928
Ben Murdoch3ef787d2012-04-12 10:51:47 +010012929 // If the value is not a JSReceiver, store the value in the map's
Steve Blocka7e24c12009-10-30 11:49:00 +000012930 // constructor field so it can be accessed. Also, set the prototype
12931 // used for constructing objects to the original object prototype.
12932 // See ECMA-262 13.2.2.
Ben Murdoch3ef787d2012-04-12 10:51:47 +010012933 if (!value->IsJSReceiver()) {
Steve Blocka7e24c12009-10-30 11:49:00 +000012934 // Copy the map so this does not affect unrelated functions.
12935 // Remove map transitions because they point to maps with a
12936 // different prototype.
Emily Bernierd0a1eb72015-03-24 16:35:39 -040012937 Handle<Map> new_map = Map::Copy(handle(function->map()), "SetPrototype");
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012938
12939 JSObject::MigrateToMap(function, new_map);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000012940 new_map->SetConstructor(*value);
Ben Murdoch8b112d22011-06-08 16:22:53 +010012941 new_map->set_non_instance_prototype(true);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012942 Isolate* isolate = new_map->GetIsolate();
12943 construct_prototype = handle(
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000012944 function->context()->native_context()->initial_object_prototype(),
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012945 isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +000012946 } else {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012947 function->map()->set_non_instance_prototype(false);
Steve Blocka7e24c12009-10-30 11:49:00 +000012948 }
12949
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012950 return SetInstancePrototype(function, construct_prototype);
Steve Blocka7e24c12009-10-30 11:49:00 +000012951}
12952
12953
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012954bool JSFunction::RemovePrototype() {
12955 Context* native_context = context()->native_context();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000012956 Map* no_prototype_map =
12957 is_strict(shared()->language_mode())
12958 ? native_context->strict_function_without_prototype_map()
12959 : native_context->sloppy_function_without_prototype_map();
Steve Block44f0eee2011-05-26 01:26:41 +010012960
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012961 if (map() == no_prototype_map) return true;
12962
12963#ifdef DEBUG
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000012964 if (map() != (is_strict(shared()->language_mode())
12965 ? native_context->strict_function_map()
12966 : native_context->sloppy_function_map())) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012967 return false;
Ben Murdoche0cee9b2011-05-25 10:26:03 +010012968 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012969#endif
Steve Block44f0eee2011-05-26 01:26:41 +010012970
12971 set_map(no_prototype_map);
Ben Murdoch3ef787d2012-04-12 10:51:47 +010012972 set_prototype_or_initial_map(no_prototype_map->GetHeap()->the_hole_value());
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012973 return true;
Steve Block6ded16b2010-05-10 14:33:55 +010012974}
12975
12976
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012977void JSFunction::SetInitialMap(Handle<JSFunction> function, Handle<Map> map,
12978 Handle<Object> prototype) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -040012979 if (map->prototype() != *prototype) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000012980 Map::SetPrototype(map, prototype, FAST_PROTOTYPE);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012981 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012982 function->set_prototype_or_initial_map(*map);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000012983 map->SetConstructor(*function);
Emily Bernierd0a1eb72015-03-24 16:35:39 -040012984#if TRACE_MAPS
12985 if (FLAG_trace_maps) {
12986 PrintF("[TraceMaps: InitialMap map= %p SFI= %d_%s ]\n",
12987 reinterpret_cast<void*>(*map), function->shared()->unique_id(),
12988 function->shared()->DebugName()->ToCString().get());
12989 }
12990#endif
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012991}
12992
12993
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000012994#ifdef DEBUG
12995namespace {
12996
12997bool CanSubclassHaveInobjectProperties(InstanceType instance_type) {
12998 switch (instance_type) {
12999 case JS_OBJECT_TYPE:
13000 case JS_CONTEXT_EXTENSION_OBJECT_TYPE:
13001 case JS_GENERATOR_OBJECT_TYPE:
13002 case JS_MODULE_TYPE:
13003 case JS_VALUE_TYPE:
13004 case JS_DATE_TYPE:
13005 case JS_ARRAY_TYPE:
13006 case JS_MESSAGE_OBJECT_TYPE:
13007 case JS_ARRAY_BUFFER_TYPE:
13008 case JS_TYPED_ARRAY_TYPE:
13009 case JS_DATA_VIEW_TYPE:
13010 case JS_SET_TYPE:
13011 case JS_MAP_TYPE:
13012 case JS_SET_ITERATOR_TYPE:
13013 case JS_MAP_ITERATOR_TYPE:
13014 case JS_ITERATOR_RESULT_TYPE:
13015 case JS_WEAK_MAP_TYPE:
13016 case JS_WEAK_SET_TYPE:
13017 case JS_PROMISE_TYPE:
13018 case JS_REGEXP_TYPE:
13019 case JS_FUNCTION_TYPE:
13020 return true;
13021
13022 case JS_BOUND_FUNCTION_TYPE:
13023 case JS_PROXY_TYPE:
13024 case JS_GLOBAL_PROXY_TYPE:
13025 case JS_GLOBAL_OBJECT_TYPE:
13026 case FIXED_ARRAY_TYPE:
13027 case FIXED_DOUBLE_ARRAY_TYPE:
13028 case ODDBALL_TYPE:
13029 case FOREIGN_TYPE:
13030 case MAP_TYPE:
13031 case CODE_TYPE:
13032 case CELL_TYPE:
13033 case PROPERTY_CELL_TYPE:
13034 case WEAK_CELL_TYPE:
13035 case SYMBOL_TYPE:
13036 case BYTECODE_ARRAY_TYPE:
13037 case HEAP_NUMBER_TYPE:
13038 case MUTABLE_HEAP_NUMBER_TYPE:
13039 case SIMD128_VALUE_TYPE:
13040 case FILLER_TYPE:
13041 case BYTE_ARRAY_TYPE:
13042 case FREE_SPACE_TYPE:
13043 case SHARED_FUNCTION_INFO_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
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013064void JSFunction::EnsureHasInitialMap(Handle<JSFunction> function) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000013065 DCHECK(function->IsConstructor() || function->shared()->is_generator());
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013066 if (function->has_initial_map()) return;
13067 Isolate* isolate = function->GetIsolate();
13068
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000013069 // The constructor should be compiled for the optimization hints to be
13070 // available.
13071 Compiler::Compile(function, CLEAR_EXCEPTION);
13072
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013073 // First create a new map with the size and number of in-object properties
13074 // suggested by the function.
13075 InstanceType instance_type;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013076 if (function->shared()->is_generator()) {
13077 instance_type = JS_GENERATOR_OBJECT_TYPE;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013078 } else {
13079 instance_type = JS_OBJECT_TYPE;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013080 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000013081 int instance_size;
13082 int in_object_properties;
13083 function->CalculateInstanceSize(instance_type, 0, &instance_size,
13084 &in_object_properties);
13085
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013086 Handle<Map> map = isolate->factory()->NewMap(instance_type, instance_size);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000013087 if (function->map()->is_strong()) {
13088 map->set_is_strong();
13089 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013090
13091 // Fetch or allocate prototype.
13092 Handle<Object> prototype;
13093 if (function->has_instance_prototype()) {
13094 prototype = handle(function->instance_prototype(), isolate);
13095 } else {
13096 prototype = isolate->factory()->NewFunctionPrototype(function);
13097 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000013098 map->SetInObjectProperties(in_object_properties);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013099 map->set_unused_property_fields(in_object_properties);
13100 DCHECK(map->has_fast_object_elements());
13101
13102 // Finally link initial map and constructor function.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000013103 DCHECK(prototype->IsJSReceiver());
13104 JSFunction::SetInitialMap(function, map, prototype);
13105 map->StartInobjectSlackTracking();
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013106}
13107
13108
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000013109// static
13110MaybeHandle<Map> JSFunction::GetDerivedMap(Isolate* isolate,
13111 Handle<JSFunction> constructor,
13112 Handle<JSReceiver> new_target) {
13113 EnsureHasInitialMap(constructor);
13114
13115 Handle<Map> constructor_initial_map(constructor->initial_map(), isolate);
13116 if (*new_target == *constructor) return constructor_initial_map;
13117
13118 // Fast case, new.target is a subclass of constructor. The map is cacheable
13119 // (and may already have been cached). new.target.prototype is guaranteed to
13120 // be a JSReceiver.
13121 if (new_target->IsJSFunction()) {
13122 Handle<JSFunction> function = Handle<JSFunction>::cast(new_target);
13123
13124 // Check that |function|'s initial map still in sync with the |constructor|,
13125 // otherwise we must create a new initial map for |function|.
13126 if (function->has_initial_map() &&
13127 function->initial_map()->GetConstructor() == *constructor) {
13128 return handle(function->initial_map(), isolate);
13129 }
13130
13131 // Create a new map with the size and number of in-object properties
13132 // suggested by |function|.
13133
13134 // Link initial map and constructor function if the new.target is actually a
13135 // subclass constructor.
13136 if (IsSubclassConstructor(function->shared()->kind())) {
13137 Handle<Object> prototype(function->instance_prototype(), isolate);
13138 InstanceType instance_type = constructor_initial_map->instance_type();
13139 DCHECK(CanSubclassHaveInobjectProperties(instance_type));
13140 int internal_fields =
13141 JSObject::GetInternalFieldCount(*constructor_initial_map);
13142 int pre_allocated = constructor_initial_map->GetInObjectProperties() -
13143 constructor_initial_map->unused_property_fields();
13144 int instance_size;
13145 int in_object_properties;
13146 function->CalculateInstanceSizeForDerivedClass(
13147 instance_type, internal_fields, &instance_size,
13148 &in_object_properties);
13149
13150 int unused_property_fields = in_object_properties - pre_allocated;
13151 Handle<Map> map =
13152 Map::CopyInitialMap(constructor_initial_map, instance_size,
13153 in_object_properties, unused_property_fields);
13154 map->set_new_target_is_base(false);
13155
13156 JSFunction::SetInitialMap(function, map, prototype);
13157 map->SetConstructor(*constructor);
13158 map->StartInobjectSlackTracking();
13159 return map;
13160 }
13161 }
13162
13163 // Slow path, new.target is either a proxy or can't cache the map.
13164 // new.target.prototype is not guaranteed to be a JSReceiver, and may need to
13165 // fall back to the intrinsicDefaultProto.
13166 Handle<Object> prototype;
13167 if (new_target->IsJSFunction()) {
13168 Handle<JSFunction> function = Handle<JSFunction>::cast(new_target);
13169 // Make sure the new.target.prototype is cached.
13170 EnsureHasInitialMap(function);
13171 prototype = handle(function->prototype(), isolate);
13172 } else {
13173 Handle<String> prototype_string = isolate->factory()->prototype_string();
13174 ASSIGN_RETURN_ON_EXCEPTION(
13175 isolate, prototype,
13176 JSReceiver::GetProperty(new_target, prototype_string), Map);
13177 // The above prototype lookup might change the constructor and its
13178 // prototype, hence we have to reload the initial map.
13179 EnsureHasInitialMap(constructor);
13180 constructor_initial_map = handle(constructor->initial_map(), isolate);
13181 }
13182
13183 // If prototype is not a JSReceiver, fetch the intrinsicDefaultProto from the
13184 // correct realm. Rather than directly fetching the .prototype, we fetch the
13185 // constructor that points to the .prototype. This relies on
13186 // constructor.prototype being FROZEN for those constructors.
13187 if (!prototype->IsJSReceiver()) {
13188 Handle<Context> context;
13189 ASSIGN_RETURN_ON_EXCEPTION(isolate, context,
13190 JSReceiver::GetFunctionRealm(new_target), Map);
13191 DCHECK(context->IsNativeContext());
13192 Handle<Object> maybe_index = JSReceiver::GetDataProperty(
13193 constructor, isolate->factory()->native_context_index_symbol());
13194 int index = maybe_index->IsSmi() ? Smi::cast(*maybe_index)->value()
13195 : Context::OBJECT_FUNCTION_INDEX;
13196 Handle<JSFunction> realm_constructor(JSFunction::cast(context->get(index)));
13197 prototype = handle(realm_constructor->prototype(), isolate);
13198 }
13199
13200 Handle<Map> map = Map::CopyInitialMap(constructor_initial_map);
13201 map->set_new_target_is_base(false);
13202 DCHECK(prototype->IsJSReceiver());
13203 if (map->prototype() != *prototype) {
13204 Map::SetPrototype(map, prototype, FAST_PROTOTYPE);
13205 }
13206 map->SetConstructor(*constructor);
13207 return map;
Steve Blocka7e24c12009-10-30 11:49:00 +000013208}
13209
13210
Ben Murdochb0fe1622011-05-05 13:52:32 +010013211void JSFunction::PrintName(FILE* out) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000013212 base::SmartArrayPointer<char> name = shared()->DebugName()->ToCString();
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013213 PrintF(out, "%s", name.get());
Ben Murdochb0fe1622011-05-05 13:52:32 +010013214}
13215
13216
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013217// The filter is a pattern that matches function names in this way:
13218// "*" all; the default
13219// "-" all but the top-level function
13220// "-name" all but the function "name"
13221// "" only the top-level function
13222// "name" only the function "name"
13223// "name*" only functions starting with "name"
13224// "~" none; the tilde is not an identifier
13225bool JSFunction::PassesFilter(const char* raw_filter) {
13226 if (*raw_filter == '*') return true;
13227 String* name = shared()->DebugName();
13228 Vector<const char> filter = CStrVector(raw_filter);
13229 if (filter.length() == 0) return name->length() == 0;
13230 if (filter[0] == '-') {
13231 // Negative filter.
13232 if (filter.length() == 1) {
13233 return (name->length() != 0);
13234 } else if (name->IsUtf8EqualTo(filter.SubVector(1, filter.length()))) {
13235 return false;
13236 }
13237 if (filter[filter.length() - 1] == '*' &&
13238 name->IsUtf8EqualTo(filter.SubVector(1, filter.length() - 1), true)) {
13239 return false;
13240 }
13241 return true;
13242
13243 } else if (name->IsUtf8EqualTo(filter)) {
13244 return true;
John Reck59135872010-11-02 12:39:01 -070013245 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013246 if (filter[filter.length() - 1] == '*' &&
13247 name->IsUtf8EqualTo(filter.SubVector(0, filter.length() - 1), true)) {
13248 return true;
13249 }
13250 return false;
13251}
13252
13253
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000013254Handle<String> JSFunction::GetName(Handle<JSFunction> function) {
13255 Isolate* isolate = function->GetIsolate();
13256 Handle<Object> name =
13257 JSReceiver::GetDataProperty(function, isolate->factory()->name_string());
13258 if (name->IsString()) return Handle<String>::cast(name);
13259 return handle(function->shared()->DebugName(), isolate);
13260}
13261
13262
13263Handle<String> JSFunction::GetDebugName(Handle<JSFunction> function) {
13264 Isolate* isolate = function->GetIsolate();
13265 Handle<Object> name = JSReceiver::GetDataProperty(
13266 function, isolate->factory()->display_name_string());
13267 if (name->IsString()) return Handle<String>::cast(name);
13268 return JSFunction::GetName(function);
13269}
13270
13271
13272namespace {
13273
13274char const kNativeCodeSource[] = "function () { [native code] }";
13275
13276
13277Handle<String> NativeCodeFunctionSourceString(
13278 Handle<SharedFunctionInfo> shared_info) {
13279 Isolate* const isolate = shared_info->GetIsolate();
13280 if (shared_info->name()->IsString()) {
13281 IncrementalStringBuilder builder(isolate);
13282 builder.AppendCString("function ");
13283 builder.AppendString(handle(String::cast(shared_info->name()), isolate));
13284 builder.AppendCString("() { [native code] }");
13285 return builder.Finish().ToHandleChecked();
13286 }
13287 return isolate->factory()->NewStringFromAsciiChecked(kNativeCodeSource);
13288}
13289
13290} // namespace
13291
13292
13293// static
13294Handle<String> JSBoundFunction::ToString(Handle<JSBoundFunction> function) {
13295 Isolate* const isolate = function->GetIsolate();
13296 return isolate->factory()->NewStringFromAsciiChecked(kNativeCodeSource);
13297}
13298
13299
13300// static
13301Handle<String> JSFunction::ToString(Handle<JSFunction> function) {
13302 Isolate* const isolate = function->GetIsolate();
13303 Handle<SharedFunctionInfo> shared_info(function->shared(), isolate);
13304
13305 // Check if {function} should hide its source code.
13306 if (!shared_info->script()->IsScript() ||
13307 Script::cast(shared_info->script())->hide_source()) {
13308 return NativeCodeFunctionSourceString(shared_info);
13309 }
13310
13311 // Check if we should print {function} as a class.
13312 Handle<Object> class_start_position = JSReceiver::GetDataProperty(
13313 function, isolate->factory()->class_start_position_symbol());
13314 if (class_start_position->IsSmi()) {
13315 Handle<Object> class_end_position = JSReceiver::GetDataProperty(
13316 function, isolate->factory()->class_end_position_symbol());
13317 Handle<String> script_source(
13318 String::cast(Script::cast(shared_info->script())->source()), isolate);
13319 return isolate->factory()->NewSubString(
13320 script_source, Handle<Smi>::cast(class_start_position)->value(),
13321 Handle<Smi>::cast(class_end_position)->value());
13322 }
13323
13324 // Check if we have source code for the {function}.
13325 if (!shared_info->HasSourceCode()) {
13326 return NativeCodeFunctionSourceString(shared_info);
13327 }
13328
13329 IncrementalStringBuilder builder(isolate);
13330 if (!shared_info->is_arrow()) {
13331 if (shared_info->is_concise_method()) {
13332 if (shared_info->is_generator()) builder.AppendCharacter('*');
13333 } else {
13334 if (shared_info->is_generator()) {
13335 builder.AppendCString("function* ");
13336 } else {
13337 builder.AppendCString("function ");
13338 }
13339 }
13340 if (shared_info->name_should_print_as_anonymous()) {
13341 builder.AppendCString("anonymous");
13342 } else {
13343 builder.AppendString(handle(String::cast(shared_info->name()), isolate));
13344 }
13345 }
13346 builder.AppendString(Handle<String>::cast(shared_info->GetSourceCode()));
13347 return builder.Finish().ToHandleChecked();
13348}
13349
13350
13351void Oddball::Initialize(Isolate* isolate, Handle<Oddball> oddball,
13352 const char* to_string, Handle<Object> to_number,
13353 const char* type_of, byte kind) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013354 Handle<String> internalized_to_string =
13355 isolate->factory()->InternalizeUtf8String(to_string);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000013356 Handle<String> internalized_type_of =
13357 isolate->factory()->InternalizeUtf8String(type_of);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013358 oddball->set_to_number(*to_number);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000013359 oddball->set_to_string(*internalized_to_string);
13360 oddball->set_type_of(*internalized_type_of);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013361 oddball->set_kind(kind);
13362}
13363
13364
13365void Script::InitLineEnds(Handle<Script> script) {
13366 if (!script->line_ends()->IsUndefined()) return;
13367
13368 Isolate* isolate = script->GetIsolate();
13369
13370 if (!script->source()->IsString()) {
13371 DCHECK(script->source()->IsUndefined());
13372 Handle<FixedArray> empty = isolate->factory()->NewFixedArray(0);
13373 script->set_line_ends(*empty);
13374 DCHECK(script->line_ends()->IsFixedArray());
13375 return;
13376 }
13377
13378 Handle<String> src(String::cast(script->source()), isolate);
13379
13380 Handle<FixedArray> array = String::CalculateLineEnds(src, true);
13381
13382 if (*array != isolate->heap()->empty_fixed_array()) {
13383 array->set_map(isolate->heap()->fixed_cow_array_map());
13384 }
13385
13386 script->set_line_ends(*array);
13387 DCHECK(script->line_ends()->IsFixedArray());
13388}
13389
13390
13391int Script::GetColumnNumber(Handle<Script> script, int code_pos) {
13392 int line_number = GetLineNumber(script, code_pos);
13393 if (line_number == -1) return -1;
13394
13395 DisallowHeapAllocation no_allocation;
13396 FixedArray* line_ends_array = FixedArray::cast(script->line_ends());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000013397 line_number = line_number - script->line_offset();
13398 if (line_number == 0) return code_pos + script->column_offset();
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013399 int prev_line_end_pos =
13400 Smi::cast(line_ends_array->get(line_number - 1))->value();
13401 return code_pos - (prev_line_end_pos + 1);
13402}
13403
13404
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000013405int Script::GetLineNumberWithArray(int code_pos) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013406 DisallowHeapAllocation no_allocation;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000013407 DCHECK(line_ends()->IsFixedArray());
13408 FixedArray* line_ends_array = FixedArray::cast(line_ends());
13409 int line_ends_len = line_ends_array->length();
13410 if (line_ends_len == 0) return -1;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013411
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000013412 if ((Smi::cast(line_ends_array->get(0)))->value() >= code_pos) {
13413 return line_offset();
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013414 }
13415
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000013416 int left = 0;
13417 int right = line_ends_len;
13418 while (int half = (right - left) / 2) {
13419 if ((Smi::cast(line_ends_array->get(left + half)))->value() > code_pos) {
13420 right -= half;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013421 } else {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000013422 left += half;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013423 }
13424 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000013425 return right + line_offset();
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013426}
13427
13428
13429int Script::GetLineNumber(Handle<Script> script, int code_pos) {
13430 InitLineEnds(script);
13431 return script->GetLineNumberWithArray(code_pos);
13432}
13433
13434
13435int Script::GetLineNumber(int code_pos) {
13436 DisallowHeapAllocation no_allocation;
13437 if (!line_ends()->IsUndefined()) return GetLineNumberWithArray(code_pos);
13438
13439 // Slow mode: we do not have line_ends. We have to iterate through source.
13440 if (!source()->IsString()) return -1;
13441
13442 String* source_string = String::cast(source());
13443 int line = 0;
13444 int len = source_string->length();
13445 for (int pos = 0; pos < len; pos++) {
13446 if (pos == code_pos) break;
13447 if (source_string->Get(pos) == '\n') line++;
13448 }
13449 return line;
13450}
13451
13452
13453Handle<Object> Script::GetNameOrSourceURL(Handle<Script> script) {
13454 Isolate* isolate = script->GetIsolate();
13455 Handle<String> name_or_source_url_key =
13456 isolate->factory()->InternalizeOneByteString(
13457 STATIC_CHAR_VECTOR("nameOrSourceURL"));
13458 Handle<JSObject> script_wrapper = Script::GetWrapper(script);
13459 Handle<Object> property = Object::GetProperty(
13460 script_wrapper, name_or_source_url_key).ToHandleChecked();
13461 DCHECK(property->IsJSFunction());
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013462 Handle<Object> result;
13463 // Do not check against pending exception, since this function may be called
13464 // when an exception has already been pending.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000013465 if (!Execution::TryCall(isolate, property, script_wrapper, 0, NULL)
13466 .ToHandle(&result)) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013467 return isolate->factory()->undefined_value();
13468 }
13469 return result;
13470}
13471
13472
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013473Handle<JSObject> Script::GetWrapper(Handle<Script> script) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013474 Isolate* isolate = script->GetIsolate();
Emily Bernierd0a1eb72015-03-24 16:35:39 -040013475 if (!script->wrapper()->IsUndefined()) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000013476 DCHECK(script->wrapper()->IsWeakCell());
Emily Bernierd0a1eb72015-03-24 16:35:39 -040013477 Handle<WeakCell> cell(WeakCell::cast(script->wrapper()));
13478 if (!cell->cleared()) {
13479 // Return a handle for the existing script wrapper from the cache.
13480 return handle(JSObject::cast(cell->value()));
13481 }
13482 // If we found an empty WeakCell, that means the script wrapper was
13483 // GCed. We are not notified directly of that, so we decrement here
13484 // so that we at least don't count double for any given script.
13485 isolate->counters()->script_wrappers()->Decrement();
13486 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013487 // Construct a new script wrapper.
13488 isolate->counters()->script_wrappers()->Increment();
13489 Handle<JSFunction> constructor = isolate->script_function();
13490 Handle<JSValue> result =
13491 Handle<JSValue>::cast(isolate->factory()->NewJSObject(constructor));
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013492 result->set_value(*script);
Emily Bernierd0a1eb72015-03-24 16:35:39 -040013493 Handle<WeakCell> cell = isolate->factory()->NewWeakCell(result);
13494 script->set_wrapper(*cell);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013495 return result;
Steve Blocka7e24c12009-10-30 11:49:00 +000013496}
13497
13498
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000013499MaybeHandle<SharedFunctionInfo> Script::FindSharedFunctionInfo(
13500 FunctionLiteral* fun) {
13501 WeakFixedArray::Iterator iterator(shared_function_infos());
13502 SharedFunctionInfo* shared;
13503 while ((shared = iterator.Next<SharedFunctionInfo>())) {
13504 if (fun->function_token_position() == shared->function_token_position() &&
13505 fun->start_position() == shared->start_position()) {
13506 return Handle<SharedFunctionInfo>(shared);
13507 }
13508 }
13509 return MaybeHandle<SharedFunctionInfo>();
13510}
13511
13512
13513Script::Iterator::Iterator(Isolate* isolate)
13514 : iterator_(isolate->heap()->script_list()) {}
13515
13516
13517Script* Script::Iterator::Next() { return iterator_.Next<Script>(); }
13518
13519
13520SharedFunctionInfo::Iterator::Iterator(Isolate* isolate)
13521 : script_iterator_(isolate),
13522 sfi_iterator_(isolate->heap()->noscript_shared_function_infos()) {}
13523
13524
13525bool SharedFunctionInfo::Iterator::NextScript() {
13526 Script* script = script_iterator_.Next();
13527 if (script == NULL) return false;
13528 sfi_iterator_.Reset(script->shared_function_infos());
13529 return true;
13530}
13531
13532
13533SharedFunctionInfo* SharedFunctionInfo::Iterator::Next() {
13534 do {
13535 SharedFunctionInfo* next = sfi_iterator_.Next<SharedFunctionInfo>();
13536 if (next != NULL) return next;
13537 } while (NextScript());
13538 return NULL;
13539}
13540
13541
13542void SharedFunctionInfo::SetScript(Handle<SharedFunctionInfo> shared,
13543 Handle<Object> script_object) {
13544 if (shared->script() == *script_object) return;
13545 Isolate* isolate = shared->GetIsolate();
13546
13547 // Add shared function info to new script's list. If a collection occurs,
13548 // the shared function info may be temporarily in two lists.
13549 // This is okay because the gc-time processing of these lists can tolerate
13550 // duplicates.
13551 Handle<Object> list;
13552 if (script_object->IsScript()) {
13553 Handle<Script> script = Handle<Script>::cast(script_object);
13554 list = handle(script->shared_function_infos(), isolate);
13555 } else {
13556 list = isolate->factory()->noscript_shared_function_infos();
13557 }
13558
13559#ifdef DEBUG
13560 {
13561 WeakFixedArray::Iterator iterator(*list);
13562 SharedFunctionInfo* next;
13563 while ((next = iterator.Next<SharedFunctionInfo>())) {
13564 DCHECK_NE(next, *shared);
13565 }
13566 }
13567#endif // DEBUG
13568 list = WeakFixedArray::Add(list, shared);
13569
13570 if (script_object->IsScript()) {
13571 Handle<Script> script = Handle<Script>::cast(script_object);
13572 script->set_shared_function_infos(*list);
13573 } else {
13574 isolate->heap()->SetRootNoScriptSharedFunctionInfos(*list);
13575 }
13576
13577 // Remove shared function info from old script's list.
13578 if (shared->script()->IsScript()) {
13579 Script* old_script = Script::cast(shared->script());
13580 if (old_script->shared_function_infos()->IsWeakFixedArray()) {
13581 WeakFixedArray* list =
13582 WeakFixedArray::cast(old_script->shared_function_infos());
13583 list->Remove(shared);
13584 }
13585 } else {
13586 // Remove shared function info from root array.
13587 Object* list = isolate->heap()->noscript_shared_function_infos();
13588 CHECK(WeakFixedArray::cast(list)->Remove(shared));
13589 }
13590
13591 // Finally set new script.
13592 shared->set_script(*script_object);
13593}
13594
13595
Ben Murdochf87a2032010-10-22 12:50:53 +010013596String* SharedFunctionInfo::DebugName() {
13597 Object* n = name();
13598 if (!n->IsString() || String::cast(n)->length() == 0) return inferred_name();
13599 return String::cast(n);
13600}
13601
13602
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013603bool SharedFunctionInfo::HasSourceCode() const {
Steve Blocka7e24c12009-10-30 11:49:00 +000013604 return !script()->IsUndefined() &&
Iain Merrick75681382010-08-19 15:07:18 +010013605 !reinterpret_cast<Script*>(script())->source()->IsUndefined();
Steve Blocka7e24c12009-10-30 11:49:00 +000013606}
13607
13608
Ben Murdoch3ef787d2012-04-12 10:51:47 +010013609Handle<Object> SharedFunctionInfo::GetSourceCode() {
13610 if (!HasSourceCode()) return GetIsolate()->factory()->undefined_value();
13611 Handle<String> source(String::cast(Script::cast(script())->source()));
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013612 return GetIsolate()->factory()->NewSubString(
13613 source, start_position(), end_position());
13614}
13615
13616
13617bool SharedFunctionInfo::IsInlineable() {
13618 // Check that the function has a script associated with it.
13619 if (!script()->IsScript()) return false;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000013620 return !optimization_disabled();
Steve Blocka7e24c12009-10-30 11:49:00 +000013621}
13622
13623
Ben Murdochb0fe1622011-05-05 13:52:32 +010013624int SharedFunctionInfo::SourceSize() {
13625 return end_position() - start_position();
13626}
13627
13628
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000013629namespace {
13630
13631void CalculateInstanceSizeHelper(InstanceType instance_type,
13632 int requested_internal_fields,
13633 int requested_in_object_properties,
13634 int* instance_size,
13635 int* in_object_properties) {
13636 int header_size = JSObject::GetHeaderSize(instance_type);
13637 DCHECK_LE(requested_internal_fields,
13638 (JSObject::kMaxInstanceSize - header_size) >> kPointerSizeLog2);
13639 *instance_size =
13640 Min(header_size +
13641 ((requested_internal_fields + requested_in_object_properties)
13642 << kPointerSizeLog2),
13643 JSObject::kMaxInstanceSize);
13644 *in_object_properties = ((*instance_size - header_size) >> kPointerSizeLog2) -
13645 requested_internal_fields;
13646}
13647
13648} // namespace
13649
13650
13651void JSFunction::CalculateInstanceSize(InstanceType instance_type,
13652 int requested_internal_fields,
13653 int* instance_size,
13654 int* in_object_properties) {
13655 CalculateInstanceSizeHelper(instance_type, requested_internal_fields,
13656 shared()->expected_nof_properties(),
13657 instance_size, in_object_properties);
Steve Blocka7e24c12009-10-30 11:49:00 +000013658}
13659
13660
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000013661void JSFunction::CalculateInstanceSizeForDerivedClass(
13662 InstanceType instance_type, int requested_internal_fields,
13663 int* instance_size, int* in_object_properties) {
13664 Isolate* isolate = GetIsolate();
13665 int expected_nof_properties = 0;
13666 for (PrototypeIterator iter(isolate, this,
13667 PrototypeIterator::START_AT_RECEIVER);
13668 !iter.IsAtEnd(); iter.Advance()) {
13669 JSFunction* func = iter.GetCurrent<JSFunction>();
13670 SharedFunctionInfo* shared = func->shared();
13671 expected_nof_properties += shared->expected_nof_properties();
13672 if (!IsSubclassConstructor(shared->kind())) {
13673 break;
13674 }
13675 }
13676 CalculateInstanceSizeHelper(instance_type, requested_internal_fields,
13677 expected_nof_properties, instance_size,
13678 in_object_properties);
Steve Blocka7e24c12009-10-30 11:49:00 +000013679}
13680
13681
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013682// Output the source code without any allocation in the heap.
Emily Bernierd0a1eb72015-03-24 16:35:39 -040013683std::ostream& operator<<(std::ostream& os, const SourceCodeOf& v) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013684 const SharedFunctionInfo* s = v.value;
Steve Blocka7e24c12009-10-30 11:49:00 +000013685 // For some native functions there is no source.
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013686 if (!s->HasSourceCode()) return os << "<No Source>";
Steve Blocka7e24c12009-10-30 11:49:00 +000013687
Steve Blockd0582a62009-12-15 09:54:21 +000013688 // Get the source for the script which this function came from.
Steve Blocka7e24c12009-10-30 11:49:00 +000013689 // Don't use String::cast because we don't want more assertion errors while
13690 // we are already creating a stack dump.
13691 String* script_source =
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013692 reinterpret_cast<String*>(Script::cast(s->script())->source());
Steve Blocka7e24c12009-10-30 11:49:00 +000013693
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013694 if (!script_source->LooksValid()) return os << "<Invalid Source>";
Steve Blocka7e24c12009-10-30 11:49:00 +000013695
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013696 if (!s->is_toplevel()) {
13697 os << "function ";
13698 Object* name = s->name();
Steve Blocka7e24c12009-10-30 11:49:00 +000013699 if (name->IsString() && String::cast(name)->length() > 0) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013700 String::cast(name)->PrintUC16(os);
Steve Blocka7e24c12009-10-30 11:49:00 +000013701 }
13702 }
13703
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013704 int len = s->end_position() - s->start_position();
13705 if (len <= v.max_length || v.max_length < 0) {
13706 script_source->PrintUC16(os, s->start_position(), s->end_position());
13707 return os;
Ben Murdochb0fe1622011-05-05 13:52:32 +010013708 } else {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013709 script_source->PrintUC16(os, s->start_position(),
13710 s->start_position() + v.max_length);
13711 return os << "...\n";
Steve Blocka7e24c12009-10-30 11:49:00 +000013712 }
13713}
13714
13715
Ben Murdochb0fe1622011-05-05 13:52:32 +010013716static bool IsCodeEquivalent(Code* code, Code* recompiled) {
13717 if (code->instruction_size() != recompiled->instruction_size()) return false;
13718 ByteArray* code_relocation = code->relocation_info();
13719 ByteArray* recompiled_relocation = recompiled->relocation_info();
13720 int length = code_relocation->length();
13721 if (length != recompiled_relocation->length()) return false;
13722 int compare = memcmp(code_relocation->GetDataStartAddress(),
13723 recompiled_relocation->GetDataStartAddress(),
13724 length);
13725 return compare == 0;
13726}
13727
13728
13729void SharedFunctionInfo::EnableDeoptimizationSupport(Code* recompiled) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013730 DCHECK(!has_deoptimization_support());
13731 DisallowHeapAllocation no_allocation;
Ben Murdochb0fe1622011-05-05 13:52:32 +010013732 Code* code = this->code();
13733 if (IsCodeEquivalent(code, recompiled)) {
13734 // Copy the deoptimization data from the recompiled code.
13735 code->set_deoptimization_data(recompiled->deoptimization_data());
13736 code->set_has_deoptimization_support(true);
13737 } else {
13738 // TODO(3025757): In case the recompiled isn't equivalent to the
13739 // old code, we have to replace it. We should try to avoid this
13740 // altogether because it flushes valuable type feedback by
13741 // effectively resetting all IC state.
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013742 ReplaceCode(recompiled);
Ben Murdochb0fe1622011-05-05 13:52:32 +010013743 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013744 DCHECK(has_deoptimization_support());
Ben Murdochb0fe1622011-05-05 13:52:32 +010013745}
13746
13747
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013748void SharedFunctionInfo::DisableOptimization(BailoutReason reason) {
Ben Murdoch257744e2011-11-30 15:57:28 +000013749 // Disable optimization for the shared function info and mark the
13750 // code as non-optimizable. The marker on the shared function info
13751 // is there because we flush non-optimized code thereby loosing the
13752 // non-optimizable information for the code. When the code is
13753 // regenerated and set on the shared function info it is marked as
13754 // non-optimizable if optimization is disabled for the shared
13755 // function info.
Emily Bernierd0a1eb72015-03-24 16:35:39 -040013756 DCHECK(reason != kNoReason);
Ben Murdoch257744e2011-11-30 15:57:28 +000013757 set_optimization_disabled(true);
Emily Bernierd0a1eb72015-03-24 16:35:39 -040013758 set_disable_optimization_reason(reason);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000013759 // Code should be the lazy compilation stub or else unoptimized.
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013760 DCHECK(code()->kind() == Code::FUNCTION || code()->kind() == Code::BUILTIN);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013761 PROFILE(GetIsolate(), CodeDisableOptEvent(code(), this));
Ben Murdoch257744e2011-11-30 15:57:28 +000013762 if (FLAG_trace_opt) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013763 PrintF("[disabled optimization for ");
13764 ShortPrint();
13765 PrintF(", reason: %s]\n", GetBailoutReason(reason));
Ben Murdoch257744e2011-11-30 15:57:28 +000013766 }
13767}
13768
13769
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000013770void SharedFunctionInfo::InitFromFunctionLiteral(
13771 Handle<SharedFunctionInfo> shared_info, FunctionLiteral* lit) {
13772 shared_info->set_length(lit->scope()->default_function_length());
13773 shared_info->set_internal_formal_parameter_count(lit->parameter_count());
13774 shared_info->set_function_token_position(lit->function_token_position());
13775 shared_info->set_start_position(lit->start_position());
13776 shared_info->set_end_position(lit->end_position());
13777 shared_info->set_is_expression(lit->is_expression());
13778 shared_info->set_is_anonymous(lit->is_anonymous());
13779 shared_info->set_inferred_name(*lit->inferred_name());
13780 shared_info->set_allows_lazy_compilation(lit->AllowsLazyCompilation());
13781 shared_info->set_allows_lazy_compilation_without_context(
13782 lit->AllowsLazyCompilationWithoutContext());
13783 shared_info->set_language_mode(lit->language_mode());
13784 shared_info->set_uses_arguments(lit->scope()->arguments() != NULL);
13785 shared_info->set_has_duplicate_parameters(lit->has_duplicate_parameters());
13786 shared_info->set_ast_node_count(lit->ast_node_count());
13787 shared_info->set_is_function(lit->is_function());
13788 if (lit->dont_optimize_reason() != kNoReason) {
13789 shared_info->DisableOptimization(lit->dont_optimize_reason());
13790 }
13791 shared_info->set_dont_crankshaft(lit->flags() &
13792 AstProperties::kDontCrankshaft);
13793 shared_info->set_kind(lit->kind());
13794 if (!IsConstructable(lit->kind(), lit->language_mode())) {
13795 shared_info->set_construct_stub(
13796 *shared_info->GetIsolate()->builtins()->ConstructedNonConstructable());
13797 }
13798 shared_info->set_needs_home_object(lit->scope()->NeedsHomeObject());
13799 shared_info->set_asm_function(lit->scope()->asm_function());
13800}
13801
13802
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013803bool SharedFunctionInfo::VerifyBailoutId(BailoutId id) {
13804 DCHECK(!id.IsNone());
Ben Murdochb0fe1622011-05-05 13:52:32 +010013805 Code* unoptimized = code();
13806 DeoptimizationOutputData* data =
13807 DeoptimizationOutputData::cast(unoptimized->deoptimization_data());
13808 unsigned ignore = Deoptimizer::GetOutputInfo(data, id, this);
13809 USE(ignore);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013810 return true; // Return true if there was no DCHECK.
Ben Murdochb0fe1622011-05-05 13:52:32 +010013811}
13812
13813
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000013814void Map::StartInobjectSlackTracking() {
13815 DCHECK(!IsInobjectSlackTrackingInProgress());
Ben Murdoch3ef787d2012-04-12 10:51:47 +010013816
Kristian Monsen0d5e1162010-09-30 15:31:59 +010013817 // No tracking during the snapshot construction phase.
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013818 Isolate* isolate = GetIsolate();
13819 if (isolate->serializer_enabled()) return;
Kristian Monsen0d5e1162010-09-30 15:31:59 +010013820
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000013821 if (unused_property_fields() == 0) return;
Kristian Monsen0d5e1162010-09-30 15:31:59 +010013822
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000013823 set_construction_counter(Map::kSlackTrackingCounterStart);
Kristian Monsen0d5e1162010-09-30 15:31:59 +010013824}
13825
13826
Ben Murdoch8f9999f2012-04-23 10:39:17 +010013827void SharedFunctionInfo::ResetForNewContext(int new_ic_age) {
13828 code()->ClearInlineCaches();
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013829 // If we clear ICs, we need to clear the type feedback vector too, since
13830 // CallICs are synced with a feedback vector slot.
13831 ClearTypeFeedbackInfo();
Ben Murdoch8f9999f2012-04-23 10:39:17 +010013832 set_ic_age(new_ic_age);
13833 if (code()->kind() == Code::FUNCTION) {
13834 code()->set_profiler_ticks(0);
13835 if (optimization_disabled() &&
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013836 opt_count() >= FLAG_max_opt_count) {
Ben Murdoch8f9999f2012-04-23 10:39:17 +010013837 // Re-enable optimizations if they were disabled due to opt_count limit.
13838 set_optimization_disabled(false);
Ben Murdoch8f9999f2012-04-23 10:39:17 +010013839 }
13840 set_opt_count(0);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013841 set_deopt_count(0);
Ben Murdoch8f9999f2012-04-23 10:39:17 +010013842 }
13843}
13844
13845
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000013846int SharedFunctionInfo::SearchOptimizedCodeMapEntry(Context* native_context,
13847 BailoutId osr_ast_id) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013848 DisallowHeapAllocation no_gc;
13849 DCHECK(native_context->IsNativeContext());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000013850 if (!OptimizedCodeMapIsCleared()) {
13851 FixedArray* optimized_code_map = this->optimized_code_map();
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013852 int length = optimized_code_map->length();
13853 Smi* osr_ast_id_smi = Smi::FromInt(osr_ast_id.ToInt());
13854 for (int i = kEntriesStart; i < length; i += kEntryLength) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000013855 if (WeakCell::cast(optimized_code_map->get(i + kContextOffset))
13856 ->value() == native_context &&
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013857 optimized_code_map->get(i + kOsrAstIdOffset) == osr_ast_id_smi) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000013858 return i;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013859 }
13860 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000013861 Object* shared_code =
13862 WeakCell::cast(optimized_code_map->get(kSharedCodeIndex))->value();
13863 if (shared_code->IsCode() && osr_ast_id.IsNone()) {
13864 return kSharedCodeIndex;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013865 }
13866 }
13867 return -1;
Ben Murdoch8f9999f2012-04-23 10:39:17 +010013868}
13869
13870
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000013871CodeAndLiterals SharedFunctionInfo::SearchOptimizedCodeMap(
13872 Context* native_context, BailoutId osr_ast_id) {
13873 CodeAndLiterals result = {nullptr, nullptr};
13874 int entry = SearchOptimizedCodeMapEntry(native_context, osr_ast_id);
13875 if (entry != kNotFound) {
13876 FixedArray* code_map = optimized_code_map();
13877 if (entry == kSharedCodeIndex) {
13878 // We know the weak cell isn't cleared because we made sure of it in
13879 // SearchOptimizedCodeMapEntry and performed no allocations since that
13880 // call.
13881 result = {
13882 Code::cast(WeakCell::cast(code_map->get(kSharedCodeIndex))->value()),
13883 nullptr};
13884 } else {
13885 DCHECK_LE(entry + kEntryLength, code_map->length());
13886 WeakCell* cell = WeakCell::cast(code_map->get(entry + kCachedCodeOffset));
13887 WeakCell* literals_cell =
13888 WeakCell::cast(code_map->get(entry + kLiteralsOffset));
13889
13890 result = {cell->cleared() ? nullptr : Code::cast(cell->value()),
13891 literals_cell->cleared()
13892 ? nullptr
13893 : LiteralsArray::cast(literals_cell->value())};
13894 }
13895 }
13896 if (FLAG_trace_opt && !OptimizedCodeMapIsCleared() &&
13897 result.code == nullptr) {
13898 PrintF("[didn't find optimized code in optimized code map for ");
13899 ShortPrint();
13900 PrintF("]\n");
13901 }
13902 return result;
13903}
13904
13905
Ben Murdoch3ef787d2012-04-12 10:51:47 +010013906#define DECLARE_TAG(ignore1, name, ignore2) name,
13907const char* const VisitorSynchronization::kTags[
13908 VisitorSynchronization::kNumberOfSyncTags] = {
13909 VISITOR_SYNCHRONIZATION_TAGS_LIST(DECLARE_TAG)
13910};
13911#undef DECLARE_TAG
13912
13913
13914#define DECLARE_TAG(ignore1, ignore2, name) name,
13915const char* const VisitorSynchronization::kTagNames[
13916 VisitorSynchronization::kNumberOfSyncTags] = {
13917 VISITOR_SYNCHRONIZATION_TAGS_LIST(DECLARE_TAG)
13918};
13919#undef DECLARE_TAG
13920
13921
Steve Blocka7e24c12009-10-30 11:49:00 +000013922void ObjectVisitor::VisitCodeTarget(RelocInfo* rinfo) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013923 DCHECK(RelocInfo::IsCodeTarget(rinfo->rmode()));
Steve Blocka7e24c12009-10-30 11:49:00 +000013924 Object* target = Code::GetCodeFromTargetAddress(rinfo->target_address());
13925 Object* old_target = target;
13926 VisitPointer(&target);
13927 CHECK_EQ(target, old_target); // VisitPointer doesn't change Code* *target.
13928}
13929
13930
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013931void ObjectVisitor::VisitCodeAgeSequence(RelocInfo* rinfo) {
13932 DCHECK(RelocInfo::IsCodeAgeSequence(rinfo->rmode()));
13933 Object* stub = rinfo->code_age_stub();
13934 if (stub) {
13935 VisitPointer(&stub);
13936 }
13937}
13938
13939
Steve Block791712a2010-08-27 10:21:07 +010013940void ObjectVisitor::VisitCodeEntry(Address entry_address) {
13941 Object* code = Code::GetObjectFromEntryAddress(entry_address);
13942 Object* old_code = code;
13943 VisitPointer(&code);
13944 if (code != old_code) {
13945 Memory::Address_at(entry_address) = reinterpret_cast<Code*>(code)->entry();
13946 }
13947}
13948
13949
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013950void ObjectVisitor::VisitCell(RelocInfo* rinfo) {
13951 DCHECK(rinfo->rmode() == RelocInfo::CELL);
Ben Murdochb0fe1622011-05-05 13:52:32 +010013952 Object* cell = rinfo->target_cell();
13953 Object* old_cell = cell;
13954 VisitPointer(&cell);
13955 if (cell != old_cell) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013956 rinfo->set_target_cell(reinterpret_cast<Cell*>(cell));
Ben Murdochb0fe1622011-05-05 13:52:32 +010013957 }
13958}
13959
13960
Steve Blocka7e24c12009-10-30 11:49:00 +000013961void ObjectVisitor::VisitDebugTarget(RelocInfo* rinfo) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000013962 DCHECK(RelocInfo::IsDebugBreakSlot(rinfo->rmode()) &&
13963 rinfo->IsPatchedDebugBreakSlotSequence());
13964 Object* target = Code::GetCodeFromTargetAddress(rinfo->debug_call_address());
Steve Blocka7e24c12009-10-30 11:49:00 +000013965 Object* old_target = target;
13966 VisitPointer(&target);
13967 CHECK_EQ(target, old_target); // VisitPointer doesn't change Code* *target.
13968}
13969
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013970
Ben Murdoch3ef787d2012-04-12 10:51:47 +010013971void ObjectVisitor::VisitEmbeddedPointer(RelocInfo* rinfo) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013972 DCHECK(rinfo->rmode() == RelocInfo::EMBEDDED_OBJECT);
13973 Object* p = rinfo->target_object();
13974 VisitPointer(&p);
Ben Murdoch3ef787d2012-04-12 10:51:47 +010013975}
13976
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013977
Ben Murdoch3ef787d2012-04-12 10:51:47 +010013978void ObjectVisitor::VisitExternalReference(RelocInfo* rinfo) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000013979 Address p = rinfo->target_external_reference();
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013980 VisitExternalReference(&p);
Ben Murdoch3ef787d2012-04-12 10:51:47 +010013981}
13982
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013983
Ben Murdochb0fe1622011-05-05 13:52:32 +010013984void Code::InvalidateRelocation() {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013985 InvalidateEmbeddedObjects();
Ben Murdoch3ef787d2012-04-12 10:51:47 +010013986 set_relocation_info(GetHeap()->empty_byte_array());
Ben Murdochb0fe1622011-05-05 13:52:32 +010013987}
13988
13989
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013990void Code::InvalidateEmbeddedObjects() {
13991 Object* undefined = GetHeap()->undefined_value();
13992 Cell* undefined_cell = GetHeap()->undefined_cell();
13993 int mode_mask = RelocInfo::ModeMask(RelocInfo::EMBEDDED_OBJECT) |
13994 RelocInfo::ModeMask(RelocInfo::CELL);
13995 for (RelocIterator it(this, mode_mask); !it.done(); it.next()) {
13996 RelocInfo::Mode mode = it.rinfo()->rmode();
13997 if (mode == RelocInfo::EMBEDDED_OBJECT) {
13998 it.rinfo()->set_target_object(undefined, SKIP_WRITE_BARRIER);
13999 } else if (mode == RelocInfo::CELL) {
14000 it.rinfo()->set_target_cell(undefined_cell, SKIP_WRITE_BARRIER);
14001 }
14002 }
14003}
14004
14005
Steve Blockd0582a62009-12-15 09:54:21 +000014006void Code::Relocate(intptr_t delta) {
Steve Blocka7e24c12009-10-30 11:49:00 +000014007 for (RelocIterator it(this, RelocInfo::kApplyMask); !it.done(); it.next()) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000014008 it.rinfo()->apply(delta);
Steve Blocka7e24c12009-10-30 11:49:00 +000014009 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000014010 Assembler::FlushICache(GetIsolate(), instruction_start(), instruction_size());
Steve Blocka7e24c12009-10-30 11:49:00 +000014011}
14012
14013
14014void Code::CopyFrom(const CodeDesc& desc) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014015 DCHECK(Marking::Color(this) == Marking::WHITE_OBJECT);
Ben Murdoch3ef787d2012-04-12 10:51:47 +010014016
Steve Blocka7e24c12009-10-30 11:49:00 +000014017 // copy code
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014018 CopyBytes(instruction_start(), desc.buffer,
14019 static_cast<size_t>(desc.instr_size));
Steve Blocka7e24c12009-10-30 11:49:00 +000014020
Steve Blocka7e24c12009-10-30 11:49:00 +000014021 // copy reloc info
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014022 CopyBytes(relocation_start(),
14023 desc.buffer + desc.buffer_size - desc.reloc_size,
14024 static_cast<size_t>(desc.reloc_size));
Steve Blocka7e24c12009-10-30 11:49:00 +000014025
14026 // unbox handles and relocate
Steve Block3ce2e202009-11-05 08:53:23 +000014027 intptr_t delta = instruction_start() - desc.buffer;
Steve Blocka7e24c12009-10-30 11:49:00 +000014028 int mode_mask = RelocInfo::kCodeTargetMask |
14029 RelocInfo::ModeMask(RelocInfo::EMBEDDED_OBJECT) |
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014030 RelocInfo::ModeMask(RelocInfo::CELL) |
14031 RelocInfo::ModeMask(RelocInfo::RUNTIME_ENTRY) |
Steve Blocka7e24c12009-10-30 11:49:00 +000014032 RelocInfo::kApplyMask;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014033 // Needed to find target_object and runtime_entry on X64
14034 Assembler* origin = desc.origin;
14035 AllowDeferredHandleDereference embedding_raw_address;
Steve Blocka7e24c12009-10-30 11:49:00 +000014036 for (RelocIterator it(this, mode_mask); !it.done(); it.next()) {
14037 RelocInfo::Mode mode = it.rinfo()->rmode();
14038 if (mode == RelocInfo::EMBEDDED_OBJECT) {
Steve Block3ce2e202009-11-05 08:53:23 +000014039 Handle<Object> p = it.rinfo()->target_object_handle(origin);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014040 it.rinfo()->set_target_object(*p, SKIP_WRITE_BARRIER, SKIP_ICACHE_FLUSH);
14041 } else if (mode == RelocInfo::CELL) {
14042 Handle<Cell> cell = it.rinfo()->target_cell_handle();
14043 it.rinfo()->set_target_cell(*cell, SKIP_WRITE_BARRIER, SKIP_ICACHE_FLUSH);
Steve Blocka7e24c12009-10-30 11:49:00 +000014044 } else if (RelocInfo::IsCodeTarget(mode)) {
14045 // rewrite code handles in inline cache targets to direct
14046 // pointers to the first instruction in the code object
Steve Block3ce2e202009-11-05 08:53:23 +000014047 Handle<Object> p = it.rinfo()->target_object_handle(origin);
Steve Blocka7e24c12009-10-30 11:49:00 +000014048 Code* code = Code::cast(*p);
Ben Murdoch3ef787d2012-04-12 10:51:47 +010014049 it.rinfo()->set_target_address(code->instruction_start(),
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014050 SKIP_WRITE_BARRIER,
14051 SKIP_ICACHE_FLUSH);
14052 } else if (RelocInfo::IsRuntimeEntry(mode)) {
14053 Address p = it.rinfo()->target_runtime_entry(origin);
14054 it.rinfo()->set_target_runtime_entry(p, SKIP_WRITE_BARRIER,
14055 SKIP_ICACHE_FLUSH);
14056 } else if (mode == RelocInfo::CODE_AGE_SEQUENCE) {
14057 Handle<Object> p = it.rinfo()->code_age_stub_handle(origin);
14058 Code* code = Code::cast(*p);
14059 it.rinfo()->set_code_age_stub(code, SKIP_ICACHE_FLUSH);
Steve Blocka7e24c12009-10-30 11:49:00 +000014060 } else {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000014061 it.rinfo()->apply(delta);
Steve Blocka7e24c12009-10-30 11:49:00 +000014062 }
14063 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000014064 Assembler::FlushICache(GetIsolate(), instruction_start(), instruction_size());
Steve Blocka7e24c12009-10-30 11:49:00 +000014065}
14066
14067
14068// Locate the source position which is closest to the address in the code. This
14069// is using the source position information embedded in the relocation info.
14070// The position returned is relative to the beginning of the script where the
14071// source for this function is found.
14072int Code::SourcePosition(Address pc) {
14073 int distance = kMaxInt;
14074 int position = RelocInfo::kNoPosition; // Initially no position found.
14075 // Run through all the relocation info to find the best matching source
14076 // position. All the code needs to be considered as the sequence of the
14077 // instructions in the code does not necessarily follow the same order as the
14078 // source.
14079 RelocIterator it(this, RelocInfo::kPositionMask);
14080 while (!it.done()) {
14081 // Only look at positions after the current pc.
14082 if (it.rinfo()->pc() < pc) {
14083 // Get position and distance.
Steve Blockd0582a62009-12-15 09:54:21 +000014084
14085 int dist = static_cast<int>(pc - it.rinfo()->pc());
14086 int pos = static_cast<int>(it.rinfo()->data());
Steve Blocka7e24c12009-10-30 11:49:00 +000014087 // If this position is closer than the current candidate or if it has the
14088 // same distance as the current candidate and the position is higher then
14089 // this position is the new candidate.
14090 if ((dist < distance) ||
14091 (dist == distance && pos > position)) {
14092 position = pos;
14093 distance = dist;
14094 }
14095 }
14096 it.next();
14097 }
14098 return position;
14099}
14100
14101
14102// Same as Code::SourcePosition above except it only looks for statement
14103// positions.
14104int Code::SourceStatementPosition(Address pc) {
14105 // First find the position as close as possible using all position
14106 // information.
14107 int position = SourcePosition(pc);
14108 // Now find the closest statement position before the position.
14109 int statement_position = 0;
14110 RelocIterator it(this, RelocInfo::kPositionMask);
14111 while (!it.done()) {
14112 if (RelocInfo::IsStatementPosition(it.rinfo()->rmode())) {
Steve Blockd0582a62009-12-15 09:54:21 +000014113 int p = static_cast<int>(it.rinfo()->data());
Steve Blocka7e24c12009-10-30 11:49:00 +000014114 if (statement_position < p && p <= position) {
14115 statement_position = p;
14116 }
14117 }
14118 it.next();
14119 }
14120 return statement_position;
14121}
14122
14123
Ben Murdochb8e0da22011-05-16 14:20:40 +010014124SafepointEntry Code::GetSafepointEntry(Address pc) {
Ben Murdochb0fe1622011-05-05 13:52:32 +010014125 SafepointTable table(this);
Ben Murdochb8e0da22011-05-16 14:20:40 +010014126 return table.FindEntry(pc);
Ben Murdochb0fe1622011-05-05 13:52:32 +010014127}
14128
14129
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014130Object* Code::FindNthObject(int n, Map* match_map) {
14131 DCHECK(is_inline_cache_stub());
14132 DisallowHeapAllocation no_allocation;
Ben Murdochb0fe1622011-05-05 13:52:32 +010014133 int mask = RelocInfo::ModeMask(RelocInfo::EMBEDDED_OBJECT);
14134 for (RelocIterator it(this, mask); !it.done(); it.next()) {
14135 RelocInfo* info = it.rinfo();
14136 Object* object = info->target_object();
Emily Bernierd0a1eb72015-03-24 16:35:39 -040014137 if (object->IsWeakCell()) object = WeakCell::cast(object)->value();
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014138 if (object->IsHeapObject()) {
14139 if (HeapObject::cast(object)->map() == match_map) {
14140 if (--n == 0) return object;
14141 }
14142 }
14143 }
14144 return NULL;
14145}
14146
14147
14148AllocationSite* Code::FindFirstAllocationSite() {
14149 Object* result = FindNthObject(1, GetHeap()->allocation_site_map());
14150 return (result != NULL) ? AllocationSite::cast(result) : NULL;
14151}
14152
14153
14154Map* Code::FindFirstMap() {
14155 Object* result = FindNthObject(1, GetHeap()->meta_map());
14156 return (result != NULL) ? Map::cast(result) : NULL;
14157}
14158
14159
14160void Code::FindAndReplace(const FindAndReplacePattern& pattern) {
14161 DCHECK(is_inline_cache_stub() || is_handler());
14162 DisallowHeapAllocation no_allocation;
14163 int mask = RelocInfo::ModeMask(RelocInfo::EMBEDDED_OBJECT);
14164 STATIC_ASSERT(FindAndReplacePattern::kMaxCount < 32);
14165 int current_pattern = 0;
14166 for (RelocIterator it(this, mask); !it.done(); it.next()) {
14167 RelocInfo* info = it.rinfo();
14168 Object* object = info->target_object();
14169 if (object->IsHeapObject()) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -040014170 if (object->IsWeakCell()) {
14171 object = HeapObject::cast(WeakCell::cast(object)->value());
14172 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014173 Map* map = HeapObject::cast(object)->map();
14174 if (map == *pattern.find_[current_pattern]) {
14175 info->set_target_object(*pattern.replace_[current_pattern]);
14176 if (++current_pattern == pattern.count_) return;
14177 }
14178 }
14179 }
14180 UNREACHABLE();
14181}
14182
14183
14184void Code::FindAllMaps(MapHandleList* maps) {
14185 DCHECK(is_inline_cache_stub());
14186 DisallowHeapAllocation no_allocation;
14187 int mask = RelocInfo::ModeMask(RelocInfo::EMBEDDED_OBJECT);
14188 for (RelocIterator it(this, mask); !it.done(); it.next()) {
14189 RelocInfo* info = it.rinfo();
14190 Object* object = info->target_object();
Emily Bernierd0a1eb72015-03-24 16:35:39 -040014191 if (object->IsWeakCell()) object = WeakCell::cast(object)->value();
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014192 if (object->IsMap()) maps->Add(handle(Map::cast(object)));
14193 }
14194}
14195
14196
14197Code* Code::FindFirstHandler() {
14198 DCHECK(is_inline_cache_stub());
14199 DisallowHeapAllocation no_allocation;
Emily Bernierd0a1eb72015-03-24 16:35:39 -040014200 int mask = RelocInfo::ModeMask(RelocInfo::CODE_TARGET) |
14201 RelocInfo::ModeMask(RelocInfo::EMBEDDED_OBJECT);
14202 bool skip_next_handler = false;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014203 for (RelocIterator it(this, mask); !it.done(); it.next()) {
14204 RelocInfo* info = it.rinfo();
Emily Bernierd0a1eb72015-03-24 16:35:39 -040014205 if (info->rmode() == RelocInfo::EMBEDDED_OBJECT) {
14206 Object* obj = info->target_object();
14207 skip_next_handler |= obj->IsWeakCell() && WeakCell::cast(obj)->cleared();
14208 } else {
14209 Code* code = Code::GetCodeFromTargetAddress(info->target_address());
14210 if (code->kind() == Code::HANDLER) {
14211 if (!skip_next_handler) return code;
14212 skip_next_handler = false;
14213 }
14214 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014215 }
14216 return NULL;
14217}
14218
14219
14220bool Code::FindHandlers(CodeHandleList* code_list, int length) {
14221 DCHECK(is_inline_cache_stub());
14222 DisallowHeapAllocation no_allocation;
Emily Bernierd0a1eb72015-03-24 16:35:39 -040014223 int mask = RelocInfo::ModeMask(RelocInfo::CODE_TARGET) |
14224 RelocInfo::ModeMask(RelocInfo::EMBEDDED_OBJECT);
14225 bool skip_next_handler = false;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014226 int i = 0;
14227 for (RelocIterator it(this, mask); !it.done(); it.next()) {
14228 if (i == length) return true;
14229 RelocInfo* info = it.rinfo();
Emily Bernierd0a1eb72015-03-24 16:35:39 -040014230 if (info->rmode() == RelocInfo::EMBEDDED_OBJECT) {
14231 Object* obj = info->target_object();
14232 skip_next_handler |= obj->IsWeakCell() && WeakCell::cast(obj)->cleared();
14233 } else {
14234 Code* code = Code::GetCodeFromTargetAddress(info->target_address());
14235 // IC stubs with handlers never contain non-handler code objects before
14236 // handler targets.
14237 if (code->kind() != Code::HANDLER) break;
14238 if (!skip_next_handler) {
14239 code_list->Add(Handle<Code>(code));
14240 i++;
14241 }
14242 skip_next_handler = false;
14243 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014244 }
14245 return i == length;
14246}
14247
14248
14249MaybeHandle<Code> Code::FindHandlerForMap(Map* map) {
14250 DCHECK(is_inline_cache_stub());
14251 int mask = RelocInfo::ModeMask(RelocInfo::CODE_TARGET) |
14252 RelocInfo::ModeMask(RelocInfo::EMBEDDED_OBJECT);
14253 bool return_next = false;
14254 for (RelocIterator it(this, mask); !it.done(); it.next()) {
14255 RelocInfo* info = it.rinfo();
14256 if (info->rmode() == RelocInfo::EMBEDDED_OBJECT) {
14257 Object* object = info->target_object();
Emily Bernierd0a1eb72015-03-24 16:35:39 -040014258 if (object->IsWeakCell()) object = WeakCell::cast(object)->value();
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014259 if (object == map) return_next = true;
14260 } else if (return_next) {
14261 Code* code = Code::GetCodeFromTargetAddress(info->target_address());
14262 DCHECK(code->kind() == Code::HANDLER);
14263 return handle(code);
14264 }
14265 }
14266 return MaybeHandle<Code>();
14267}
14268
14269
14270Name* Code::FindFirstName() {
14271 DCHECK(is_inline_cache_stub());
14272 DisallowHeapAllocation no_allocation;
14273 int mask = RelocInfo::ModeMask(RelocInfo::EMBEDDED_OBJECT);
14274 for (RelocIterator it(this, mask); !it.done(); it.next()) {
14275 RelocInfo* info = it.rinfo();
14276 Object* object = info->target_object();
14277 if (object->IsName()) return Name::cast(object);
Ben Murdochb0fe1622011-05-05 13:52:32 +010014278 }
14279 return NULL;
14280}
14281
14282
Ben Murdoch8f9999f2012-04-23 10:39:17 +010014283void Code::ClearInlineCaches() {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014284 ClearInlineCaches(NULL);
14285}
14286
14287
14288void Code::ClearInlineCaches(Code::Kind kind) {
14289 ClearInlineCaches(&kind);
14290}
14291
14292
14293void Code::ClearInlineCaches(Code::Kind* kind) {
Ben Murdoch8f9999f2012-04-23 10:39:17 +010014294 int mask = RelocInfo::ModeMask(RelocInfo::CODE_TARGET) |
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014295 RelocInfo::ModeMask(RelocInfo::CODE_TARGET_WITH_ID);
Ben Murdoch8f9999f2012-04-23 10:39:17 +010014296 for (RelocIterator it(this, mask); !it.done(); it.next()) {
14297 RelocInfo* info = it.rinfo();
14298 Code* target(Code::GetCodeFromTargetAddress(info->target_address()));
14299 if (target->is_inline_cache_stub()) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014300 if (kind == NULL || *kind == target->kind()) {
14301 IC::Clear(this->GetIsolate(), info->pc(),
14302 info->host()->constant_pool());
14303 }
Ben Murdoch8f9999f2012-04-23 10:39:17 +010014304 }
14305 }
14306}
14307
14308
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014309void SharedFunctionInfo::ClearTypeFeedbackInfo() {
Emily Bernierd0a1eb72015-03-24 16:35:39 -040014310 feedback_vector()->ClearSlots(this);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014311}
14312
14313
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000014314void SharedFunctionInfo::ClearTypeFeedbackInfoAtGCTime() {
14315 feedback_vector()->ClearSlotsAtGCTime(this);
14316}
14317
14318
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014319BailoutId Code::TranslatePcOffsetToAstId(uint32_t pc_offset) {
14320 DisallowHeapAllocation no_gc;
14321 DCHECK(kind() == FUNCTION);
14322 BackEdgeTable back_edges(this, &no_gc);
14323 for (uint32_t i = 0; i < back_edges.length(); i++) {
14324 if (back_edges.pc_offset(i) == pc_offset) return back_edges.ast_id(i);
14325 }
14326 return BailoutId::None();
14327}
14328
14329
14330uint32_t Code::TranslateAstIdToPcOffset(BailoutId ast_id) {
14331 DisallowHeapAllocation no_gc;
14332 DCHECK(kind() == FUNCTION);
14333 BackEdgeTable back_edges(this, &no_gc);
14334 for (uint32_t i = 0; i < back_edges.length(); i++) {
14335 if (back_edges.ast_id(i) == ast_id) return back_edges.pc_offset(i);
14336 }
14337 UNREACHABLE(); // We expect to find the back edge.
14338 return 0;
14339}
14340
14341
14342void Code::MakeCodeAgeSequenceYoung(byte* sequence, Isolate* isolate) {
14343 PatchPlatformCodeAge(isolate, sequence, kNoAgeCodeAge, NO_MARKING_PARITY);
14344}
14345
14346
14347void Code::MarkCodeAsExecuted(byte* sequence, Isolate* isolate) {
14348 PatchPlatformCodeAge(isolate, sequence, kExecutedOnceCodeAge,
14349 NO_MARKING_PARITY);
14350}
14351
14352
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000014353// NextAge defines the Code::Age state transitions during a GC cycle.
14354static Code::Age NextAge(Code::Age age) {
14355 switch (age) {
14356 case Code::kNotExecutedCodeAge: // Keep, until we've been executed.
14357 case Code::kToBeExecutedOnceCodeAge: // Keep, until we've been executed.
14358 case Code::kLastCodeAge: // Clamp at last Code::Age value.
14359 return age;
14360 case Code::kExecutedOnceCodeAge:
14361 // Pre-age code that has only been executed once.
14362 return static_cast<Code::Age>(Code::kPreAgedCodeAge + 1);
14363 default:
14364 return static_cast<Code::Age>(age + 1); // Default case: Increase age.
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014365 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000014366}
14367
14368
14369// IsOldAge defines the collection criteria for a Code object.
14370static bool IsOldAge(Code::Age age) {
14371 return age >= Code::kIsOldCodeAge || age == Code::kNotExecutedCodeAge;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014372}
14373
14374
Emily Bernierd0a1eb72015-03-24 16:35:39 -040014375void Code::MakeYoung(Isolate* isolate) {
14376 byte* sequence = FindCodeAgeSequence();
14377 if (sequence != NULL) MakeCodeAgeSequenceYoung(sequence, isolate);
14378}
14379
14380
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000014381void Code::MarkToBeExecutedOnce(Isolate* isolate) {
14382 byte* sequence = FindCodeAgeSequence();
14383 if (sequence != NULL) {
14384 PatchPlatformCodeAge(isolate, sequence, kToBeExecutedOnceCodeAge,
14385 NO_MARKING_PARITY);
14386 }
14387}
14388
14389
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014390void Code::MakeOlder(MarkingParity current_parity) {
14391 byte* sequence = FindCodeAgeSequence();
14392 if (sequence != NULL) {
14393 Age age;
14394 MarkingParity code_parity;
14395 Isolate* isolate = GetIsolate();
14396 GetCodeAgeAndParity(isolate, sequence, &age, &code_parity);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000014397 Age next_age = NextAge(age);
14398 if (age != next_age && code_parity != current_parity) {
14399 PatchPlatformCodeAge(isolate, sequence, next_age, current_parity);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014400 }
14401 }
14402}
14403
14404
14405bool Code::IsOld() {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000014406 return IsOldAge(GetAge());
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014407}
14408
14409
14410byte* Code::FindCodeAgeSequence() {
14411 return FLAG_age_code &&
14412 prologue_offset() != Code::kPrologueOffsetNotSet &&
14413 (kind() == OPTIMIZED_FUNCTION ||
14414 (kind() == FUNCTION && !has_debug_break_slots()))
14415 ? instruction_start() + prologue_offset()
14416 : NULL;
14417}
14418
14419
14420Code::Age Code::GetAge() {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014421 byte* sequence = FindCodeAgeSequence();
14422 if (sequence == NULL) {
14423 return kNoAgeCodeAge;
14424 }
14425 Age age;
14426 MarkingParity parity;
14427 GetCodeAgeAndParity(GetIsolate(), sequence, &age, &parity);
14428 return age;
14429}
14430
14431
14432void Code::GetCodeAgeAndParity(Code* code, Age* age,
14433 MarkingParity* parity) {
14434 Isolate* isolate = code->GetIsolate();
14435 Builtins* builtins = isolate->builtins();
14436 Code* stub = NULL;
14437#define HANDLE_CODE_AGE(AGE) \
14438 stub = *builtins->Make##AGE##CodeYoungAgainEvenMarking(); \
14439 if (code == stub) { \
14440 *age = k##AGE##CodeAge; \
14441 *parity = EVEN_MARKING_PARITY; \
14442 return; \
14443 } \
14444 stub = *builtins->Make##AGE##CodeYoungAgainOddMarking(); \
14445 if (code == stub) { \
14446 *age = k##AGE##CodeAge; \
14447 *parity = ODD_MARKING_PARITY; \
14448 return; \
14449 }
14450 CODE_AGE_LIST(HANDLE_CODE_AGE)
14451#undef HANDLE_CODE_AGE
14452 stub = *builtins->MarkCodeAsExecutedOnce();
14453 if (code == stub) {
14454 *age = kNotExecutedCodeAge;
14455 *parity = NO_MARKING_PARITY;
14456 return;
14457 }
14458 stub = *builtins->MarkCodeAsExecutedTwice();
14459 if (code == stub) {
14460 *age = kExecutedOnceCodeAge;
14461 *parity = NO_MARKING_PARITY;
14462 return;
14463 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000014464 stub = *builtins->MarkCodeAsToBeExecutedOnce();
14465 if (code == stub) {
14466 *age = kToBeExecutedOnceCodeAge;
14467 *parity = NO_MARKING_PARITY;
14468 return;
14469 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014470 UNREACHABLE();
14471}
14472
14473
14474Code* Code::GetCodeAgeStub(Isolate* isolate, Age age, MarkingParity parity) {
14475 Builtins* builtins = isolate->builtins();
14476 switch (age) {
14477#define HANDLE_CODE_AGE(AGE) \
14478 case k##AGE##CodeAge: { \
14479 Code* stub = parity == EVEN_MARKING_PARITY \
14480 ? *builtins->Make##AGE##CodeYoungAgainEvenMarking() \
14481 : *builtins->Make##AGE##CodeYoungAgainOddMarking(); \
14482 return stub; \
14483 }
14484 CODE_AGE_LIST(HANDLE_CODE_AGE)
14485#undef HANDLE_CODE_AGE
14486 case kNotExecutedCodeAge: {
14487 DCHECK(parity == NO_MARKING_PARITY);
14488 return *builtins->MarkCodeAsExecutedOnce();
14489 }
14490 case kExecutedOnceCodeAge: {
14491 DCHECK(parity == NO_MARKING_PARITY);
14492 return *builtins->MarkCodeAsExecutedTwice();
14493 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000014494 case kToBeExecutedOnceCodeAge: {
14495 DCHECK(parity == NO_MARKING_PARITY);
14496 return *builtins->MarkCodeAsToBeExecutedOnce();
14497 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014498 default:
14499 UNREACHABLE();
14500 break;
14501 }
14502 return NULL;
14503}
14504
14505
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000014506void Code::PrintDeoptLocation(FILE* out, Address pc) {
14507 Deoptimizer::DeoptInfo info = Deoptimizer::GetDeoptInfo(this, pc);
14508 class SourcePosition pos = info.position;
14509 if (info.deopt_reason != Deoptimizer::kNoReason || !pos.IsUnknown()) {
14510 if (FLAG_hydrogen_track_positions) {
14511 PrintF(out, " ;;; deoptimize at %d_%d: %s\n",
14512 pos.inlining_id(), pos.position(),
14513 Deoptimizer::GetDeoptReason(info.deopt_reason));
14514 } else {
14515 PrintF(out, " ;;; deoptimize at %d: %s\n", pos.raw(),
14516 Deoptimizer::GetDeoptReason(info.deopt_reason));
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014517 }
14518 }
14519}
14520
14521
14522bool Code::CanDeoptAt(Address pc) {
14523 DeoptimizationInputData* deopt_data =
14524 DeoptimizationInputData::cast(deoptimization_data());
14525 Address code_start_address = instruction_start();
14526 for (int i = 0; i < deopt_data->DeoptCount(); i++) {
14527 if (deopt_data->Pc(i)->value() == -1) continue;
14528 Address address = code_start_address + deopt_data->Pc(i)->value();
14529 if (address == pc) return true;
14530 }
14531 return false;
14532}
14533
14534
14535// Identify kind of code.
14536const char* Code::Kind2String(Kind kind) {
14537 switch (kind) {
14538#define CASE(name) case name: return #name;
14539 CODE_KIND_LIST(CASE)
14540#undef CASE
14541 case NUMBER_OF_KINDS: break;
14542 }
14543 UNREACHABLE();
14544 return NULL;
14545}
14546
14547
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000014548Handle<WeakCell> Code::WeakCellFor(Handle<Code> code) {
14549 DCHECK(code->kind() == OPTIMIZED_FUNCTION);
14550 WeakCell* raw_cell = code->CachedWeakCell();
14551 if (raw_cell != NULL) return Handle<WeakCell>(raw_cell);
14552 Handle<WeakCell> cell = code->GetIsolate()->factory()->NewWeakCell(code);
14553 DeoptimizationInputData::cast(code->deoptimization_data())
14554 ->SetWeakCellCache(*cell);
14555 return cell;
14556}
14557
14558
14559WeakCell* Code::CachedWeakCell() {
14560 DCHECK(kind() == OPTIMIZED_FUNCTION);
14561 Object* weak_cell_cache =
14562 DeoptimizationInputData::cast(deoptimization_data())->WeakCellCache();
14563 if (weak_cell_cache->IsWeakCell()) {
14564 DCHECK(this == WeakCell::cast(weak_cell_cache)->value());
14565 return WeakCell::cast(weak_cell_cache);
14566 }
14567 return NULL;
14568}
14569
14570
Steve Blocka7e24c12009-10-30 11:49:00 +000014571#ifdef ENABLE_DISASSEMBLER
Ben Murdochb0fe1622011-05-05 13:52:32 +010014572
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014573void DeoptimizationInputData::DeoptimizationInputDataPrint(
Emily Bernierd0a1eb72015-03-24 16:35:39 -040014574 std::ostream& os) { // NOLINT
Ben Murdochb0fe1622011-05-05 13:52:32 +010014575 disasm::NameConverter converter;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000014576 int const inlined_function_count = InlinedFunctionCount()->value();
14577 os << "Inlined functions (count = " << inlined_function_count << ")\n";
14578 for (int id = 0; id < inlined_function_count; ++id) {
14579 Object* info = LiteralArray()->get(id);
14580 os << " " << Brief(SharedFunctionInfo::cast(info)) << "\n";
14581 }
14582 os << "\n";
Ben Murdochb0fe1622011-05-05 13:52:32 +010014583 int deopt_count = DeoptCount();
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014584 os << "Deoptimization Input Data (deopt points = " << deopt_count << ")\n";
14585 if (0 != deopt_count) {
14586 os << " index ast id argc pc";
14587 if (FLAG_print_code_verbose) os << " commands";
14588 os << "\n";
14589 }
Ben Murdochb0fe1622011-05-05 13:52:32 +010014590 for (int i = 0; i < deopt_count; i++) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000014591 os << std::setw(6) << i << " " << std::setw(6) << AstId(i).ToInt() << " "
14592 << std::setw(6) << ArgumentsStackHeight(i)->value() << " "
14593 << std::setw(6) << Pc(i)->value();
Ben Murdoch69a99ed2011-11-30 16:03:39 +000014594
14595 if (!FLAG_print_code_verbose) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014596 os << "\n";
Ben Murdoch69a99ed2011-11-30 16:03:39 +000014597 continue;
14598 }
14599 // Print details of the frame translation.
Ben Murdochb0fe1622011-05-05 13:52:32 +010014600 int translation_index = TranslationIndex(i)->value();
14601 TranslationIterator iterator(TranslationByteArray(), translation_index);
14602 Translation::Opcode opcode =
14603 static_cast<Translation::Opcode>(iterator.Next());
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014604 DCHECK(Translation::BEGIN == opcode);
Ben Murdochb0fe1622011-05-05 13:52:32 +010014605 int frame_count = iterator.Next();
Ben Murdoch3ef787d2012-04-12 10:51:47 +010014606 int jsframe_count = iterator.Next();
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014607 os << " " << Translation::StringFor(opcode)
14608 << " {frame count=" << frame_count
14609 << ", js frame count=" << jsframe_count << "}\n";
Ben Murdochb0fe1622011-05-05 13:52:32 +010014610
Ben Murdoch69a99ed2011-11-30 16:03:39 +000014611 while (iterator.HasNext() &&
14612 Translation::BEGIN !=
14613 (opcode = static_cast<Translation::Opcode>(iterator.Next()))) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000014614 os << std::setw(31) << " " << Translation::StringFor(opcode) << " ";
Ben Murdoch69a99ed2011-11-30 16:03:39 +000014615
14616 switch (opcode) {
14617 case Translation::BEGIN:
14618 UNREACHABLE();
14619 break;
14620
Ben Murdoch3ef787d2012-04-12 10:51:47 +010014621 case Translation::JS_FRAME: {
Ben Murdoch69a99ed2011-11-30 16:03:39 +000014622 int ast_id = iterator.Next();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000014623 int shared_info_id = iterator.Next();
Ben Murdoch69a99ed2011-11-30 16:03:39 +000014624 unsigned height = iterator.Next();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000014625 Object* shared_info = LiteralArray()->get(shared_info_id);
14626 os << "{ast_id=" << ast_id << ", function="
14627 << Brief(SharedFunctionInfo::cast(shared_info)->DebugName())
14628 << ", height=" << height << "}";
14629 break;
14630 }
14631
14632 case Translation::INTERPRETED_FRAME: {
14633 int bytecode_offset = iterator.Next();
14634 int shared_info_id = iterator.Next();
14635 unsigned height = iterator.Next();
14636 Object* shared_info = LiteralArray()->get(shared_info_id);
14637 os << "{bytecode_offset=" << bytecode_offset << ", function="
14638 << Brief(SharedFunctionInfo::cast(shared_info)->DebugName())
14639 << ", height=" << height << "}";
14640 break;
14641 }
14642
14643 case Translation::JS_FRAME_FUNCTION: {
14644 os << "{function}";
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014645 break;
14646 }
14647
14648 case Translation::COMPILED_STUB_FRAME: {
14649 Code::Kind stub_kind = static_cast<Code::Kind>(iterator.Next());
14650 os << "{kind=" << stub_kind << "}";
Ben Murdoch69a99ed2011-11-30 16:03:39 +000014651 break;
14652 }
14653
Ben Murdoch3ef787d2012-04-12 10:51:47 +010014654 case Translation::ARGUMENTS_ADAPTOR_FRAME:
14655 case Translation::CONSTRUCT_STUB_FRAME: {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000014656 int shared_info_id = iterator.Next();
14657 Object* shared_info = LiteralArray()->get(shared_info_id);
Ben Murdoch3ef787d2012-04-12 10:51:47 +010014658 unsigned height = iterator.Next();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000014659 os << "{function="
14660 << Brief(SharedFunctionInfo::cast(shared_info)->DebugName())
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014661 << ", height=" << height << "}";
Ben Murdoch3ef787d2012-04-12 10:51:47 +010014662 break;
14663 }
14664
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014665 case Translation::GETTER_STUB_FRAME:
14666 case Translation::SETTER_STUB_FRAME: {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000014667 int shared_info_id = iterator.Next();
14668 Object* shared_info = LiteralArray()->get(shared_info_id);
14669 os << "{function=" << Brief(SharedFunctionInfo::cast(shared_info)
14670 ->DebugName()) << "}";
Ben Murdoch69a99ed2011-11-30 16:03:39 +000014671 break;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014672 }
Ben Murdoch69a99ed2011-11-30 16:03:39 +000014673
14674 case Translation::REGISTER: {
14675 int reg_code = iterator.Next();
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014676 os << "{input=" << converter.NameOfCPURegister(reg_code) << "}";
Ben Murdoch69a99ed2011-11-30 16:03:39 +000014677 break;
14678 }
14679
14680 case Translation::INT32_REGISTER: {
14681 int reg_code = iterator.Next();
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014682 os << "{input=" << converter.NameOfCPURegister(reg_code) << "}";
14683 break;
14684 }
14685
14686 case Translation::UINT32_REGISTER: {
14687 int reg_code = iterator.Next();
14688 os << "{input=" << converter.NameOfCPURegister(reg_code)
14689 << " (unsigned)}";
Ben Murdoch69a99ed2011-11-30 16:03:39 +000014690 break;
14691 }
14692
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000014693 case Translation::BOOL_REGISTER: {
14694 int reg_code = iterator.Next();
14695 os << "{input=" << converter.NameOfCPURegister(reg_code)
14696 << " (bool)}";
14697 break;
14698 }
14699
Ben Murdoch69a99ed2011-11-30 16:03:39 +000014700 case Translation::DOUBLE_REGISTER: {
14701 int reg_code = iterator.Next();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000014702 os << "{input=" << DoubleRegister::from_code(reg_code).ToString()
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014703 << "}";
Ben Murdoch69a99ed2011-11-30 16:03:39 +000014704 break;
14705 }
14706
14707 case Translation::STACK_SLOT: {
14708 int input_slot_index = iterator.Next();
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014709 os << "{input=" << input_slot_index << "}";
Ben Murdoch69a99ed2011-11-30 16:03:39 +000014710 break;
14711 }
14712
14713 case Translation::INT32_STACK_SLOT: {
14714 int input_slot_index = iterator.Next();
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014715 os << "{input=" << input_slot_index << "}";
14716 break;
14717 }
14718
14719 case Translation::UINT32_STACK_SLOT: {
14720 int input_slot_index = iterator.Next();
14721 os << "{input=" << input_slot_index << " (unsigned)}";
Ben Murdoch69a99ed2011-11-30 16:03:39 +000014722 break;
14723 }
14724
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000014725 case Translation::BOOL_STACK_SLOT: {
14726 int input_slot_index = iterator.Next();
14727 os << "{input=" << input_slot_index << " (bool)}";
14728 break;
14729 }
14730
Ben Murdoch69a99ed2011-11-30 16:03:39 +000014731 case Translation::DOUBLE_STACK_SLOT: {
14732 int input_slot_index = iterator.Next();
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014733 os << "{input=" << input_slot_index << "}";
Ben Murdoch69a99ed2011-11-30 16:03:39 +000014734 break;
14735 }
14736
14737 case Translation::LITERAL: {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000014738 int literal_index = iterator.Next();
14739 Object* literal_value = LiteralArray()->get(literal_index);
14740 os << "{literal_id=" << literal_index << " (" << Brief(literal_value)
14741 << ")}";
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014742 break;
14743 }
14744
14745 case Translation::DUPLICATED_OBJECT: {
14746 int object_index = iterator.Next();
14747 os << "{object_index=" << object_index << "}";
Ben Murdoch69a99ed2011-11-30 16:03:39 +000014748 break;
14749 }
14750
14751 case Translation::ARGUMENTS_OBJECT:
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014752 case Translation::CAPTURED_OBJECT: {
14753 int args_length = iterator.Next();
14754 os << "{length=" << args_length << "}";
Ben Murdoch69a99ed2011-11-30 16:03:39 +000014755 break;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014756 }
Ben Murdochb0fe1622011-05-05 13:52:32 +010014757 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014758 os << "\n";
Ben Murdochb0fe1622011-05-05 13:52:32 +010014759 }
Ben Murdochb0fe1622011-05-05 13:52:32 +010014760 }
14761}
14762
14763
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014764void DeoptimizationOutputData::DeoptimizationOutputDataPrint(
Emily Bernierd0a1eb72015-03-24 16:35:39 -040014765 std::ostream& os) { // NOLINT
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014766 os << "Deoptimization Output Data (deopt points = " << this->DeoptPoints()
14767 << ")\n";
Ben Murdochb0fe1622011-05-05 13:52:32 +010014768 if (this->DeoptPoints() == 0) return;
14769
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014770 os << "ast id pc state\n";
Ben Murdochb0fe1622011-05-05 13:52:32 +010014771 for (int i = 0; i < this->DeoptPoints(); i++) {
14772 int pc_and_state = this->PcAndState(i)->value();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000014773 os << std::setw(6) << this->AstId(i).ToInt() << " " << std::setw(8)
14774 << FullCodeGenerator::PcField::decode(pc_and_state) << " "
14775 << FullCodeGenerator::State2String(
14776 FullCodeGenerator::StateField::decode(pc_and_state)) << "\n";
14777 }
14778}
14779
14780
14781void HandlerTable::HandlerTableRangePrint(std::ostream& os) {
14782 os << " from to hdlr\n";
14783 for (int i = 0; i < length(); i += kRangeEntrySize) {
14784 int pc_start = Smi::cast(get(i + kRangeStartIndex))->value();
14785 int pc_end = Smi::cast(get(i + kRangeEndIndex))->value();
14786 int handler_field = Smi::cast(get(i + kRangeHandlerIndex))->value();
14787 int handler_offset = HandlerOffsetField::decode(handler_field);
14788 CatchPrediction prediction = HandlerPredictionField::decode(handler_field);
14789 int depth = Smi::cast(get(i + kRangeDepthIndex))->value();
14790 os << " (" << std::setw(4) << pc_start << "," << std::setw(4) << pc_end
14791 << ") -> " << std::setw(4) << handler_offset
14792 << " (prediction=" << prediction << ", depth=" << depth << ")\n";
14793 }
14794}
14795
14796
14797void HandlerTable::HandlerTableReturnPrint(std::ostream& os) {
14798 os << " off hdlr (c)\n";
14799 for (int i = 0; i < length(); i += kReturnEntrySize) {
14800 int pc_offset = Smi::cast(get(i + kReturnOffsetIndex))->value();
14801 int handler_field = Smi::cast(get(i + kReturnHandlerIndex))->value();
14802 int handler_offset = HandlerOffsetField::decode(handler_field);
14803 CatchPrediction prediction = HandlerPredictionField::decode(handler_field);
14804 os << " " << std::setw(4) << pc_offset << " -> " << std::setw(4)
14805 << handler_offset << " (prediction=" << prediction << ")\n";
Ben Murdochb0fe1622011-05-05 13:52:32 +010014806 }
14807}
14808
Ben Murdochb0fe1622011-05-05 13:52:32 +010014809
Steve Blocka7e24c12009-10-30 11:49:00 +000014810const char* Code::ICState2String(InlineCacheState state) {
14811 switch (state) {
14812 case UNINITIALIZED: return "UNINITIALIZED";
14813 case PREMONOMORPHIC: return "PREMONOMORPHIC";
14814 case MONOMORPHIC: return "MONOMORPHIC";
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014815 case PROTOTYPE_FAILURE:
14816 return "PROTOTYPE_FAILURE";
14817 case POLYMORPHIC: return "POLYMORPHIC";
Steve Blocka7e24c12009-10-30 11:49:00 +000014818 case MEGAMORPHIC: return "MEGAMORPHIC";
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014819 case GENERIC: return "GENERIC";
14820 case DEBUG_STUB: return "DEBUG_STUB";
Steve Blocka7e24c12009-10-30 11:49:00 +000014821 }
14822 UNREACHABLE();
14823 return NULL;
14824}
14825
14826
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014827const char* Code::StubType2String(StubType type) {
Steve Blocka7e24c12009-10-30 11:49:00 +000014828 switch (type) {
14829 case NORMAL: return "NORMAL";
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014830 case FAST: return "FAST";
Steve Blocka7e24c12009-10-30 11:49:00 +000014831 }
Ben Murdoch3ef787d2012-04-12 10:51:47 +010014832 UNREACHABLE(); // keep the compiler happy
Steve Blocka7e24c12009-10-30 11:49:00 +000014833 return NULL;
14834}
14835
Ben Murdochb0fe1622011-05-05 13:52:32 +010014836
Emily Bernierd0a1eb72015-03-24 16:35:39 -040014837void Code::PrintExtraICState(std::ostream& os, // NOLINT
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014838 Kind kind, ExtraICState extra) {
14839 os << "extra_ic_state = ";
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000014840 if ((kind == STORE_IC || kind == KEYED_STORE_IC) &&
14841 is_strict(static_cast<LanguageMode>(extra))) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014842 os << "STRICT\n";
Steve Block1e0659c2011-05-24 12:43:12 +010014843 } else {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014844 os << extra << "\n";
Steve Block1e0659c2011-05-24 12:43:12 +010014845 }
14846}
14847
14848
Emily Bernierd0a1eb72015-03-24 16:35:39 -040014849void Code::Disassemble(const char* name, std::ostream& os) { // NOLINT
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014850 os << "kind = " << Kind2String(kind()) << "\n";
14851 if (IsCodeStubOrIC()) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000014852 const char* n = CodeStub::MajorName(CodeStub::GetMajorKey(this));
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014853 os << "major_key = " << (n == NULL ? "null" : n) << "\n";
14854 }
Steve Blocka7e24c12009-10-30 11:49:00 +000014855 if (is_inline_cache_stub()) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014856 os << "ic_state = " << ICState2String(ic_state()) << "\n";
14857 PrintExtraICState(os, kind(), extra_ic_state());
Steve Blocka7e24c12009-10-30 11:49:00 +000014858 if (ic_state() == MONOMORPHIC) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014859 os << "type = " << StubType2String(type()) << "\n";
Steve Blocka7e24c12009-10-30 11:49:00 +000014860 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014861 if (is_compare_ic_stub()) {
14862 DCHECK(CodeStub::GetMajorKey(this) == CodeStub::CompareIC);
14863 CompareICStub stub(stub_key(), GetIsolate());
14864 os << "compare_state = " << CompareICState::GetStateName(stub.left())
14865 << "*" << CompareICState::GetStateName(stub.right()) << " -> "
14866 << CompareICState::GetStateName(stub.state()) << "\n";
14867 os << "compare_operation = " << Token::Name(stub.op()) << "\n";
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000014868 }
Steve Blocka7e24c12009-10-30 11:49:00 +000014869 }
14870 if ((name != NULL) && (name[0] != '\0')) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014871 os << "name = " << name << "\n";
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000014872 } else if (kind() == BUILTIN) {
14873 name = GetIsolate()->builtins()->Lookup(instruction_start());
14874 if (name != NULL) {
14875 os << "name = " << name << "\n";
14876 }
Ben Murdochb0fe1622011-05-05 13:52:32 +010014877 }
14878 if (kind() == OPTIMIZED_FUNCTION) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014879 os << "stack_slots = " << stack_slots() << "\n";
Steve Blocka7e24c12009-10-30 11:49:00 +000014880 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000014881 os << "compiler = " << (is_turbofanned()
14882 ? "turbofan"
14883 : is_crankshafted() ? "crankshaft"
14884 : kind() == Code::FUNCTION
14885 ? "full-codegen"
14886 : "unknown") << "\n";
Steve Blocka7e24c12009-10-30 11:49:00 +000014887
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014888 os << "Instructions (size = " << instruction_size() << ")\n";
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014889 {
Emily Bernierd0a1eb72015-03-24 16:35:39 -040014890 Isolate* isolate = GetIsolate();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000014891 int size = instruction_size();
14892 int safepoint_offset =
14893 is_crankshafted() ? static_cast<int>(safepoint_table_offset()) : size;
14894 int back_edge_offset = (kind() == Code::FUNCTION)
14895 ? static_cast<int>(back_edge_table_offset())
14896 : size;
14897 int constant_pool_offset = FLAG_enable_embedded_constant_pool
14898 ? this->constant_pool_offset()
14899 : size;
14900
14901 // Stop before reaching any embedded tables
14902 int code_size = Min(safepoint_offset, back_edge_offset);
14903 code_size = Min(code_size, constant_pool_offset);
Emily Bernierd0a1eb72015-03-24 16:35:39 -040014904 byte* begin = instruction_start();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000014905 byte* end = begin + code_size;
Emily Bernierd0a1eb72015-03-24 16:35:39 -040014906 Disassembler::Decode(isolate, &os, begin, end, this);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000014907
14908 if (constant_pool_offset < size) {
14909 int constant_pool_size = size - constant_pool_offset;
14910 DCHECK((constant_pool_size & kPointerAlignmentMask) == 0);
14911 os << "\nConstant Pool (size = " << constant_pool_size << ")\n";
14912 Vector<char> buf = Vector<char>::New(50);
14913 intptr_t* ptr = reinterpret_cast<intptr_t*>(begin + constant_pool_offset);
14914 for (int i = 0; i < constant_pool_size; i += kPointerSize, ptr++) {
14915 SNPrintF(buf, "%4d %08" V8PRIxPTR, i, *ptr);
14916 os << static_cast<const void*>(ptr) << " " << buf.start() << "\n";
14917 }
14918 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014919 }
14920 os << "\n";
Ben Murdochb0fe1622011-05-05 13:52:32 +010014921
Ben Murdochb0fe1622011-05-05 13:52:32 +010014922 if (kind() == FUNCTION) {
14923 DeoptimizationOutputData* data =
14924 DeoptimizationOutputData::cast(this->deoptimization_data());
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014925 data->DeoptimizationOutputDataPrint(os);
Ben Murdochb0fe1622011-05-05 13:52:32 +010014926 } else if (kind() == OPTIMIZED_FUNCTION) {
14927 DeoptimizationInputData* data =
14928 DeoptimizationInputData::cast(this->deoptimization_data());
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014929 data->DeoptimizationInputDataPrint(os);
Ben Murdochb0fe1622011-05-05 13:52:32 +010014930 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014931 os << "\n";
Ben Murdochb0fe1622011-05-05 13:52:32 +010014932
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014933 if (is_crankshafted()) {
Ben Murdochb0fe1622011-05-05 13:52:32 +010014934 SafepointTable table(this);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014935 os << "Safepoints (size = " << table.size() << ")\n";
Ben Murdochb0fe1622011-05-05 13:52:32 +010014936 for (unsigned i = 0; i < table.length(); i++) {
14937 unsigned pc_offset = table.GetPcOffset(i);
Emily Bernierd0a1eb72015-03-24 16:35:39 -040014938 os << static_cast<const void*>(instruction_start() + pc_offset) << " ";
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000014939 os << std::setw(4) << pc_offset << " ";
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014940 table.PrintEntry(i, os);
14941 os << " (sp -> fp) ";
Ben Murdochb8e0da22011-05-16 14:20:40 +010014942 SafepointEntry entry = table.GetEntry(i);
14943 if (entry.deoptimization_index() != Safepoint::kNoDeoptimizationIndex) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000014944 os << std::setw(6) << entry.deoptimization_index();
Ben Murdochb0fe1622011-05-05 13:52:32 +010014945 } else {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014946 os << "<none>";
Ben Murdochb0fe1622011-05-05 13:52:32 +010014947 }
Ben Murdochb8e0da22011-05-16 14:20:40 +010014948 if (entry.argument_count() > 0) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014949 os << " argc: " << entry.argument_count();
Ben Murdochb8e0da22011-05-16 14:20:40 +010014950 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014951 os << "\n";
Ben Murdochb0fe1622011-05-05 13:52:32 +010014952 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014953 os << "\n";
Ben Murdochb0fe1622011-05-05 13:52:32 +010014954 } else if (kind() == FUNCTION) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014955 unsigned offset = back_edge_table_offset();
14956 // If there is no back edge table, the "table start" will be at or after
Ben Murdochb0fe1622011-05-05 13:52:32 +010014957 // (due to alignment) the end of the instruction stream.
14958 if (static_cast<int>(offset) < instruction_size()) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014959 DisallowHeapAllocation no_gc;
14960 BackEdgeTable back_edges(this, &no_gc);
14961
14962 os << "Back edges (size = " << back_edges.length() << ")\n";
14963 os << "ast_id pc_offset loop_depth\n";
14964
14965 for (uint32_t i = 0; i < back_edges.length(); i++) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000014966 os << std::setw(6) << back_edges.ast_id(i).ToInt() << " "
14967 << std::setw(9) << back_edges.pc_offset(i) << " " << std::setw(10)
14968 << back_edges.loop_depth(i) << "\n";
Ben Murdochb0fe1622011-05-05 13:52:32 +010014969 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014970
14971 os << "\n";
Ben Murdochb0fe1622011-05-05 13:52:32 +010014972 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014973#ifdef OBJECT_PRINT
14974 if (!type_feedback_info()->IsUndefined()) {
14975 OFStream os(stdout);
14976 TypeFeedbackInfo::cast(type_feedback_info())->TypeFeedbackInfoPrint(os);
14977 os << "\n";
14978 }
14979#endif
Ben Murdochb0fe1622011-05-05 13:52:32 +010014980 }
Steve Blocka7e24c12009-10-30 11:49:00 +000014981
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000014982 if (handler_table()->length() > 0) {
14983 os << "Handler Table (size = " << handler_table()->Size() << ")\n";
14984 if (kind() == FUNCTION) {
14985 HandlerTable::cast(handler_table())->HandlerTableRangePrint(os);
14986 } else if (kind() == OPTIMIZED_FUNCTION) {
14987 HandlerTable::cast(handler_table())->HandlerTableReturnPrint(os);
14988 }
14989 os << "\n";
14990 }
14991
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014992 os << "RelocInfo (size = " << relocation_size() << ")\n";
14993 for (RelocIterator it(this); !it.done(); it.next()) {
14994 it.rinfo()->Print(GetIsolate(), os);
14995 }
14996 os << "\n";
Steve Blocka7e24c12009-10-30 11:49:00 +000014997}
14998#endif // ENABLE_DISASSEMBLER
14999
15000
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000015001void BytecodeArray::Disassemble(std::ostream& os) {
15002 os << "Parameter count " << parameter_count() << "\n";
15003 os << "Frame size " << frame_size() << "\n";
15004 Vector<char> buf = Vector<char>::New(50);
Steve Block8defd9f2010-07-08 12:39:36 +010015005
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000015006 const uint8_t* first_bytecode_address = GetFirstBytecodeAddress();
15007 int bytecode_size = 0;
15008 for (int i = 0; i < this->length(); i += bytecode_size) {
15009 const uint8_t* bytecode_start = &first_bytecode_address[i];
15010 interpreter::Bytecode bytecode =
15011 interpreter::Bytecodes::FromByte(bytecode_start[0]);
15012 bytecode_size = interpreter::Bytecodes::Size(bytecode);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000015013
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000015014 SNPrintF(buf, "%p", bytecode_start);
15015 os << buf.start() << " : ";
15016 interpreter::Bytecodes::Decode(os, bytecode_start, parameter_count());
15017
15018 if (interpreter::Bytecodes::IsJumpConstantWide(bytecode)) {
15019 DCHECK_EQ(bytecode_size, 3);
15020 int index = static_cast<int>(ReadUnalignedUInt16(bytecode_start + 1));
15021 int offset = Smi::cast(constant_pool()->get(index))->value();
15022 SNPrintF(buf, " (%p)", bytecode_start + offset);
15023 os << buf.start();
15024 } else if (interpreter::Bytecodes::IsJumpConstant(bytecode)) {
15025 DCHECK_EQ(bytecode_size, 2);
15026 int index = static_cast<int>(bytecode_start[1]);
15027 int offset = Smi::cast(constant_pool()->get(index))->value();
15028 SNPrintF(buf, " (%p)", bytecode_start + offset);
15029 os << buf.start();
15030 } else if (interpreter::Bytecodes::IsJump(bytecode)) {
15031 DCHECK_EQ(bytecode_size, 2);
15032 int offset = static_cast<int8_t>(bytecode_start[1]);
15033 SNPrintF(buf, " (%p)", bytecode_start + offset);
15034 os << buf.start();
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015035 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000015036 os << "\n";
Ben Murdoch3ef787d2012-04-12 10:51:47 +010015037 }
15038
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000015039 os << "Constant pool (size = " << constant_pool()->length() << ")\n";
15040 constant_pool()->Print();
Steve Blocka7e24c12009-10-30 11:49:00 +000015041}
15042
15043
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015044// static
15045void JSArray::Initialize(Handle<JSArray> array, int capacity, int length) {
15046 DCHECK(capacity >= 0);
15047 array->GetIsolate()->factory()->NewJSArrayStorage(
15048 array, length, capacity, INITIALIZE_ARRAY_ELEMENTS_WITH_HOLE);
15049}
15050
15051
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000015052// Returns false if the passed-in index is marked non-configurable, which will
15053// cause the truncation operation to halt, and thus no further old values need
15054// be collected.
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015055static bool GetOldValue(Isolate* isolate,
15056 Handle<JSObject> object,
15057 uint32_t index,
15058 List<Handle<Object> >* old_values,
15059 List<uint32_t>* indices) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000015060 LookupIterator it(isolate, object, index, LookupIterator::HIDDEN);
15061 CHECK(JSReceiver::GetPropertyAttributes(&it).IsJust());
15062 DCHECK(it.IsFound());
15063 if (!it.IsConfigurable()) return false;
15064 Handle<Object> value =
15065 it.state() == LookupIterator::ACCESSOR
15066 ? Handle<Object>::cast(isolate->factory()->the_hole_value())
15067 : JSReceiver::GetDataProperty(&it);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015068 old_values->Add(value);
15069 indices->Add(index);
15070 return true;
15071}
15072
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015073
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000015074void JSArray::SetLength(Handle<JSArray> array, uint32_t new_length) {
Steve Block3ce2e202009-11-05 08:53:23 +000015075 // We should never end in here with a pixel or external array.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000015076 DCHECK(array->AllowsSetLength());
15077 if (array->SetLengthWouldNormalize(new_length)) {
15078 JSObject::NormalizeElements(array);
15079 }
15080 array->GetElementsAccessor()->SetLength(array, new_length);
15081}
15082
15083
15084MaybeHandle<Object> JSArray::ObservableSetLength(Handle<JSArray> array,
15085 uint32_t new_length) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015086 if (!array->map()->is_observed()) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000015087 SetLength(array, new_length);
15088 return array;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015089 }
15090
15091 Isolate* isolate = array->GetIsolate();
15092 List<uint32_t> indices;
15093 List<Handle<Object> > old_values;
15094 Handle<Object> old_length_handle(array->length(), isolate);
15095 uint32_t old_length = 0;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000015096 CHECK(old_length_handle->ToArrayLength(&old_length));
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015097
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000015098 int num_elements = array->NumberOfOwnElements(ALL_PROPERTIES);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015099 if (num_elements > 0) {
15100 if (old_length == static_cast<uint32_t>(num_elements)) {
15101 // Simple case for arrays without holes.
15102 for (uint32_t i = old_length - 1; i + 1 > new_length; --i) {
15103 if (!GetOldValue(isolate, array, i, &old_values, &indices)) break;
15104 }
15105 } else {
15106 // For sparse arrays, only iterate over existing elements.
15107 // TODO(rafaelw): For fast, sparse arrays, we can avoid iterating over
15108 // the to-be-removed indices twice.
15109 Handle<FixedArray> keys = isolate->factory()->NewFixedArray(num_elements);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000015110 array->GetOwnElementKeys(*keys, ALL_PROPERTIES);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015111 while (num_elements-- > 0) {
15112 uint32_t index = NumberToUint32(keys->get(num_elements));
15113 if (index < new_length) break;
15114 if (!GetOldValue(isolate, array, index, &old_values, &indices)) break;
15115 }
15116 }
15117 }
15118
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000015119 SetLength(array, new_length);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015120
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000015121 CHECK(array->length()->ToArrayLength(&new_length));
15122 if (old_length == new_length) return array;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015123
Emily Bernierd0a1eb72015-03-24 16:35:39 -040015124 RETURN_ON_EXCEPTION(isolate, BeginPerformSplice(array), Object);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015125
15126 for (int i = 0; i < indices.length(); ++i) {
15127 // For deletions where the property was an accessor, old_values[i]
15128 // will be the hole, which instructs EnqueueChangeRecord to elide
15129 // the "oldValue" property.
Emily Bernierd0a1eb72015-03-24 16:35:39 -040015130 RETURN_ON_EXCEPTION(
15131 isolate,
15132 JSObject::EnqueueChangeRecord(
15133 array, "delete", isolate->factory()->Uint32ToString(indices[i]),
15134 old_values[i]),
15135 Object);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015136 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000015137
Emily Bernierd0a1eb72015-03-24 16:35:39 -040015138 RETURN_ON_EXCEPTION(isolate,
15139 JSObject::EnqueueChangeRecord(
15140 array, "update", isolate->factory()->length_string(),
15141 old_length_handle),
15142 Object);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015143
Emily Bernierd0a1eb72015-03-24 16:35:39 -040015144 RETURN_ON_EXCEPTION(isolate, EndPerformSplice(array), Object);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015145
15146 uint32_t index = Min(old_length, new_length);
15147 uint32_t add_count = new_length > old_length ? new_length - old_length : 0;
15148 uint32_t delete_count = new_length < old_length ? old_length - new_length : 0;
15149 Handle<JSArray> deleted = isolate->factory()->NewJSArray(0);
15150 if (delete_count > 0) {
15151 for (int i = indices.length() - 1; i >= 0; i--) {
15152 // Skip deletions where the property was an accessor, leaving holes
15153 // in the array of old values.
15154 if (old_values[i]->IsTheHole()) continue;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000015155 JSObject::AddDataElement(deleted, indices[i] - index, old_values[i], NONE)
15156 .Assert();
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015157 }
15158
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000015159 JSArray::SetLength(deleted, delete_count);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015160 }
15161
Emily Bernierd0a1eb72015-03-24 16:35:39 -040015162 RETURN_ON_EXCEPTION(
15163 isolate, EnqueueSpliceRecord(array, index, deleted, add_count), Object);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015164
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000015165 return array;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015166}
15167
15168
15169// static
15170void Map::AddDependentCode(Handle<Map> map,
15171 DependentCode::DependencyGroup group,
15172 Handle<Code> code) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000015173 Handle<WeakCell> cell = Code::WeakCellFor(code);
15174 Handle<DependentCode> codes = DependentCode::InsertWeakCode(
15175 Handle<DependentCode>(map->dependent_code()), group, cell);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015176 if (*codes != map->dependent_code()) map->set_dependent_code(*codes);
15177}
15178
15179
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000015180Handle<DependentCode> DependentCode::InsertCompilationDependencies(
15181 Handle<DependentCode> entries, DependencyGroup group,
15182 Handle<Foreign> info) {
15183 return Insert(entries, group, info);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015184}
15185
15186
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000015187Handle<DependentCode> DependentCode::InsertWeakCode(
15188 Handle<DependentCode> entries, DependencyGroup group,
15189 Handle<WeakCell> code_cell) {
15190 return Insert(entries, group, code_cell);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015191}
15192
15193
15194Handle<DependentCode> DependentCode::Insert(Handle<DependentCode> entries,
15195 DependencyGroup group,
15196 Handle<Object> object) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000015197 if (entries->length() == 0 || entries->group() > group) {
15198 // There is no such group.
15199 return DependentCode::New(group, object, entries);
15200 }
15201 if (entries->group() < group) {
15202 // The group comes later in the list.
15203 Handle<DependentCode> old_next(entries->next_link());
15204 Handle<DependentCode> new_next = Insert(old_next, group, object);
15205 if (!old_next.is_identical_to(new_next)) {
15206 entries->set_next_link(*new_next);
15207 }
15208 return entries;
15209 }
15210 DCHECK_EQ(group, entries->group());
15211 int count = entries->count();
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015212 // Check for existing entry to avoid duplicates.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000015213 for (int i = 0; i < count; i++) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015214 if (entries->object_at(i) == *object) return entries;
15215 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000015216 if (entries->length() < kCodesStartIndex + count + 1) {
15217 entries = EnsureSpace(entries);
15218 // Count could have changed, reload it.
15219 count = entries->count();
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015220 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000015221 entries->set_object_at(count, *object);
15222 entries->set_count(count + 1);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015223 return entries;
15224}
15225
15226
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000015227Handle<DependentCode> DependentCode::New(DependencyGroup group,
15228 Handle<Object> object,
15229 Handle<DependentCode> next) {
15230 Isolate* isolate = next->GetIsolate();
15231 Handle<DependentCode> result = Handle<DependentCode>::cast(
15232 isolate->factory()->NewFixedArray(kCodesStartIndex + 1, TENURED));
15233 result->set_next_link(*next);
15234 result->set_flags(GroupField::encode(group) | CountField::encode(1));
15235 result->set_object_at(0, *object);
15236 return result;
15237}
15238
15239
15240Handle<DependentCode> DependentCode::EnsureSpace(
15241 Handle<DependentCode> entries) {
15242 if (entries->Compact()) return entries;
15243 Isolate* isolate = entries->GetIsolate();
15244 int capacity = kCodesStartIndex + DependentCode::Grow(entries->count());
15245 int grow_by = capacity - entries->length();
15246 return Handle<DependentCode>::cast(
15247 isolate->factory()->CopyFixedArrayAndGrow(entries, grow_by, TENURED));
15248}
15249
15250
15251bool DependentCode::Compact() {
15252 int old_count = count();
15253 int new_count = 0;
15254 for (int i = 0; i < old_count; i++) {
15255 Object* obj = object_at(i);
15256 if (!obj->IsWeakCell() || !WeakCell::cast(obj)->cleared()) {
15257 if (i != new_count) {
15258 copy(i, new_count);
15259 }
15260 new_count++;
15261 }
15262 }
15263 set_count(new_count);
15264 for (int i = new_count; i < old_count; i++) {
15265 clear_at(i);
15266 }
15267 return new_count < old_count;
15268}
15269
15270
15271void DependentCode::UpdateToFinishedCode(DependencyGroup group, Foreign* info,
15272 WeakCell* code_cell) {
15273 if (this->length() == 0 || this->group() > group) {
15274 // There is no such group.
15275 return;
15276 }
15277 if (this->group() < group) {
15278 // The group comes later in the list.
15279 next_link()->UpdateToFinishedCode(group, info, code_cell);
15280 return;
15281 }
15282 DCHECK_EQ(group, this->group());
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015283 DisallowHeapAllocation no_gc;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000015284 int count = this->count();
15285 for (int i = 0; i < count; i++) {
15286 if (object_at(i) == info) {
15287 set_object_at(i, code_cell);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015288 break;
15289 }
15290 }
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000015291#ifdef DEBUG
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000015292 for (int i = 0; i < count; i++) {
15293 DCHECK(object_at(i) != info);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015294 }
15295#endif
15296}
15297
15298
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000015299void DependentCode::RemoveCompilationDependencies(
15300 DependentCode::DependencyGroup group, Foreign* info) {
15301 if (this->length() == 0 || this->group() > group) {
15302 // There is no such group.
15303 return;
15304 }
15305 if (this->group() < group) {
15306 // The group comes later in the list.
15307 next_link()->RemoveCompilationDependencies(group, info);
15308 return;
15309 }
15310 DCHECK_EQ(group, this->group());
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015311 DisallowHeapAllocation no_allocation;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000015312 int old_count = count();
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015313 // Find compilation info wrapper.
15314 int info_pos = -1;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000015315 for (int i = 0; i < old_count; i++) {
15316 if (object_at(i) == info) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015317 info_pos = i;
15318 break;
15319 }
15320 }
15321 if (info_pos == -1) return; // Not found.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000015322 // Use the last code to fill the gap.
15323 if (info_pos < old_count - 1) {
15324 copy(old_count - 1, info_pos);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015325 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000015326 clear_at(old_count - 1);
15327 set_count(old_count - 1);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015328
15329#ifdef DEBUG
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000015330 for (int i = 0; i < old_count - 1; i++) {
15331 DCHECK(object_at(i) != info);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015332 }
15333#endif
15334}
15335
15336
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000015337bool DependentCode::Contains(DependencyGroup group, WeakCell* code_cell) {
15338 if (this->length() == 0 || this->group() > group) {
15339 // There is no such group.
15340 return false;
15341 }
15342 if (this->group() < group) {
15343 // The group comes later in the list.
15344 return next_link()->Contains(group, code_cell);
15345 }
15346 DCHECK_EQ(group, this->group());
15347 int count = this->count();
15348 for (int i = 0; i < count; i++) {
15349 if (object_at(i) == code_cell) return true;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015350 }
15351 return false;
15352}
15353
15354
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000015355bool DependentCode::IsEmpty(DependencyGroup group) {
15356 if (this->length() == 0 || this->group() > group) {
15357 // There is no such group.
15358 return true;
15359 }
15360 if (this->group() < group) {
15361 // The group comes later in the list.
15362 return next_link()->IsEmpty(group);
15363 }
15364 DCHECK_EQ(group, this->group());
15365 return count() == 0;
15366}
15367
15368
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015369bool DependentCode::MarkCodeForDeoptimization(
15370 Isolate* isolate,
15371 DependentCode::DependencyGroup group) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000015372 if (this->length() == 0 || this->group() > group) {
15373 // There is no such group.
15374 return false;
15375 }
15376 if (this->group() < group) {
15377 // The group comes later in the list.
15378 return next_link()->MarkCodeForDeoptimization(isolate, group);
15379 }
15380 DCHECK_EQ(group, this->group());
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015381 DisallowHeapAllocation no_allocation_scope;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015382 // Mark all the code that needs to be deoptimized.
15383 bool marked = false;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000015384 bool invalidate_embedded_objects = group == kWeakCodeGroup;
15385 int count = this->count();
15386 for (int i = 0; i < count; i++) {
15387 Object* obj = object_at(i);
15388 if (obj->IsWeakCell()) {
15389 WeakCell* cell = WeakCell::cast(obj);
15390 if (cell->cleared()) continue;
15391 Code* code = Code::cast(cell->value());
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015392 if (!code->marked_for_deoptimization()) {
15393 SetMarkedForDeoptimization(code, group);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000015394 if (invalidate_embedded_objects) {
15395 code->InvalidateEmbeddedObjects();
15396 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015397 marked = true;
15398 }
15399 } else {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000015400 DCHECK(obj->IsForeign());
15401 CompilationDependencies* info =
15402 reinterpret_cast<CompilationDependencies*>(
15403 Foreign::cast(obj)->foreign_address());
15404 info->Abort();
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015405 }
15406 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000015407 for (int i = 0; i < count; i++) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015408 clear_at(i);
15409 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000015410 set_count(0);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015411 return marked;
15412}
15413
15414
15415void DependentCode::DeoptimizeDependentCodeGroup(
15416 Isolate* isolate,
15417 DependentCode::DependencyGroup group) {
15418 DCHECK(AllowCodeDependencyChange::IsAllowed());
15419 DisallowHeapAllocation no_allocation_scope;
15420 bool marked = MarkCodeForDeoptimization(isolate, group);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015421 if (marked) Deoptimizer::DeoptimizeMarkedCode(isolate);
15422}
15423
15424
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015425void DependentCode::SetMarkedForDeoptimization(Code* code,
15426 DependencyGroup group) {
15427 code->set_marked_for_deoptimization(true);
15428 if (FLAG_trace_deopt &&
15429 (code->deoptimization_data() != code->GetHeap()->empty_fixed_array())) {
15430 DeoptimizationInputData* deopt_data =
15431 DeoptimizationInputData::cast(code->deoptimization_data());
15432 CodeTracer::Scope scope(code->GetHeap()->isolate()->GetCodeTracer());
15433 PrintF(scope.file(), "[marking dependent code 0x%08" V8PRIxPTR
15434 " (opt #%d) for deoptimization, reason: %s]\n",
15435 reinterpret_cast<intptr_t>(code),
15436 deopt_data->OptimizationId()->value(), DependencyGroupName(group));
15437 }
15438}
15439
15440
15441const char* DependentCode::DependencyGroupName(DependencyGroup group) {
15442 switch (group) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015443 case kWeakCodeGroup:
15444 return "weak-code";
15445 case kTransitionGroup:
15446 return "transition";
15447 case kPrototypeCheckGroup:
15448 return "prototype-check";
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015449 case kPropertyCellChangedGroup:
15450 return "property-cell-changed";
15451 case kFieldTypeGroup:
15452 return "field-type";
15453 case kInitialMapChangedGroup:
15454 return "initial-map-changed";
15455 case kAllocationSiteTenuringChangedGroup:
15456 return "allocation-site-tenuring-changed";
15457 case kAllocationSiteTransitionChangedGroup:
15458 return "allocation-site-transition-changed";
15459 }
15460 UNREACHABLE();
15461 return "?";
15462}
15463
15464
15465Handle<Map> Map::TransitionToPrototype(Handle<Map> map,
Emily Bernierd0a1eb72015-03-24 16:35:39 -040015466 Handle<Object> prototype,
15467 PrototypeOptimizationMode mode) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000015468 Handle<Map> new_map = TransitionArray::GetPrototypeTransition(map, prototype);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015469 if (new_map.is_null()) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -040015470 new_map = Copy(map, "TransitionToPrototype");
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000015471 TransitionArray::PutPrototypeTransition(map, prototype, new_map);
15472 Map::SetPrototype(new_map, prototype, mode);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015473 }
15474 return new_map;
15475}
15476
15477
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000015478Maybe<bool> JSReceiver::SetPrototype(Handle<JSReceiver> object,
15479 Handle<Object> value, bool from_javascript,
15480 ShouldThrow should_throw) {
15481 if (object->IsJSProxy()) {
15482 return JSProxy::SetPrototype(Handle<JSProxy>::cast(object), value,
15483 from_javascript, should_throw);
15484 }
15485 return JSObject::SetPrototype(Handle<JSObject>::cast(object), value,
15486 from_javascript, should_throw);
15487}
15488
15489
15490// ES6: 9.5.2 [[SetPrototypeOf]] (V)
15491// static
15492Maybe<bool> JSProxy::SetPrototype(Handle<JSProxy> proxy, Handle<Object> value,
15493 bool from_javascript,
15494 ShouldThrow should_throw) {
15495 Isolate* isolate = proxy->GetIsolate();
15496 STACK_CHECK(Nothing<bool>());
15497 Handle<Name> trap_name = isolate->factory()->setPrototypeOf_string();
15498 // 1. Assert: Either Type(V) is Object or Type(V) is Null.
15499 DCHECK(value->IsJSReceiver() || value->IsNull());
15500 // 2. Let handler be the value of the [[ProxyHandler]] internal slot of O.
15501 Handle<Object> handler(proxy->handler(), isolate);
15502 // 3. If handler is null, throw a TypeError exception.
15503 // 4. Assert: Type(handler) is Object.
15504 if (proxy->IsRevoked()) {
15505 isolate->Throw(*isolate->factory()->NewTypeError(
15506 MessageTemplate::kProxyRevoked, trap_name));
15507 return Nothing<bool>();
15508 }
15509 // 5. Let target be the value of the [[ProxyTarget]] internal slot.
15510 Handle<JSReceiver> target(proxy->target(), isolate);
15511 // 6. Let trap be ? GetMethod(handler, "getPrototypeOf").
15512 Handle<Object> trap;
15513 ASSIGN_RETURN_ON_EXCEPTION_VALUE(
15514 isolate, trap,
15515 Object::GetMethod(Handle<JSReceiver>::cast(handler), trap_name),
15516 Nothing<bool>());
15517 // 7. If trap is undefined, then return target.[[SetPrototypeOf]]().
15518 if (trap->IsUndefined()) {
15519 return JSReceiver::SetPrototype(target, value, from_javascript,
15520 should_throw);
15521 }
15522 // 8. Let booleanTrapResult be ToBoolean(? Call(trap, handler, «target, V»)).
15523 Handle<Object> argv[] = {target, value};
15524 Handle<Object> trap_result;
15525 ASSIGN_RETURN_ON_EXCEPTION_VALUE(
15526 isolate, trap_result,
15527 Execution::Call(isolate, trap, handler, arraysize(argv), argv),
15528 Nothing<bool>());
15529 bool bool_trap_result = trap_result->BooleanValue();
15530 // 9. Let extensibleTarget be ? IsExtensible(target).
15531 Maybe<bool> is_extensible = JSReceiver::IsExtensible(target);
15532 if (is_extensible.IsNothing()) return Nothing<bool>();
15533 // 10. If extensibleTarget is true, return booleanTrapResult.
15534 if (is_extensible.FromJust()) {
15535 if (bool_trap_result) return Just(true);
15536 RETURN_FAILURE(
15537 isolate, should_throw,
15538 NewTypeError(MessageTemplate::kProxyTrapReturnedFalsish, trap_name));
15539 }
15540 // 11. Let targetProto be ? target.[[GetPrototypeOf]]().
15541 Handle<Object> target_proto;
15542 ASSIGN_RETURN_ON_EXCEPTION_VALUE(isolate, target_proto,
15543 Object::GetPrototype(isolate, target),
15544 Nothing<bool>());
15545 // 12. If booleanTrapResult is true and SameValue(V, targetProto) is false,
15546 // throw a TypeError exception.
15547 if (bool_trap_result && !value->SameValue(*target_proto)) {
15548 isolate->Throw(*isolate->factory()->NewTypeError(
15549 MessageTemplate::kProxySetPrototypeOfNonExtensible));
15550 return Nothing<bool>();
15551 }
15552 // 13. Return booleanTrapResult.
15553 if (bool_trap_result) return Just(true);
15554 RETURN_FAILURE(
15555 isolate, should_throw,
15556 NewTypeError(MessageTemplate::kProxyTrapReturnedFalsish, trap_name));
15557}
15558
15559
15560Maybe<bool> JSObject::SetPrototype(Handle<JSObject> object,
15561 Handle<Object> value, bool from_javascript,
15562 ShouldThrow should_throw) {
15563 Isolate* isolate = object->GetIsolate();
15564
15565 const bool observed = from_javascript && object->map()->is_observed();
15566 Handle<Object> old_value;
15567 if (observed) {
15568 ASSIGN_RETURN_ON_EXCEPTION_VALUE(isolate, old_value,
15569 Object::GetPrototype(isolate, object),
15570 Nothing<bool>());
15571 }
15572
15573 Maybe<bool> result =
15574 SetPrototypeUnobserved(object, value, from_javascript, should_throw);
15575 MAYBE_RETURN(result, Nothing<bool>());
15576
15577 if (result.FromJust() && observed) {
15578 Handle<Object> new_value;
15579 ASSIGN_RETURN_ON_EXCEPTION_VALUE(isolate, new_value,
15580 Object::GetPrototype(isolate, object),
15581 Nothing<bool>());
15582 if (!new_value->SameValue(*old_value)) {
15583 RETURN_ON_EXCEPTION_VALUE(
15584 isolate, JSObject::EnqueueChangeRecord(
15585 object, "setPrototype",
15586 isolate->factory()->proto_string(), old_value),
15587 Nothing<bool>());
15588 }
15589 }
15590
15591 return result;
15592}
15593
15594
15595Maybe<bool> JSObject::SetPrototypeUnobserved(Handle<JSObject> object,
15596 Handle<Object> value,
15597 bool from_javascript,
15598 ShouldThrow should_throw) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015599#ifdef DEBUG
15600 int size = object->Size();
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000015601#endif
15602
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015603 Isolate* isolate = object->GetIsolate();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000015604
15605 if (from_javascript) {
15606 if (object->IsAccessCheckNeeded() &&
15607 !isolate->MayAccess(handle(isolate->context()), object)) {
15608 isolate->ReportFailedAccessCheck(object);
15609 RETURN_VALUE_IF_SCHEDULED_EXCEPTION(isolate, Nothing<bool>());
15610 RETURN_FAILURE(isolate, should_throw,
15611 NewTypeError(MessageTemplate::kNoAccess));
15612 }
15613 } else {
15614 DCHECK(!object->IsAccessCheckNeeded());
15615 }
15616
15617 // Strong objects may not have their prototype set via __proto__ or
15618 // setPrototypeOf.
15619 if (from_javascript && object->map()->is_strong()) {
15620 RETURN_FAILURE(isolate, should_throw,
15621 NewTypeError(MessageTemplate::kStrongSetProto, object));
15622 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015623 Heap* heap = isolate->heap();
Andrei Popescu402d9372010-02-26 13:31:12 +000015624 // Silently ignore the change if value is not a JSObject or null.
15625 // SpiderMonkey behaves this way.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000015626 if (!value->IsJSReceiver() && !value->IsNull()) return Just(true);
15627
15628 bool dictionary_elements_in_chain =
15629 object->map()->DictionaryElementsInPrototypeChainOnly();
15630
15631 bool all_extensible = object->map()->is_extensible();
15632 Handle<JSObject> real_receiver = object;
15633 if (from_javascript) {
15634 // Find the first object in the chain whose prototype object is not
15635 // hidden.
15636 PrototypeIterator iter(isolate, real_receiver);
15637 while (!iter.IsAtEnd(PrototypeIterator::END_AT_NON_HIDDEN)) {
15638 // Casting to JSObject is fine because hidden prototypes are never
15639 // JSProxies.
15640 real_receiver = PrototypeIterator::GetCurrent<JSObject>(iter);
15641 iter.Advance();
15642 all_extensible = all_extensible && real_receiver->map()->is_extensible();
15643 }
15644 }
15645 Handle<Map> map(real_receiver->map());
15646
15647 // Nothing to do if prototype is already set.
15648 if (map->prototype() == *value) return Just(true);
Andrei Popescu402d9372010-02-26 13:31:12 +000015649
Ben Murdoch8b112d22011-06-08 16:22:53 +010015650 // From 8.6.2 Object Internal Methods
15651 // ...
15652 // In addition, if [[Extensible]] is false the value of the [[Class]] and
15653 // [[Prototype]] internal properties of the object may not be modified.
15654 // ...
15655 // Implementation specific extensions that modify [[Class]], [[Prototype]]
15656 // or [[Extensible]] must not violate the invariants defined in the preceding
15657 // paragraph.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000015658 if (!all_extensible) {
15659 RETURN_FAILURE(isolate, should_throw,
15660 NewTypeError(MessageTemplate::kNonExtensibleProto, object));
Ben Murdoch8b112d22011-06-08 16:22:53 +010015661 }
15662
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000015663 // Before we can set the prototype we need to be sure prototype cycles are
15664 // prevented. It is sufficient to validate that the receiver is not in the
15665 // new prototype chain.
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015666 for (PrototypeIterator iter(isolate, *value,
15667 PrototypeIterator::START_AT_RECEIVER);
15668 !iter.IsAtEnd(); iter.Advance()) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000015669 if (iter.GetCurrent<JSReceiver>() == *object) {
Andrei Popescu402d9372010-02-26 13:31:12 +000015670 // Cycle detected.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000015671 RETURN_FAILURE(isolate, should_throw,
15672 NewTypeError(MessageTemplate::kCyclicProto));
Andrei Popescu402d9372010-02-26 13:31:12 +000015673 }
15674 }
15675
15676 // Set the new prototype of the object.
Steve Block053d10c2011-06-13 19:13:29 +010015677
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000015678 isolate->UpdateArrayProtectorOnSetPrototype(real_receiver);
Steve Block053d10c2011-06-13 19:13:29 +010015679
Emily Bernierd0a1eb72015-03-24 16:35:39 -040015680 PrototypeOptimizationMode mode =
15681 from_javascript ? REGULAR_PROTOTYPE : FAST_PROTOTYPE;
15682 Handle<Map> new_map = Map::TransitionToPrototype(map, value, mode);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015683 DCHECK(new_map->prototype() == *value);
15684 JSObject::MigrateToMap(real_receiver, new_map);
15685
Emily Bernierd0a1eb72015-03-24 16:35:39 -040015686 if (from_javascript && !dictionary_elements_in_chain &&
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015687 new_map->DictionaryElementsInPrototypeChainOnly()) {
15688 // If the prototype chain didn't previously have element callbacks, then
15689 // KeyedStoreICs need to be cleared to ensure any that involve this
15690 // map go generic.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000015691 TypeFeedbackVector::ClearAllKeyedStoreICs(isolate);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015692 }
Andrei Popescu402d9372010-02-26 13:31:12 +000015693
Steve Block44f0eee2011-05-26 01:26:41 +010015694 heap->ClearInstanceofCache();
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015695 DCHECK(size == object->Size());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000015696 return Just(true);
Andrei Popescu402d9372010-02-26 13:31:12 +000015697}
15698
15699
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015700void JSObject::EnsureCanContainElements(Handle<JSObject> object,
15701 Arguments* args,
15702 uint32_t first_arg,
15703 uint32_t arg_count,
15704 EnsureElementsMode mode) {
Ben Murdoch3ef787d2012-04-12 10:51:47 +010015705 // Elements in |Arguments| are ordered backwards (because they're on the
15706 // stack), but the method that's called here iterates over them in forward
15707 // direction.
15708 return EnsureCanContainElements(
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015709 object, args->arguments() - first_arg - (arg_count - 1), arg_count, mode);
Ben Murdoch592a9fc2012-03-05 11:04:45 +000015710}
15711
15712
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000015713ElementsAccessor* JSObject::GetElementsAccessor() {
15714 return ElementsAccessor::ForKind(GetElementsKind());
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015715}
15716
15717
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000015718void JSObject::ValidateElements(Handle<JSObject> object) {
15719#ifdef ENABLE_SLOW_DCHECKS
15720 if (FLAG_enable_slow_asserts) {
15721 ElementsAccessor* accessor = object->GetElementsAccessor();
15722 accessor->Validate(object);
Steve Blocka7e24c12009-10-30 11:49:00 +000015723 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000015724#endif
Steve Blocka7e24c12009-10-30 11:49:00 +000015725}
15726
15727
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000015728static bool ShouldConvertToSlowElements(JSObject* object, uint32_t capacity,
15729 uint32_t index,
15730 uint32_t* new_capacity) {
15731 STATIC_ASSERT(JSObject::kMaxUncheckedOldFastElementsLength <=
15732 JSObject::kMaxUncheckedFastElementsLength);
15733 if (index < capacity) {
15734 *new_capacity = capacity;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000015735 return false;
15736 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000015737 if (index - capacity >= JSObject::kMaxGap) return true;
15738 *new_capacity = JSObject::NewElementsCapacity(index + 1);
15739 DCHECK_LT(index, *new_capacity);
15740 if (*new_capacity <= JSObject::kMaxUncheckedOldFastElementsLength ||
15741 (*new_capacity <= JSObject::kMaxUncheckedFastElementsLength &&
15742 object->GetHeap()->InNewSpace(object))) {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000015743 return false;
15744 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000015745 // If the fast-case backing storage takes up roughly three times as
15746 // much space (in machine words) as a dictionary backing storage
15747 // would, the object should have slow elements.
15748 int used_elements = object->GetFastElementsUsage();
15749 int dictionary_size = SeededNumberDictionary::ComputeCapacity(used_elements) *
15750 SeededNumberDictionary::kEntrySize;
15751 return 3 * static_cast<uint32_t>(dictionary_size) <= *new_capacity;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000015752}
15753
15754
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000015755bool JSObject::WouldConvertToSlowElements(uint32_t index) {
15756 if (HasFastElements()) {
15757 Handle<FixedArrayBase> backing_store(FixedArrayBase::cast(elements()));
15758 uint32_t capacity = static_cast<uint32_t>(backing_store->length());
15759 uint32_t new_capacity;
15760 return ShouldConvertToSlowElements(this, capacity, index, &new_capacity);
15761 }
15762 return false;
15763}
15764
15765
15766static ElementsKind BestFittingFastElementsKind(JSObject* object) {
15767 if (object->HasSloppyArgumentsElements()) {
15768 return FAST_SLOPPY_ARGUMENTS_ELEMENTS;
15769 }
15770 DCHECK(object->HasDictionaryElements());
15771 SeededNumberDictionary* dictionary = object->element_dictionary();
15772 ElementsKind kind = FAST_HOLEY_SMI_ELEMENTS;
15773 for (int i = 0; i < dictionary->Capacity(); i++) {
15774 Object* key = dictionary->KeyAt(i);
15775 if (key->IsNumber()) {
15776 Object* value = dictionary->ValueAt(i);
15777 if (!value->IsNumber()) return FAST_HOLEY_ELEMENTS;
15778 if (!value->IsSmi()) {
15779 if (!FLAG_unbox_double_arrays) return FAST_HOLEY_ELEMENTS;
15780 kind = FAST_HOLEY_DOUBLE_ELEMENTS;
15781 }
15782 }
15783 }
15784 return kind;
15785}
15786
15787
15788static bool ShouldConvertToFastElements(JSObject* object,
15789 SeededNumberDictionary* dictionary,
15790 uint32_t index,
15791 uint32_t* new_capacity) {
15792 // If properties with non-standard attributes or accessors were added, we
15793 // cannot go back to fast elements.
15794 if (dictionary->requires_slow_elements()) return false;
15795
15796 // Adding a property with this index will require slow elements.
15797 if (index >= static_cast<uint32_t>(Smi::kMaxValue)) return false;
15798
15799 if (object->IsJSArray()) {
15800 Object* length = JSArray::cast(object)->length();
15801 if (!length->IsSmi()) return false;
15802 *new_capacity = static_cast<uint32_t>(Smi::cast(length)->value());
15803 } else {
15804 *new_capacity = dictionary->max_number_key() + 1;
15805 }
15806 *new_capacity = Max(index + 1, *new_capacity);
15807
15808 uint32_t dictionary_size = static_cast<uint32_t>(dictionary->Capacity()) *
15809 SeededNumberDictionary::kEntrySize;
15810
15811 // Turn fast if the dictionary only saves 50% space.
15812 return 2 * dictionary_size >= *new_capacity;
15813}
15814
15815
15816// static
15817MaybeHandle<Object> JSObject::AddDataElement(Handle<JSObject> object,
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015818 uint32_t index,
15819 Handle<Object> value,
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000015820 PropertyAttributes attributes) {
15821 MAYBE_RETURN_NULL(
15822 AddDataElement(object, index, value, attributes, THROW_ON_ERROR));
Ben Murdoch3ef787d2012-04-12 10:51:47 +010015823 return value;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000015824}
15825
15826
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000015827// static
15828Maybe<bool> JSObject::AddDataElement(Handle<JSObject> object, uint32_t index,
15829 Handle<Object> value,
15830 PropertyAttributes attributes,
15831 ShouldThrow should_throw) {
15832 DCHECK(object->map()->is_extensible());
15833
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015834 Isolate* isolate = object->GetIsolate();
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000015835
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000015836 uint32_t old_length = 0;
15837 uint32_t new_capacity = 0;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000015838
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015839 Handle<Object> old_length_handle;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000015840 if (object->IsJSArray()) {
15841 CHECK(JSArray::cast(*object)->length()->ToArrayLength(&old_length));
15842 if (object->map()->is_observed()) {
15843 old_length_handle = handle(JSArray::cast(*object)->length(), isolate);
15844 }
15845 }
15846
15847 ElementsKind kind = object->GetElementsKind();
15848 FixedArrayBase* elements = object->elements();
15849 ElementsKind dictionary_kind = DICTIONARY_ELEMENTS;
15850 if (IsSloppyArgumentsElements(kind)) {
15851 elements = FixedArrayBase::cast(FixedArray::cast(elements)->get(1));
15852 dictionary_kind = SLOW_SLOPPY_ARGUMENTS_ELEMENTS;
15853 }
15854
15855 if (attributes != NONE) {
15856 kind = dictionary_kind;
15857 } else if (elements->IsSeededNumberDictionary()) {
15858 kind = ShouldConvertToFastElements(*object,
15859 SeededNumberDictionary::cast(elements),
15860 index, &new_capacity)
15861 ? BestFittingFastElementsKind(*object)
15862 : dictionary_kind; // Overwrite in case of arguments.
15863 } else if (ShouldConvertToSlowElements(
15864 *object, static_cast<uint32_t>(elements->length()), index,
15865 &new_capacity)) {
15866 kind = dictionary_kind;
15867 }
15868
15869 ElementsKind to = value->OptimalElementsKind();
15870 if (IsHoleyElementsKind(kind) || !object->IsJSArray() || index > old_length) {
15871 to = GetHoleyElementsKind(to);
15872 kind = GetHoleyElementsKind(kind);
15873 }
15874 to = GetMoreGeneralElementsKind(kind, to);
15875 ElementsAccessor* accessor = ElementsAccessor::ForKind(to);
15876 accessor->Add(object, index, value, attributes, new_capacity);
15877
15878 uint32_t new_length = old_length;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015879 Handle<Object> new_length_handle;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000015880 if (object->IsJSArray() && index >= old_length) {
15881 new_length = index + 1;
15882 new_length_handle = isolate->factory()->NewNumberFromUint(new_length);
15883 JSArray::cast(*object)->set_length(*new_length_handle);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015884 }
15885
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000015886 if (!old_length_handle.is_null() && new_length != old_length) {
15887 // |old_length_handle| is kept null above unless the object is observed.
15888 DCHECK(object->map()->is_observed());
15889 Handle<JSArray> array = Handle<JSArray>::cast(object);
15890 Handle<String> name = isolate->factory()->Uint32ToString(index);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015891
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000015892 RETURN_ON_EXCEPTION_VALUE(isolate, BeginPerformSplice(array),
15893 Nothing<bool>());
15894 RETURN_ON_EXCEPTION_VALUE(
15895 isolate, EnqueueChangeRecord(array, "add", name,
15896 isolate->factory()->the_hole_value()),
15897 Nothing<bool>());
15898 RETURN_ON_EXCEPTION_VALUE(
15899 isolate, EnqueueChangeRecord(array, "update",
15900 isolate->factory()->length_string(),
15901 old_length_handle),
15902 Nothing<bool>());
15903 RETURN_ON_EXCEPTION_VALUE(isolate, EndPerformSplice(array),
15904 Nothing<bool>());
15905 Handle<JSArray> deleted = isolate->factory()->NewJSArray(0);
15906 RETURN_ON_EXCEPTION_VALUE(isolate,
15907 EnqueueSpliceRecord(array, old_length, deleted,
15908 new_length - old_length),
15909 Nothing<bool>());
15910 } else if (object->map()->is_observed()) {
15911 Handle<String> name = isolate->factory()->Uint32ToString(index);
15912 RETURN_ON_EXCEPTION_VALUE(
15913 isolate, EnqueueChangeRecord(object, "add", name,
15914 isolate->factory()->the_hole_value()),
15915 Nothing<bool>());
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015916 }
15917
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000015918 return Just(true);
Steve Blocka7e24c12009-10-30 11:49:00 +000015919}
15920
15921
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000015922bool JSArray::SetLengthWouldNormalize(uint32_t new_length) {
15923 if (!HasFastElements()) return false;
15924 uint32_t capacity = static_cast<uint32_t>(elements()->length());
15925 uint32_t new_capacity;
15926 return JSArray::SetLengthWouldNormalize(GetHeap(), new_length) &&
15927 ShouldConvertToSlowElements(this, capacity, new_length - 1,
15928 &new_capacity);
Steve Blocka7e24c12009-10-30 11:49:00 +000015929}
15930
15931
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015932const double AllocationSite::kPretenureRatio = 0.85;
15933
15934
15935void AllocationSite::ResetPretenureDecision() {
15936 set_pretenure_decision(kUndecided);
15937 set_memento_found_count(0);
15938 set_memento_create_count(0);
Ben Murdoch3ef787d2012-04-12 10:51:47 +010015939}
15940
15941
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015942PretenureFlag AllocationSite::GetPretenureMode() {
15943 PretenureDecision mode = pretenure_decision();
15944 // Zombie objects "decide" to be untenured.
15945 return mode == kTenure ? TENURED : NOT_TENURED;
15946}
Ben Murdoch3ef787d2012-04-12 10:51:47 +010015947
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015948
15949bool AllocationSite::IsNestedSite() {
15950 DCHECK(FLAG_trace_track_allocation_sites);
15951 Object* current = GetHeap()->allocation_sites_list();
15952 while (current->IsAllocationSite()) {
15953 AllocationSite* current_site = AllocationSite::cast(current);
15954 if (current_site->nested_site() == this) {
15955 return true;
Ben Murdoch3ef787d2012-04-12 10:51:47 +010015956 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015957 current = current_site->weak_next();
15958 }
15959 return false;
15960}
15961
15962
15963void AllocationSite::DigestTransitionFeedback(Handle<AllocationSite> site,
15964 ElementsKind to_kind) {
15965 Isolate* isolate = site->GetIsolate();
15966
15967 if (site->SitePointsToLiteral() && site->transition_info()->IsJSArray()) {
15968 Handle<JSArray> transition_info =
15969 handle(JSArray::cast(site->transition_info()));
15970 ElementsKind kind = transition_info->GetElementsKind();
15971 // if kind is holey ensure that to_kind is as well.
15972 if (IsHoleyElementsKind(kind)) {
15973 to_kind = GetHoleyElementsKind(to_kind);
15974 }
15975 if (IsMoreGeneralElementsKindTransition(kind, to_kind)) {
15976 // If the array is huge, it's not likely to be defined in a local
15977 // function, so we shouldn't make new instances of it very often.
15978 uint32_t length = 0;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000015979 CHECK(transition_info->length()->ToArrayLength(&length));
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015980 if (length <= kMaximumArrayBytesToPretransition) {
15981 if (FLAG_trace_track_allocation_sites) {
15982 bool is_nested = site->IsNestedSite();
15983 PrintF(
15984 "AllocationSite: JSArray %p boilerplate %s updated %s->%s\n",
15985 reinterpret_cast<void*>(*site),
15986 is_nested ? "(nested)" : "",
15987 ElementsKindToString(kind),
15988 ElementsKindToString(to_kind));
15989 }
15990 JSObject::TransitionElementsKind(transition_info, to_kind);
15991 site->dependent_code()->DeoptimizeDependentCodeGroup(
15992 isolate, DependentCode::kAllocationSiteTransitionChangedGroup);
15993 }
15994 }
15995 } else {
15996 ElementsKind kind = site->GetElementsKind();
15997 // if kind is holey ensure that to_kind is as well.
15998 if (IsHoleyElementsKind(kind)) {
15999 to_kind = GetHoleyElementsKind(to_kind);
16000 }
16001 if (IsMoreGeneralElementsKindTransition(kind, to_kind)) {
16002 if (FLAG_trace_track_allocation_sites) {
16003 PrintF("AllocationSite: JSArray %p site updated %s->%s\n",
16004 reinterpret_cast<void*>(*site),
16005 ElementsKindToString(kind),
16006 ElementsKindToString(to_kind));
16007 }
16008 site->SetElementsKind(to_kind);
16009 site->dependent_code()->DeoptimizeDependentCodeGroup(
16010 isolate, DependentCode::kAllocationSiteTransitionChangedGroup);
16011 }
16012 }
16013}
16014
16015
Ben Murdochb8a8cc12014-11-26 15:28:44 +000016016const char* AllocationSite::PretenureDecisionName(PretenureDecision decision) {
16017 switch (decision) {
16018 case kUndecided: return "undecided";
16019 case kDontTenure: return "don't tenure";
16020 case kMaybeTenure: return "maybe tenure";
16021 case kTenure: return "tenure";
16022 case kZombie: return "zombie";
16023 default: UNREACHABLE();
16024 }
16025 return NULL;
16026}
16027
16028
16029void JSObject::UpdateAllocationSite(Handle<JSObject> object,
16030 ElementsKind to_kind) {
16031 if (!object->IsJSArray()) return;
16032
16033 Heap* heap = object->GetHeap();
16034 if (!heap->InNewSpace(*object)) return;
16035
16036 Handle<AllocationSite> site;
16037 {
16038 DisallowHeapAllocation no_allocation;
16039
16040 AllocationMemento* memento = heap->FindAllocationMemento(*object);
16041 if (memento == NULL) return;
16042
16043 // Walk through to the Allocation Site
16044 site = handle(memento->GetAllocationSite());
16045 }
16046 AllocationSite::DigestTransitionFeedback(site, to_kind);
16047}
16048
16049
16050void JSObject::TransitionElementsKind(Handle<JSObject> object,
16051 ElementsKind to_kind) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000016052 ElementsKind from_kind = object->GetElementsKind();
Ben Murdochb8a8cc12014-11-26 15:28:44 +000016053
16054 if (IsFastHoleyElementsKind(from_kind)) {
16055 to_kind = GetHoleyElementsKind(to_kind);
Ben Murdoch3ef787d2012-04-12 10:51:47 +010016056 }
16057
Ben Murdochb8a8cc12014-11-26 15:28:44 +000016058 if (from_kind == to_kind) return;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000016059
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000016060 // This method should never be called for any other case.
16061 DCHECK(IsFastElementsKind(from_kind));
16062 DCHECK(IsFastElementsKind(to_kind));
16063 DCHECK_NE(TERMINAL_FAST_ELEMENTS_KIND, from_kind);
16064
16065 UpdateAllocationSite(object, to_kind);
16066 if (object->elements() == object->GetHeap()->empty_fixed_array() ||
16067 IsFastDoubleElementsKind(from_kind) ==
16068 IsFastDoubleElementsKind(to_kind)) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000016069 // No change is needed to the elements() buffer, the transition
16070 // only requires a map change.
16071 Handle<Map> new_map = GetElementsTransitionMap(object, to_kind);
16072 MigrateToMap(object, new_map);
16073 if (FLAG_trace_elements_transitions) {
16074 Handle<FixedArrayBase> elms(object->elements());
16075 PrintElementsTransition(stdout, object, from_kind, elms, to_kind, elms);
16076 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000016077 } else {
16078 DCHECK((IsFastSmiElementsKind(from_kind) &&
16079 IsFastDoubleElementsKind(to_kind)) ||
16080 (IsFastDoubleElementsKind(from_kind) &&
16081 IsFastObjectElementsKind(to_kind)));
16082 uint32_t c = static_cast<uint32_t>(object->elements()->length());
16083 ElementsAccessor::ForKind(to_kind)->GrowCapacityAndConvert(object, c);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000016084 }
Ben Murdoch3ef787d2012-04-12 10:51:47 +010016085}
16086
16087
16088// static
16089bool Map::IsValidElementsTransition(ElementsKind from_kind,
16090 ElementsKind to_kind) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000016091 // Transitions can't go backwards.
16092 if (!IsMoreGeneralElementsKindTransition(from_kind, to_kind)) {
16093 return false;
16094 }
16095
16096 // Transitions from HOLEY -> PACKED are not allowed.
16097 return !IsFastHoleyElementsKind(from_kind) ||
16098 IsFastHoleyElementsKind(to_kind);
Ben Murdoch3ef787d2012-04-12 10:51:47 +010016099}
16100
16101
Emily Bernierd0a1eb72015-03-24 16:35:39 -040016102bool JSArray::HasReadOnlyLength(Handle<JSArray> array) {
16103 LookupIterator it(array, array->GetIsolate()->factory()->length_string(),
16104 LookupIterator::OWN_SKIP_INTERCEPTOR);
16105 CHECK_NE(LookupIterator::ACCESS_CHECK, it.state());
16106 CHECK(it.IsFound());
16107 CHECK_EQ(LookupIterator::ACCESSOR, it.state());
16108 return it.IsReadOnly();
16109}
16110
16111
Ben Murdochb8a8cc12014-11-26 15:28:44 +000016112bool JSArray::WouldChangeReadOnlyLength(Handle<JSArray> array,
16113 uint32_t index) {
16114 uint32_t length = 0;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000016115 CHECK(array->length()->ToArrayLength(&length));
Emily Bernierd0a1eb72015-03-24 16:35:39 -040016116 if (length <= index) return HasReadOnlyLength(array);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000016117 return false;
16118}
16119
16120
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000016121template <typename BackingStore>
16122static int FastHoleyElementsUsage(JSObject* object, BackingStore* store) {
16123 int limit = object->IsJSArray()
16124 ? Smi::cast(JSArray::cast(object)->length())->value()
16125 : store->length();
Ben Murdoch69a99ed2011-11-30 16:03:39 +000016126 int used = 0;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000016127 for (int i = 0; i < limit; ++i) {
16128 if (!store->is_the_hole(i)) ++used;
16129 }
16130 return used;
Ben Murdoch69a99ed2011-11-30 16:03:39 +000016131}
16132
16133
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000016134int JSObject::GetFastElementsUsage() {
16135 FixedArrayBase* store = elements();
Steve Blocka7e24c12009-10-30 11:49:00 +000016136 switch (GetElementsKind()) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000016137 case FAST_SMI_ELEMENTS:
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000016138 case FAST_DOUBLE_ELEMENTS:
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000016139 case FAST_ELEMENTS:
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000016140 return IsJSArray() ? Smi::cast(JSArray::cast(this)->length())->value()
16141 : store->length();
16142 case FAST_SLOPPY_ARGUMENTS_ELEMENTS:
16143 store = FixedArray::cast(FixedArray::cast(store)->get(1));
16144 // Fall through.
Ben Murdochb8a8cc12014-11-26 15:28:44 +000016145 case FAST_HOLEY_SMI_ELEMENTS:
16146 case FAST_HOLEY_ELEMENTS:
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000016147 return FastHoleyElementsUsage(this, FixedArray::cast(store));
16148 case FAST_HOLEY_DOUBLE_ELEMENTS:
16149 if (elements()->length() == 0) return 0;
16150 return FastHoleyElementsUsage(this, FixedDoubleArray::cast(store));
Ben Murdochb8a8cc12014-11-26 15:28:44 +000016151
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000016152 case SLOW_SLOPPY_ARGUMENTS_ELEMENTS:
16153 case DICTIONARY_ELEMENTS:
Ben Murdochb8a8cc12014-11-26 15:28:44 +000016154#define TYPED_ARRAY_CASE(Type, type, TYPE, ctype, size) \
Ben Murdochb8a8cc12014-11-26 15:28:44 +000016155 case TYPE##_ELEMENTS: \
16156
16157 TYPED_ARRAYS(TYPED_ARRAY_CASE)
16158#undef TYPED_ARRAY_CASE
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000016159 UNREACHABLE();
Steve Blocka7e24c12009-10-30 11:49:00 +000016160 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000016161 return 0;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000016162}
16163
16164
Steve Blocka7e24c12009-10-30 11:49:00 +000016165// Certain compilers request function template instantiation when they
16166// see the definition of the other template functions in the
16167// class. This requires us to have the template functions put
16168// together, so even though this function belongs in objects-debug.cc,
16169// we keep it here instead to satisfy certain compilers.
Ben Murdochb0fe1622011-05-05 13:52:32 +010016170#ifdef OBJECT_PRINT
Ben Murdochb8a8cc12014-11-26 15:28:44 +000016171template <typename Derived, typename Shape, typename Key>
Emily Bernierd0a1eb72015-03-24 16:35:39 -040016172void Dictionary<Derived, Shape, Key>::Print(std::ostream& os) { // NOLINT
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000016173 int capacity = this->Capacity();
Steve Blocka7e24c12009-10-30 11:49:00 +000016174 for (int i = 0; i < capacity; i++) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000016175 Object* k = this->KeyAt(i);
16176 if (this->IsKey(k)) {
16177 os << "\n ";
Steve Blocka7e24c12009-10-30 11:49:00 +000016178 if (k->IsString()) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000016179 String::cast(k)->StringPrint(os);
Steve Blocka7e24c12009-10-30 11:49:00 +000016180 } else {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000016181 os << Brief(k);
Steve Blocka7e24c12009-10-30 11:49:00 +000016182 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000016183 os << ": " << Brief(this->ValueAt(i)) << " " << this->DetailsAt(i);
Steve Blocka7e24c12009-10-30 11:49:00 +000016184 }
16185 }
16186}
16187#endif
16188
16189
Ben Murdochb8a8cc12014-11-26 15:28:44 +000016190template<typename Derived, typename Shape, typename Key>
16191void Dictionary<Derived, Shape, Key>::CopyValuesTo(FixedArray* elements) {
Steve Blocka7e24c12009-10-30 11:49:00 +000016192 int pos = 0;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000016193 int capacity = this->Capacity();
Ben Murdochb8a8cc12014-11-26 15:28:44 +000016194 DisallowHeapAllocation no_gc;
Leon Clarke4515c472010-02-03 11:58:03 +000016195 WriteBarrierMode mode = elements->GetWriteBarrierMode(no_gc);
Steve Blocka7e24c12009-10-30 11:49:00 +000016196 for (int i = 0; i < capacity; i++) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000016197 Object* k = this->KeyAt(i);
16198 if (this->IsKey(k)) {
16199 elements->set(pos++, this->ValueAt(i), mode);
Steve Blocka7e24c12009-10-30 11:49:00 +000016200 }
16201 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +000016202 DCHECK(pos == elements->length());
Steve Blocka7e24c12009-10-30 11:49:00 +000016203}
16204
16205
16206InterceptorInfo* JSObject::GetNamedInterceptor() {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000016207 DCHECK(map()->has_named_interceptor());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000016208 JSFunction* constructor = JSFunction::cast(map()->GetConstructor());
Ben Murdochb8a8cc12014-11-26 15:28:44 +000016209 DCHECK(constructor->shared()->IsApiFunction());
Steve Blocka7e24c12009-10-30 11:49:00 +000016210 Object* result =
Steve Block6ded16b2010-05-10 14:33:55 +010016211 constructor->shared()->get_api_func_data()->named_property_handler();
Steve Blocka7e24c12009-10-30 11:49:00 +000016212 return InterceptorInfo::cast(result);
16213}
16214
16215
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000016216MaybeHandle<Object> JSObject::GetPropertyWithInterceptor(LookupIterator* it,
16217 bool* done) {
16218 *done = false;
16219 Isolate* isolate = it->isolate();
16220 // Make sure that the top context does not change when doing callbacks or
16221 // interceptor calls.
16222 AssertNoContextChange ncc(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +000016223
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000016224 DCHECK_EQ(LookupIterator::INTERCEPTOR, it->state());
16225 Handle<InterceptorInfo> interceptor = it->GetInterceptor();
16226 if (interceptor->getter()->IsUndefined()) {
16227 return isolate->factory()->undefined_value();
Emily Bernierd0a1eb72015-03-24 16:35:39 -040016228 }
16229
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000016230 Handle<JSObject> holder = it->GetHolder<JSObject>();
16231 v8::Local<v8::Value> result;
16232 PropertyCallbackArguments args(isolate, interceptor->data(),
16233 *it->GetReceiver(), *holder);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000016234
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000016235 if (it->IsElement()) {
16236 uint32_t index = it->index();
16237 v8::IndexedPropertyGetterCallback getter =
16238 v8::ToCData<v8::IndexedPropertyGetterCallback>(interceptor->getter());
16239 LOG(isolate,
16240 ApiIndexedPropertyAccess("interceptor-indexed-get", *holder, index));
16241 result = args.Call(getter, index);
16242 } else {
16243 Handle<Name> name = it->name();
16244 DCHECK(!name->IsPrivate());
16245
16246 if (name->IsSymbol() && !interceptor->can_intercept_symbols()) {
16247 return isolate->factory()->undefined_value();
16248 }
16249
16250 v8::GenericNamedPropertyGetterCallback getter =
16251 v8::ToCData<v8::GenericNamedPropertyGetterCallback>(
16252 interceptor->getter());
16253 LOG(isolate,
16254 ApiNamedPropertyAccess("interceptor-named-get", *holder, *name));
16255 result = args.Call(getter, v8::Utils::ToLocal(name));
16256 }
16257
16258 RETURN_EXCEPTION_IF_SCHEDULED_EXCEPTION(isolate, Object);
16259 if (result.IsEmpty()) return isolate->factory()->undefined_value();
Ben Murdochb8a8cc12014-11-26 15:28:44 +000016260 Handle<Object> result_internal = v8::Utils::OpenHandle(*result);
16261 result_internal->VerifyApiCallResultType();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000016262 *done = true;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000016263 // Rebox handle before return
16264 return handle(*result_internal, isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +000016265}
16266
16267
Ben Murdochb8a8cc12014-11-26 15:28:44 +000016268Maybe<bool> JSObject::HasRealNamedProperty(Handle<JSObject> object,
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000016269 Handle<Name> name) {
16270 LookupIterator it = LookupIterator::PropertyOrElement(
16271 name->GetIsolate(), object, name, LookupIterator::OWN_SKIP_INTERCEPTOR);
16272 return HasProperty(&it);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000016273}
16274
16275
16276Maybe<bool> JSObject::HasRealElementProperty(Handle<JSObject> object,
16277 uint32_t index) {
16278 Isolate* isolate = object->GetIsolate();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000016279 LookupIterator it(isolate, object, index,
16280 LookupIterator::OWN_SKIP_INTERCEPTOR);
16281 return HasProperty(&it);
Steve Blocka7e24c12009-10-30 11:49:00 +000016282}
16283
16284
Ben Murdochb8a8cc12014-11-26 15:28:44 +000016285Maybe<bool> JSObject::HasRealNamedCallbackProperty(Handle<JSObject> object,
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000016286 Handle<Name> name) {
16287 LookupIterator it = LookupIterator::PropertyOrElement(
16288 name->GetIsolate(), object, name, LookupIterator::OWN_SKIP_INTERCEPTOR);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000016289 Maybe<PropertyAttributes> maybe_result = GetPropertyAttributes(&it);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000016290 return maybe_result.IsJust() ? Just(it.state() == LookupIterator::ACCESSOR)
16291 : Nothing<bool>();
Steve Blocka7e24c12009-10-30 11:49:00 +000016292}
16293
16294
16295void FixedArray::SwapPairs(FixedArray* numbers, int i, int j) {
16296 Object* temp = get(i);
16297 set(i, get(j));
16298 set(j, temp);
16299 if (this != numbers) {
16300 temp = numbers->get(i);
Ben Murdoch3ef787d2012-04-12 10:51:47 +010016301 numbers->set(i, Smi::cast(numbers->get(j)));
16302 numbers->set(j, Smi::cast(temp));
Steve Blocka7e24c12009-10-30 11:49:00 +000016303 }
16304}
16305
16306
16307static void InsertionSortPairs(FixedArray* content,
16308 FixedArray* numbers,
16309 int len) {
16310 for (int i = 1; i < len; i++) {
16311 int j = i;
16312 while (j > 0 &&
16313 (NumberToUint32(numbers->get(j - 1)) >
16314 NumberToUint32(numbers->get(j)))) {
16315 content->SwapPairs(numbers, j - 1, j);
16316 j--;
16317 }
16318 }
16319}
16320
16321
16322void HeapSortPairs(FixedArray* content, FixedArray* numbers, int len) {
16323 // In-place heap sort.
Ben Murdochb8a8cc12014-11-26 15:28:44 +000016324 DCHECK(content->length() == numbers->length());
Steve Blocka7e24c12009-10-30 11:49:00 +000016325
16326 // Bottom-up max-heap construction.
16327 for (int i = 1; i < len; ++i) {
16328 int child_index = i;
16329 while (child_index > 0) {
16330 int parent_index = ((child_index + 1) >> 1) - 1;
16331 uint32_t parent_value = NumberToUint32(numbers->get(parent_index));
16332 uint32_t child_value = NumberToUint32(numbers->get(child_index));
16333 if (parent_value < child_value) {
16334 content->SwapPairs(numbers, parent_index, child_index);
16335 } else {
16336 break;
16337 }
16338 child_index = parent_index;
16339 }
16340 }
16341
16342 // Extract elements and create sorted array.
16343 for (int i = len - 1; i > 0; --i) {
16344 // Put max element at the back of the array.
16345 content->SwapPairs(numbers, 0, i);
16346 // Sift down the new top element.
16347 int parent_index = 0;
16348 while (true) {
16349 int child_index = ((parent_index + 1) << 1) - 1;
16350 if (child_index >= i) break;
16351 uint32_t child1_value = NumberToUint32(numbers->get(child_index));
16352 uint32_t child2_value = NumberToUint32(numbers->get(child_index + 1));
16353 uint32_t parent_value = NumberToUint32(numbers->get(parent_index));
16354 if (child_index + 1 >= i || child1_value > child2_value) {
16355 if (parent_value > child1_value) break;
16356 content->SwapPairs(numbers, parent_index, child_index);
16357 parent_index = child_index;
16358 } else {
16359 if (parent_value > child2_value) break;
16360 content->SwapPairs(numbers, parent_index, child_index + 1);
16361 parent_index = child_index + 1;
16362 }
16363 }
16364 }
16365}
16366
16367
16368// Sort this array and the numbers as pairs wrt. the (distinct) numbers.
16369void FixedArray::SortPairs(FixedArray* numbers, uint32_t len) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000016370 DCHECK(this->length() == numbers->length());
Steve Blocka7e24c12009-10-30 11:49:00 +000016371 // For small arrays, simply use insertion sort.
16372 if (len <= 10) {
16373 InsertionSortPairs(this, numbers, len);
16374 return;
16375 }
16376 // Check the range of indices.
16377 uint32_t min_index = NumberToUint32(numbers->get(0));
16378 uint32_t max_index = min_index;
16379 uint32_t i;
16380 for (i = 1; i < len; i++) {
16381 if (NumberToUint32(numbers->get(i)) < min_index) {
16382 min_index = NumberToUint32(numbers->get(i));
16383 } else if (NumberToUint32(numbers->get(i)) > max_index) {
16384 max_index = NumberToUint32(numbers->get(i));
16385 }
16386 }
16387 if (max_index - min_index + 1 == len) {
16388 // Indices form a contiguous range, unless there are duplicates.
16389 // Do an in-place linear time sort assuming distinct numbers, but
16390 // avoid hanging in case they are not.
16391 for (i = 0; i < len; i++) {
16392 uint32_t p;
16393 uint32_t j = 0;
16394 // While the current element at i is not at its correct position p,
16395 // swap the elements at these two positions.
16396 while ((p = NumberToUint32(numbers->get(i)) - min_index) != i &&
16397 j++ < len) {
16398 SwapPairs(numbers, i, p);
16399 }
16400 }
16401 } else {
16402 HeapSortPairs(this, numbers, len);
16403 return;
16404 }
16405}
16406
16407
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000016408void JSObject::CollectOwnPropertyNames(KeyAccumulator* keys,
16409 PropertyFilter filter) {
Steve Blocka7e24c12009-10-30 11:49:00 +000016410 if (HasFastProperties()) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000016411 int real_size = map()->NumberOfOwnDescriptors();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000016412 Handle<DescriptorArray> descs(map()->instance_descriptors());
Ben Murdochb8a8cc12014-11-26 15:28:44 +000016413 for (int i = 0; i < real_size; i++) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000016414 PropertyDetails details = descs->GetDetails(i);
16415 if ((details.attributes() & filter) != 0) continue;
16416 if (filter & ONLY_ALL_CAN_READ) {
16417 if (details.kind() != kAccessor) continue;
16418 Object* accessors = descs->GetValue(i);
16419 if (!accessors->IsAccessorInfo()) continue;
16420 if (!AccessorInfo::cast(accessors)->all_can_read()) continue;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000016421 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000016422 Name* key = descs->GetKey(i);
16423 if (key->FilterKey(filter)) continue;
16424 keys->AddKey(key);
Steve Blocka7e24c12009-10-30 11:49:00 +000016425 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000016426 } else if (IsJSGlobalObject()) {
16427 GlobalDictionary::CollectKeysTo(handle(global_dictionary()), keys, filter);
Steve Blocka7e24c12009-10-30 11:49:00 +000016428 } else {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000016429 NameDictionary::CollectKeysTo(handle(property_dictionary()), keys, filter);
Steve Blocka7e24c12009-10-30 11:49:00 +000016430 }
16431}
16432
16433
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000016434int JSObject::NumberOfOwnElements(PropertyFilter filter) {
16435 // Fast case for objects with no elements.
16436 if (!IsJSValue() && HasFastElements()) {
16437 uint32_t length =
16438 IsJSArray()
16439 ? static_cast<uint32_t>(
16440 Smi::cast(JSArray::cast(this)->length())->value())
16441 : static_cast<uint32_t>(FixedArrayBase::cast(elements())->length());
16442 if (length == 0) return 0;
16443 }
16444 // Compute the number of enumerable elements.
Ben Murdochb8a8cc12014-11-26 15:28:44 +000016445 return GetOwnElementKeys(NULL, filter);
Steve Blocka7e24c12009-10-30 11:49:00 +000016446}
16447
16448
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000016449void JSObject::CollectOwnElementKeys(Handle<JSObject> object,
16450 KeyAccumulator* keys,
16451 PropertyFilter filter) {
16452 if (filter & SKIP_STRINGS) return;
16453 uint32_t string_keys = 0;
16454
16455 // If this is a String wrapper, add the string indices first,
16456 // as they're guaranteed to precede the elements in numerical order
16457 // and ascending order is required by ECMA-262, 6th, 9.1.12.
16458 if (object->IsJSValue()) {
16459 Object* val = JSValue::cast(*object)->value();
16460 if (val->IsString() && (filter & ONLY_ALL_CAN_READ) == 0) {
16461 String* str = String::cast(val);
16462 string_keys = str->length();
16463 for (uint32_t i = 0; i < string_keys; i++) {
16464 keys->AddKey(i);
16465 }
16466 }
Steve Blockd0582a62009-12-15 09:54:21 +000016467 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000016468 ElementsAccessor* accessor = object->GetElementsAccessor();
16469 accessor->CollectElementIndices(object, keys, kMaxUInt32, filter, 0);
Steve Blocka7e24c12009-10-30 11:49:00 +000016470}
16471
16472
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000016473int JSObject::GetOwnElementKeys(FixedArray* storage, PropertyFilter filter) {
Steve Blocka7e24c12009-10-30 11:49:00 +000016474 int counter = 0;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000016475
16476 // If this is a String wrapper, add the string indices first,
16477 // as they're guaranteed to precede the elements in numerical order
16478 // and ascending order is required by ECMA-262, 6th, 9.1.12.
16479 if (IsJSValue()) {
16480 Object* val = JSValue::cast(this)->value();
16481 if (val->IsString()) {
16482 String* str = String::cast(val);
16483 if (storage) {
16484 for (int i = 0; i < str->length(); i++) {
16485 storage->set(counter + i, Smi::FromInt(i));
16486 }
16487 }
16488 counter += str->length();
16489 }
16490 }
16491
Steve Blocka7e24c12009-10-30 11:49:00 +000016492 switch (GetElementsKind()) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000016493 case FAST_SMI_ELEMENTS:
16494 case FAST_ELEMENTS:
16495 case FAST_HOLEY_SMI_ELEMENTS:
16496 case FAST_HOLEY_ELEMENTS: {
Steve Blocka7e24c12009-10-30 11:49:00 +000016497 int length = IsJSArray() ?
16498 Smi::cast(JSArray::cast(this)->length())->value() :
16499 FixedArray::cast(elements())->length();
16500 for (int i = 0; i < length; i++) {
16501 if (!FixedArray::cast(elements())->get(i)->IsTheHole()) {
16502 if (storage != NULL) {
Leon Clarke4515c472010-02-03 11:58:03 +000016503 storage->set(counter, Smi::FromInt(i));
Steve Blocka7e24c12009-10-30 11:49:00 +000016504 }
16505 counter++;
16506 }
16507 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +000016508 DCHECK(!storage || storage->length() >= counter);
Steve Blocka7e24c12009-10-30 11:49:00 +000016509 break;
16510 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +000016511 case FAST_DOUBLE_ELEMENTS:
16512 case FAST_HOLEY_DOUBLE_ELEMENTS: {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000016513 int length = IsJSArray() ?
16514 Smi::cast(JSArray::cast(this)->length())->value() :
Ben Murdochb8a8cc12014-11-26 15:28:44 +000016515 FixedArrayBase::cast(elements())->length();
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000016516 for (int i = 0; i < length; i++) {
16517 if (!FixedDoubleArray::cast(elements())->is_the_hole(i)) {
16518 if (storage != NULL) {
16519 storage->set(counter, Smi::FromInt(i));
16520 }
16521 counter++;
16522 }
16523 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +000016524 DCHECK(!storage || storage->length() >= counter);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000016525 break;
16526 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +000016527
16528#define TYPED_ARRAY_CASE(Type, type, TYPE, ctype, size) \
Ben Murdochb8a8cc12014-11-26 15:28:44 +000016529 case TYPE##_ELEMENTS: \
16530
16531 TYPED_ARRAYS(TYPED_ARRAY_CASE)
16532#undef TYPED_ARRAY_CASE
16533 {
16534 int length = FixedArrayBase::cast(elements())->length();
Steve Blocka7e24c12009-10-30 11:49:00 +000016535 while (counter < length) {
16536 if (storage != NULL) {
Leon Clarke4515c472010-02-03 11:58:03 +000016537 storage->set(counter, Smi::FromInt(counter));
Steve Blocka7e24c12009-10-30 11:49:00 +000016538 }
16539 counter++;
16540 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +000016541 DCHECK(!storage || storage->length() >= counter);
Steve Blocka7e24c12009-10-30 11:49:00 +000016542 break;
16543 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +000016544
Steve Blocka7e24c12009-10-30 11:49:00 +000016545 case DICTIONARY_ELEMENTS: {
16546 if (storage != NULL) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000016547 element_dictionary()->CopyKeysTo(storage, counter, filter,
Ben Murdochc7cc0282012-03-05 14:35:55 +000016548 SeededNumberDictionary::SORTED);
Steve Blocka7e24c12009-10-30 11:49:00 +000016549 }
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000016550 counter += element_dictionary()->NumberOfElementsFilterAttributes(filter);
Steve Blocka7e24c12009-10-30 11:49:00 +000016551 break;
16552 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000016553 case FAST_SLOPPY_ARGUMENTS_ELEMENTS:
16554 case SLOW_SLOPPY_ARGUMENTS_ELEMENTS: {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000016555 FixedArray* parameter_map = FixedArray::cast(elements());
16556 int mapped_length = parameter_map->length() - 2;
16557 FixedArray* arguments = FixedArray::cast(parameter_map->get(1));
16558 if (arguments->IsDictionary()) {
16559 // Copy the keys from arguments first, because Dictionary::CopyKeysTo
16560 // will insert in storage starting at index 0.
Ben Murdochc7cc0282012-03-05 14:35:55 +000016561 SeededNumberDictionary* dictionary =
16562 SeededNumberDictionary::cast(arguments);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000016563 if (storage != NULL) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000016564 dictionary->CopyKeysTo(storage, counter, filter,
16565 SeededNumberDictionary::UNSORTED);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000016566 }
16567 counter += dictionary->NumberOfElementsFilterAttributes(filter);
16568 for (int i = 0; i < mapped_length; ++i) {
16569 if (!parameter_map->get(i + 2)->IsTheHole()) {
16570 if (storage != NULL) storage->set(counter, Smi::FromInt(i));
16571 ++counter;
16572 }
16573 }
16574 if (storage != NULL) storage->SortPairs(storage, counter);
16575
16576 } else {
16577 int backing_length = arguments->length();
16578 int i = 0;
16579 for (; i < mapped_length; ++i) {
16580 if (!parameter_map->get(i + 2)->IsTheHole()) {
16581 if (storage != NULL) storage->set(counter, Smi::FromInt(i));
16582 ++counter;
16583 } else if (i < backing_length && !arguments->get(i)->IsTheHole()) {
16584 if (storage != NULL) storage->set(counter, Smi::FromInt(i));
16585 ++counter;
16586 }
16587 }
16588 for (; i < backing_length; ++i) {
16589 if (storage != NULL) storage->set(counter, Smi::FromInt(i));
16590 ++counter;
16591 }
16592 }
Steve Blocka7e24c12009-10-30 11:49:00 +000016593 break;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000016594 }
Steve Blocka7e24c12009-10-30 11:49:00 +000016595 }
16596
Ben Murdochb8a8cc12014-11-26 15:28:44 +000016597 DCHECK(!storage || storage->length() == counter);
Steve Blocka7e24c12009-10-30 11:49:00 +000016598 return counter;
16599}
16600
16601
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000016602MaybeHandle<String> Object::ObjectProtoToString(Isolate* isolate,
16603 Handle<Object> object) {
16604 if (object->IsUndefined()) return isolate->factory()->undefined_to_string();
16605 if (object->IsNull()) return isolate->factory()->null_to_string();
16606
16607 Handle<JSReceiver> receiver;
16608 CHECK(Object::ToObject(isolate, object).ToHandle(&receiver));
16609
16610 Handle<String> tag;
16611 if (FLAG_harmony_tostring) {
16612 Handle<Object> to_string_tag;
16613 ASSIGN_RETURN_ON_EXCEPTION(
16614 isolate, to_string_tag,
16615 GetProperty(receiver, isolate->factory()->to_string_tag_symbol()),
16616 String);
16617 if (to_string_tag->IsString()) {
16618 tag = Handle<String>::cast(to_string_tag);
16619 }
16620 }
16621
16622 if (tag.is_null()) {
16623 ASSIGN_RETURN_ON_EXCEPTION(isolate, tag,
16624 JSReceiver::BuiltinStringTag(receiver), String);
16625 }
16626
16627 IncrementalStringBuilder builder(isolate);
16628 builder.AppendCString("[object ");
16629 builder.AppendString(tag);
16630 builder.AppendCharacter(']');
16631 return builder.Finish();
Steve Blocka7e24c12009-10-30 11:49:00 +000016632}
16633
16634
Emily Bernierd0a1eb72015-03-24 16:35:39 -040016635const char* Symbol::PrivateSymbolToName() const {
16636 Heap* heap = GetIsolate()->heap();
16637#define SYMBOL_CHECK_AND_PRINT(name) \
16638 if (this == heap->name()) return #name;
16639 PRIVATE_SYMBOL_LIST(SYMBOL_CHECK_AND_PRINT)
16640#undef SYMBOL_CHECK_AND_PRINT
16641 return "UNKNOWN";
16642}
16643
16644
16645void Symbol::SymbolShortPrint(std::ostream& os) {
16646 os << "<Symbol: " << Hash();
16647 if (!name()->IsUndefined()) {
16648 os << " ";
16649 HeapStringAllocator allocator;
16650 StringStream accumulator(&allocator);
16651 String::cast(name())->StringShortPrint(&accumulator);
16652 os << accumulator.ToCString().get();
16653 } else {
16654 os << " (" << PrivateSymbolToName() << ")";
16655 }
16656 os << ">";
16657}
16658
16659
Steve Blocka7e24c12009-10-30 11:49:00 +000016660// StringSharedKeys are used as keys in the eval cache.
16661class StringSharedKey : public HashTableKey {
16662 public:
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000016663 StringSharedKey(Handle<String> source, Handle<SharedFunctionInfo> shared,
16664 LanguageMode language_mode, int scope_position)
Steve Block1e0659c2011-05-24 12:43:12 +010016665 : source_(source),
16666 shared_(shared),
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000016667 language_mode_(language_mode),
16668 scope_position_(scope_position) {}
Steve Blocka7e24c12009-10-30 11:49:00 +000016669
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000016670 bool IsMatch(Object* other) override {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000016671 DisallowHeapAllocation no_allocation;
Emily Bernierd0a1eb72015-03-24 16:35:39 -040016672 if (!other->IsFixedArray()) {
16673 if (!other->IsNumber()) return false;
16674 uint32_t other_hash = static_cast<uint32_t>(other->Number());
16675 return Hash() == other_hash;
16676 }
Ben Murdoch3ef787d2012-04-12 10:51:47 +010016677 FixedArray* other_array = FixedArray::cast(other);
16678 SharedFunctionInfo* shared = SharedFunctionInfo::cast(other_array->get(0));
Ben Murdochb8a8cc12014-11-26 15:28:44 +000016679 if (shared != *shared_) return false;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000016680 int language_unchecked = Smi::cast(other_array->get(2))->value();
16681 DCHECK(is_valid_language_mode(language_unchecked));
16682 LanguageMode language_mode = static_cast<LanguageMode>(language_unchecked);
16683 if (language_mode != language_mode_) return false;
Ben Murdoch3ef787d2012-04-12 10:51:47 +010016684 int scope_position = Smi::cast(other_array->get(3))->value();
16685 if (scope_position != scope_position_) return false;
16686 String* source = String::cast(other_array->get(1));
Ben Murdochb8a8cc12014-11-26 15:28:44 +000016687 return source->Equals(*source_);
Steve Blocka7e24c12009-10-30 11:49:00 +000016688 }
16689
16690 static uint32_t StringSharedHashHelper(String* source,
Steve Block1e0659c2011-05-24 12:43:12 +010016691 SharedFunctionInfo* shared,
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000016692 LanguageMode language_mode,
Ben Murdoch3ef787d2012-04-12 10:51:47 +010016693 int scope_position) {
Steve Blocka7e24c12009-10-30 11:49:00 +000016694 uint32_t hash = source->Hash();
16695 if (shared->HasSourceCode()) {
16696 // Instead of using the SharedFunctionInfo pointer in the hash
16697 // code computation, we use a combination of the hash of the
Ben Murdoch3ef787d2012-04-12 10:51:47 +010016698 // script source code and the start position of the calling scope.
16699 // We do this to ensure that the cache entries can survive garbage
Steve Blocka7e24c12009-10-30 11:49:00 +000016700 // collection.
Ben Murdochb8a8cc12014-11-26 15:28:44 +000016701 Script* script(Script::cast(shared->script()));
Steve Blocka7e24c12009-10-30 11:49:00 +000016702 hash ^= String::cast(script->source())->Hash();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000016703 STATIC_ASSERT(LANGUAGE_END == 3);
16704 if (is_strict(language_mode)) hash ^= 0x8000;
16705 if (is_strong(language_mode)) hash ^= 0x10000;
Ben Murdoch3ef787d2012-04-12 10:51:47 +010016706 hash += scope_position;
Steve Blocka7e24c12009-10-30 11:49:00 +000016707 }
16708 return hash;
16709 }
16710
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000016711 uint32_t Hash() override {
16712 return StringSharedHashHelper(*source_, *shared_, language_mode_,
Ben Murdochb8a8cc12014-11-26 15:28:44 +000016713 scope_position_);
Steve Blocka7e24c12009-10-30 11:49:00 +000016714 }
16715
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000016716 uint32_t HashForObject(Object* obj) override {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000016717 DisallowHeapAllocation no_allocation;
Emily Bernierd0a1eb72015-03-24 16:35:39 -040016718 if (obj->IsNumber()) {
16719 return static_cast<uint32_t>(obj->Number());
16720 }
Ben Murdoch3ef787d2012-04-12 10:51:47 +010016721 FixedArray* other_array = FixedArray::cast(obj);
16722 SharedFunctionInfo* shared = SharedFunctionInfo::cast(other_array->get(0));
16723 String* source = String::cast(other_array->get(1));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000016724 int language_unchecked = Smi::cast(other_array->get(2))->value();
16725 DCHECK(is_valid_language_mode(language_unchecked));
16726 LanguageMode language_mode = static_cast<LanguageMode>(language_unchecked);
Ben Murdoch3ef787d2012-04-12 10:51:47 +010016727 int scope_position = Smi::cast(other_array->get(3))->value();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000016728 return StringSharedHashHelper(source, shared, language_mode,
16729 scope_position);
Steve Blocka7e24c12009-10-30 11:49:00 +000016730 }
16731
Ben Murdochb8a8cc12014-11-26 15:28:44 +000016732
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000016733 Handle<Object> AsHandle(Isolate* isolate) override {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000016734 Handle<FixedArray> array = isolate->factory()->NewFixedArray(4);
16735 array->set(0, *shared_);
16736 array->set(1, *source_);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000016737 array->set(2, Smi::FromInt(language_mode_));
Ben Murdochb8a8cc12014-11-26 15:28:44 +000016738 array->set(3, Smi::FromInt(scope_position_));
16739 return array;
Steve Blocka7e24c12009-10-30 11:49:00 +000016740 }
16741
16742 private:
Ben Murdochb8a8cc12014-11-26 15:28:44 +000016743 Handle<String> source_;
16744 Handle<SharedFunctionInfo> shared_;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000016745 LanguageMode language_mode_;
Ben Murdoch3ef787d2012-04-12 10:51:47 +010016746 int scope_position_;
Steve Blocka7e24c12009-10-30 11:49:00 +000016747};
16748
16749
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000016750namespace {
16751
16752JSRegExp::Flags RegExpFlagsFromString(Handle<String> flags, bool* success) {
16753 JSRegExp::Flags value = JSRegExp::kNone;
16754 int length = flags->length();
16755 // A longer flags string cannot be valid.
16756 if (length > 5) return JSRegExp::Flags(0);
16757 for (int i = 0; i < length; i++) {
16758 JSRegExp::Flag flag = JSRegExp::kNone;
16759 switch (flags->Get(i)) {
16760 case 'g':
16761 flag = JSRegExp::kGlobal;
16762 break;
16763 case 'i':
16764 flag = JSRegExp::kIgnoreCase;
16765 break;
16766 case 'm':
16767 flag = JSRegExp::kMultiline;
16768 break;
16769 case 'u':
16770 if (!FLAG_harmony_unicode_regexps) return JSRegExp::Flags(0);
16771 flag = JSRegExp::kUnicode;
16772 break;
16773 case 'y':
16774 if (!FLAG_harmony_regexps) return JSRegExp::Flags(0);
16775 flag = JSRegExp::kSticky;
16776 break;
16777 default:
16778 return JSRegExp::Flags(0);
16779 }
16780 // Duplicate flag.
16781 if (value & flag) return JSRegExp::Flags(0);
16782 value |= flag;
16783 }
16784 *success = true;
16785 return value;
16786}
16787
16788} // namespace
16789
16790
16791// static
16792MaybeHandle<JSRegExp> JSRegExp::New(Handle<String> pattern, Flags flags) {
16793 Isolate* isolate = pattern->GetIsolate();
16794 Handle<JSFunction> constructor = isolate->regexp_function();
16795 Handle<JSRegExp> regexp =
16796 Handle<JSRegExp>::cast(isolate->factory()->NewJSObject(constructor));
16797
16798 return JSRegExp::Initialize(regexp, pattern, flags);
16799}
16800
16801
16802// static
16803MaybeHandle<JSRegExp> JSRegExp::New(Handle<String> pattern,
16804 Handle<String> flags_string) {
16805 Isolate* isolate = pattern->GetIsolate();
16806 bool success = false;
16807 Flags flags = RegExpFlagsFromString(flags_string, &success);
16808 if (!success) {
16809 THROW_NEW_ERROR(
16810 isolate,
16811 NewSyntaxError(MessageTemplate::kInvalidRegExpFlags, flags_string),
16812 JSRegExp);
16813 }
16814 return New(pattern, flags);
16815}
16816
16817
16818// static
16819Handle<JSRegExp> JSRegExp::Copy(Handle<JSRegExp> regexp) {
16820 Isolate* const isolate = regexp->GetIsolate();
16821 return Handle<JSRegExp>::cast(isolate->factory()->CopyJSObject(regexp));
16822}
16823
16824
16825template <typename Char>
16826inline int CountRequiredEscapes(Handle<String> source) {
16827 DisallowHeapAllocation no_gc;
16828 int escapes = 0;
16829 Vector<const Char> src = source->GetCharVector<Char>();
16830 for (int i = 0; i < src.length(); i++) {
16831 if (src[i] == '/' && (i == 0 || src[i - 1] != '\\')) escapes++;
16832 }
16833 return escapes;
16834}
16835
16836
16837template <typename Char, typename StringType>
16838inline Handle<StringType> WriteEscapedRegExpSource(Handle<String> source,
16839 Handle<StringType> result) {
16840 DisallowHeapAllocation no_gc;
16841 Vector<const Char> src = source->GetCharVector<Char>();
16842 Vector<Char> dst(result->GetChars(), result->length());
16843 int s = 0;
16844 int d = 0;
16845 while (s < src.length()) {
16846 if (src[s] == '/' && (s == 0 || src[s - 1] != '\\')) dst[d++] = '\\';
16847 dst[d++] = src[s++];
16848 }
16849 DCHECK_EQ(result->length(), d);
16850 return result;
16851}
16852
16853
16854MaybeHandle<String> EscapeRegExpSource(Isolate* isolate,
16855 Handle<String> source) {
16856 String::Flatten(source);
16857 if (source->length() == 0) return isolate->factory()->query_colon_string();
16858 bool one_byte = source->IsOneByteRepresentationUnderneath();
16859 int escapes = one_byte ? CountRequiredEscapes<uint8_t>(source)
16860 : CountRequiredEscapes<uc16>(source);
16861 if (escapes == 0) return source;
16862 int length = source->length() + escapes;
16863 if (one_byte) {
16864 Handle<SeqOneByteString> result;
16865 ASSIGN_RETURN_ON_EXCEPTION(isolate, result,
16866 isolate->factory()->NewRawOneByteString(length),
16867 String);
16868 return WriteEscapedRegExpSource<uint8_t>(source, result);
16869 } else {
16870 Handle<SeqTwoByteString> result;
16871 ASSIGN_RETURN_ON_EXCEPTION(isolate, result,
16872 isolate->factory()->NewRawTwoByteString(length),
16873 String);
16874 return WriteEscapedRegExpSource<uc16>(source, result);
16875 }
16876}
16877
16878
16879// static
16880MaybeHandle<JSRegExp> JSRegExp::Initialize(Handle<JSRegExp> regexp,
16881 Handle<String> source,
16882 Handle<String> flags_string) {
16883 Isolate* isolate = source->GetIsolate();
16884 bool success = false;
16885 Flags flags = RegExpFlagsFromString(flags_string, &success);
16886 if (!success) {
16887 THROW_NEW_ERROR(
16888 isolate,
16889 NewSyntaxError(MessageTemplate::kInvalidRegExpFlags, flags_string),
16890 JSRegExp);
16891 }
16892 return Initialize(regexp, source, flags);
16893}
16894
16895
16896// static
16897MaybeHandle<JSRegExp> JSRegExp::Initialize(Handle<JSRegExp> regexp,
16898 Handle<String> source, Flags flags) {
16899 Isolate* isolate = regexp->GetIsolate();
16900 Factory* factory = isolate->factory();
16901 // If source is the empty string we set it to "(?:)" instead as
16902 // suggested by ECMA-262, 5th, section 15.10.4.1.
16903 if (source->length() == 0) source = factory->query_colon_string();
16904
16905 Handle<String> escaped_source;
16906 ASSIGN_RETURN_ON_EXCEPTION(isolate, escaped_source,
16907 EscapeRegExpSource(isolate, source), JSRegExp);
16908
16909 regexp->set_source(*escaped_source);
16910 regexp->set_flags(Smi::FromInt(flags));
16911
16912 Map* map = regexp->map();
16913 Object* constructor = map->GetConstructor();
16914 if (constructor->IsJSFunction() &&
16915 JSFunction::cast(constructor)->initial_map() == map) {
16916 // If we still have the original map, set in-object properties directly.
16917 regexp->InObjectPropertyAtPut(JSRegExp::kLastIndexFieldIndex,
16918 Smi::FromInt(0), SKIP_WRITE_BARRIER);
16919 } else {
16920 // Map has changed, so use generic, but slower, method.
16921 PropertyAttributes writable =
16922 static_cast<PropertyAttributes>(DONT_ENUM | DONT_DELETE);
16923 JSObject::SetOwnPropertyIgnoreAttributes(
16924 regexp, factory->last_index_string(),
16925 Handle<Smi>(Smi::FromInt(0), isolate), writable)
16926 .Check();
16927 }
16928
16929 RETURN_ON_EXCEPTION(isolate, RegExpImpl::Compile(regexp, source, flags),
16930 JSRegExp);
16931
16932 return regexp;
16933}
16934
16935
Steve Blocka7e24c12009-10-30 11:49:00 +000016936// RegExpKey carries the source and flags of a regular expression as key.
16937class RegExpKey : public HashTableKey {
16938 public:
Ben Murdochb8a8cc12014-11-26 15:28:44 +000016939 RegExpKey(Handle<String> string, JSRegExp::Flags flags)
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000016940 : string_(string), flags_(Smi::FromInt(flags)) {}
Steve Blocka7e24c12009-10-30 11:49:00 +000016941
Steve Block3ce2e202009-11-05 08:53:23 +000016942 // Rather than storing the key in the hash table, a pointer to the
16943 // stored value is stored where the key should be. IsMatch then
16944 // compares the search key to the found object, rather than comparing
16945 // a key to a key.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000016946 bool IsMatch(Object* obj) override {
Steve Blocka7e24c12009-10-30 11:49:00 +000016947 FixedArray* val = FixedArray::cast(obj);
16948 return string_->Equals(String::cast(val->get(JSRegExp::kSourceIndex)))
16949 && (flags_ == val->get(JSRegExp::kFlagsIndex));
16950 }
16951
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000016952 uint32_t Hash() override { return RegExpHash(*string_, flags_); }
Steve Blocka7e24c12009-10-30 11:49:00 +000016953
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000016954 Handle<Object> AsHandle(Isolate* isolate) override {
Steve Blocka7e24c12009-10-30 11:49:00 +000016955 // Plain hash maps, which is where regexp keys are used, don't
16956 // use this function.
16957 UNREACHABLE();
Ben Murdochb8a8cc12014-11-26 15:28:44 +000016958 return MaybeHandle<Object>().ToHandleChecked();
Steve Blocka7e24c12009-10-30 11:49:00 +000016959 }
16960
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000016961 uint32_t HashForObject(Object* obj) override {
Steve Blocka7e24c12009-10-30 11:49:00 +000016962 FixedArray* val = FixedArray::cast(obj);
16963 return RegExpHash(String::cast(val->get(JSRegExp::kSourceIndex)),
16964 Smi::cast(val->get(JSRegExp::kFlagsIndex)));
16965 }
16966
16967 static uint32_t RegExpHash(String* string, Smi* flags) {
16968 return string->Hash() + flags->value();
16969 }
16970
Ben Murdochb8a8cc12014-11-26 15:28:44 +000016971 Handle<String> string_;
Steve Blocka7e24c12009-10-30 11:49:00 +000016972 Smi* flags_;
16973};
16974
Ben Murdochb8a8cc12014-11-26 15:28:44 +000016975
16976Handle<Object> OneByteStringKey::AsHandle(Isolate* isolate) {
16977 if (hash_field_ == 0) Hash();
16978 return isolate->factory()->NewOneByteInternalizedString(string_, hash_field_);
16979}
16980
16981
16982Handle<Object> TwoByteStringKey::AsHandle(Isolate* isolate) {
16983 if (hash_field_ == 0) Hash();
16984 return isolate->factory()->NewTwoByteInternalizedString(string_, hash_field_);
16985}
16986
16987
16988Handle<Object> SeqOneByteSubStringKey::AsHandle(Isolate* isolate) {
16989 if (hash_field_ == 0) Hash();
16990 return isolate->factory()->NewOneByteInternalizedSubString(
16991 string_, from_, length_, hash_field_);
16992}
16993
16994
16995bool SeqOneByteSubStringKey::IsMatch(Object* string) {
16996 Vector<const uint8_t> chars(string_->GetChars() + from_, length_);
16997 return String::cast(string)->IsOneByteEqualTo(chars);
16998}
16999
17000
17001// InternalizedStringKey carries a string/internalized-string object as key.
17002class InternalizedStringKey : public HashTableKey {
Steve Blocka7e24c12009-10-30 11:49:00 +000017003 public:
Ben Murdochb8a8cc12014-11-26 15:28:44 +000017004 explicit InternalizedStringKey(Handle<String> string)
Steve Block44f0eee2011-05-26 01:26:41 +010017005 : string_(string) { }
Steve Blocka7e24c12009-10-30 11:49:00 +000017006
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000017007 bool IsMatch(Object* string) override {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000017008 return String::cast(string)->Equals(*string_);
Steve Blocka7e24c12009-10-30 11:49:00 +000017009 }
17010
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000017011 uint32_t Hash() override { return string_->Hash(); }
Steve Blocka7e24c12009-10-30 11:49:00 +000017012
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000017013 uint32_t HashForObject(Object* other) override {
Steve Blocka7e24c12009-10-30 11:49:00 +000017014 return String::cast(other)->Hash();
17015 }
17016
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000017017 Handle<Object> AsHandle(Isolate* isolate) override {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000017018 // Internalize the string if possible.
17019 MaybeHandle<Map> maybe_map =
17020 isolate->factory()->InternalizedStringMapForString(string_);
17021 Handle<Map> map;
17022 if (maybe_map.ToHandle(&map)) {
17023 string_->set_map_no_write_barrier(*map);
17024 DCHECK(string_->IsInternalizedString());
Steve Blocka7e24c12009-10-30 11:49:00 +000017025 return string_;
17026 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +000017027 // Otherwise allocate a new internalized string.
17028 return isolate->factory()->NewInternalizedStringImpl(
17029 string_, string_->length(), string_->hash_field());
Steve Blocka7e24c12009-10-30 11:49:00 +000017030 }
17031
17032 static uint32_t StringHash(Object* obj) {
17033 return String::cast(obj)->Hash();
17034 }
17035
Ben Murdochb8a8cc12014-11-26 15:28:44 +000017036 Handle<String> string_;
Steve Blocka7e24c12009-10-30 11:49:00 +000017037};
17038
17039
Ben Murdochb8a8cc12014-11-26 15:28:44 +000017040template<typename Derived, typename Shape, typename Key>
17041void HashTable<Derived, Shape, Key>::IteratePrefix(ObjectVisitor* v) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000017042 BodyDescriptorBase::IteratePointers(this, 0, kElementsStartOffset, v);
Steve Blocka7e24c12009-10-30 11:49:00 +000017043}
17044
17045
Ben Murdochb8a8cc12014-11-26 15:28:44 +000017046template<typename Derived, typename Shape, typename Key>
17047void HashTable<Derived, Shape, Key>::IterateElements(ObjectVisitor* v) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000017048 BodyDescriptorBase::IteratePointers(this, kElementsStartOffset,
17049 kHeaderSize + length() * kPointerSize, v);
Steve Blocka7e24c12009-10-30 11:49:00 +000017050}
17051
17052
Ben Murdochb8a8cc12014-11-26 15:28:44 +000017053template<typename Derived, typename Shape, typename Key>
17054Handle<Derived> HashTable<Derived, Shape, Key>::New(
17055 Isolate* isolate,
17056 int at_least_space_for,
17057 MinimumCapacity capacity_option,
17058 PretenureFlag pretenure) {
17059 DCHECK(0 <= at_least_space_for);
17060 DCHECK(!capacity_option || base::bits::IsPowerOfTwo32(at_least_space_for));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000017061
Ben Murdochb8a8cc12014-11-26 15:28:44 +000017062 int capacity = (capacity_option == USE_CUSTOM_MINIMUM_CAPACITY)
17063 ? at_least_space_for
17064 : ComputeCapacity(at_least_space_for);
Ben Murdoch69a99ed2011-11-30 16:03:39 +000017065 if (capacity > HashTable::kMaxCapacity) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000017066 v8::internal::Heap::FatalProcessOutOfMemory("invalid table size", true);
Leon Clarkee46be812010-01-19 14:06:41 +000017067 }
17068
Ben Murdochb8a8cc12014-11-26 15:28:44 +000017069 Factory* factory = isolate->factory();
17070 int length = EntryToIndex(capacity);
17071 Handle<FixedArray> array = factory->NewFixedArray(length, pretenure);
17072 array->set_map_no_write_barrier(*factory->hash_table_map());
17073 Handle<Derived> table = Handle<Derived>::cast(array);
17074
17075 table->SetNumberOfElements(0);
17076 table->SetNumberOfDeletedElements(0);
17077 table->SetCapacity(capacity);
17078 return table;
Steve Blocka7e24c12009-10-30 11:49:00 +000017079}
17080
17081
Leon Clarkee46be812010-01-19 14:06:41 +000017082// Find entry for key otherwise return kNotFound.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000017083template <typename Derived, typename Shape>
17084int NameDictionaryBase<Derived, Shape>::FindEntry(Handle<Name> key) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000017085 if (!key->IsUniqueName()) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000017086 return DerivedDictionary::FindEntry(key);
Ben Murdoch3bec4d22010-07-22 14:51:16 +010017087 }
17088
Ben Murdochb8a8cc12014-11-26 15:28:44 +000017089 // Optimized for unique names. Knowledge of the key type allows:
17090 // 1. Move the check if the key is unique out of the loop.
17091 // 2. Avoid comparing hash codes in unique-to-unique comparison.
17092 // 3. Detect a case when a dictionary key is not unique but the key is.
17093 // In case of positive result the dictionary key may be replaced by the
17094 // internalized string with minimal performance penalty. It gives a chance
17095 // to perform further lookups in code stubs (and significant performance
17096 // boost a certain style of code).
Ben Murdoch3bec4d22010-07-22 14:51:16 +010017097
17098 // EnsureCapacity will guarantee the hash table is never full.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000017099 uint32_t capacity = this->Capacity();
17100 uint32_t entry = Derived::FirstProbe(key->Hash(), capacity);
Ben Murdoch3bec4d22010-07-22 14:51:16 +010017101 uint32_t count = 1;
17102
17103 while (true) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000017104 int index = Derived::EntryToIndex(entry);
17105 Object* element = this->get(index);
Ben Murdoch3bec4d22010-07-22 14:51:16 +010017106 if (element->IsUndefined()) break; // Empty entry.
Ben Murdochb8a8cc12014-11-26 15:28:44 +000017107 if (*key == element) return entry;
17108 if (!element->IsUniqueName() &&
Ben Murdoch3ef787d2012-04-12 10:51:47 +010017109 !element->IsTheHole() &&
Ben Murdochb8a8cc12014-11-26 15:28:44 +000017110 Name::cast(element)->Equals(*key)) {
17111 // Replace a key that is a non-internalized string by the equivalent
17112 // internalized string for faster further lookups.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000017113 this->set(index, *key);
Ben Murdoch3bec4d22010-07-22 14:51:16 +010017114 return entry;
17115 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +000017116 DCHECK(element->IsTheHole() || !Name::cast(element)->Equals(*key));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000017117 entry = Derived::NextProbe(entry, count++, capacity);
Ben Murdoch3bec4d22010-07-22 14:51:16 +010017118 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000017119 return Derived::kNotFound;
Ben Murdoch3bec4d22010-07-22 14:51:16 +010017120}
17121
17122
Ben Murdochb8a8cc12014-11-26 15:28:44 +000017123template<typename Derived, typename Shape, typename Key>
17124void HashTable<Derived, Shape, Key>::Rehash(
17125 Handle<Derived> new_table,
17126 Key key) {
17127 DCHECK(NumberOfElements() < new_table->Capacity());
Ben Murdoch3ef787d2012-04-12 10:51:47 +010017128
Ben Murdochb8a8cc12014-11-26 15:28:44 +000017129 DisallowHeapAllocation no_gc;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000017130 WriteBarrierMode mode = new_table->GetWriteBarrierMode(no_gc);
17131
17132 // Copy prefix to new array.
17133 for (int i = kPrefixStartIndex;
17134 i < kPrefixStartIndex + Shape::kPrefixSize;
17135 i++) {
17136 new_table->set(i, get(i), mode);
17137 }
17138
17139 // Rehash the elements.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000017140 int capacity = this->Capacity();
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000017141 for (int i = 0; i < capacity; i++) {
17142 uint32_t from_index = EntryToIndex(i);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000017143 Object* k = this->get(from_index);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000017144 if (IsKey(k)) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000017145 uint32_t hash = this->HashForObject(key, k);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000017146 uint32_t insertion_index =
17147 EntryToIndex(new_table->FindInsertionEntry(hash));
17148 for (int j = 0; j < Shape::kEntrySize; j++) {
17149 new_table->set(insertion_index + j, get(from_index + j), mode);
17150 }
17151 }
17152 }
17153 new_table->SetNumberOfElements(NumberOfElements());
17154 new_table->SetNumberOfDeletedElements(0);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000017155}
17156
17157
Ben Murdochb8a8cc12014-11-26 15:28:44 +000017158template<typename Derived, typename Shape, typename Key>
17159uint32_t HashTable<Derived, Shape, Key>::EntryForProbe(
17160 Key key,
17161 Object* k,
17162 int probe,
17163 uint32_t expected) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000017164 uint32_t hash = this->HashForObject(key, k);
17165 uint32_t capacity = this->Capacity();
Ben Murdochb8a8cc12014-11-26 15:28:44 +000017166 uint32_t entry = FirstProbe(hash, capacity);
17167 for (int i = 1; i < probe; i++) {
17168 if (entry == expected) return expected;
17169 entry = NextProbe(entry, i, capacity);
17170 }
17171 return entry;
17172}
17173
17174
17175template<typename Derived, typename Shape, typename Key>
17176void HashTable<Derived, Shape, Key>::Swap(uint32_t entry1,
17177 uint32_t entry2,
17178 WriteBarrierMode mode) {
17179 int index1 = EntryToIndex(entry1);
17180 int index2 = EntryToIndex(entry2);
17181 Object* temp[Shape::kEntrySize];
17182 for (int j = 0; j < Shape::kEntrySize; j++) {
17183 temp[j] = get(index1 + j);
17184 }
17185 for (int j = 0; j < Shape::kEntrySize; j++) {
17186 set(index1 + j, get(index2 + j), mode);
17187 }
17188 for (int j = 0; j < Shape::kEntrySize; j++) {
17189 set(index2 + j, temp[j], mode);
17190 }
17191}
17192
17193
17194template<typename Derived, typename Shape, typename Key>
17195void HashTable<Derived, Shape, Key>::Rehash(Key key) {
17196 DisallowHeapAllocation no_gc;
17197 WriteBarrierMode mode = GetWriteBarrierMode(no_gc);
17198 uint32_t capacity = Capacity();
17199 bool done = false;
17200 for (int probe = 1; !done; probe++) {
17201 // All elements at entries given by one of the first _probe_ probes
17202 // are placed correctly. Other elements might need to be moved.
17203 done = true;
17204 for (uint32_t current = 0; current < capacity; current++) {
17205 Object* current_key = get(EntryToIndex(current));
17206 if (IsKey(current_key)) {
17207 uint32_t target = EntryForProbe(key, current_key, probe, current);
17208 if (current == target) continue;
17209 Object* target_key = get(EntryToIndex(target));
17210 if (!IsKey(target_key) ||
17211 EntryForProbe(key, target_key, probe, target) != target) {
17212 // Put the current element into the correct position.
17213 Swap(current, target, mode);
17214 // The other element will be processed on the next iteration.
17215 current--;
17216 } else {
17217 // The place for the current element is occupied. Leave the element
17218 // for the next probe.
17219 done = false;
17220 }
17221 }
17222 }
17223 }
17224}
17225
17226
17227template<typename Derived, typename Shape, typename Key>
17228Handle<Derived> HashTable<Derived, Shape, Key>::EnsureCapacity(
17229 Handle<Derived> table,
17230 int n,
17231 Key key,
17232 PretenureFlag pretenure) {
17233 Isolate* isolate = table->GetIsolate();
17234 int capacity = table->Capacity();
17235 int nof = table->NumberOfElements() + n;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000017236
17237 if (table->HasSufficientCapacity(n)) return table;
Steve Blocka7e24c12009-10-30 11:49:00 +000017238
Steve Block6ded16b2010-05-10 14:33:55 +010017239 const int kMinCapacityForPretenure = 256;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000017240 bool should_pretenure = pretenure == TENURED ||
17241 ((capacity > kMinCapacityForPretenure) &&
17242 !isolate->heap()->InNewSpace(*table));
17243 Handle<Derived> new_table = HashTable::New(
17244 isolate,
17245 nof * 2,
17246 USE_DEFAULT_MINIMUM_CAPACITY,
17247 should_pretenure ? TENURED : NOT_TENURED);
Leon Clarke4515c472010-02-03 11:58:03 +000017248
Ben Murdochb8a8cc12014-11-26 15:28:44 +000017249 table->Rehash(new_table, key);
17250 return new_table;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000017251}
Steve Blocka7e24c12009-10-30 11:49:00 +000017252
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000017253
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000017254template <typename Derived, typename Shape, typename Key>
17255bool HashTable<Derived, Shape, Key>::HasSufficientCapacity(int n) {
17256 int capacity = Capacity();
17257 int nof = NumberOfElements() + n;
17258 int nod = NumberOfDeletedElements();
17259 // Return true if:
17260 // 50% is still free after adding n elements and
17261 // at most 50% of the free elements are deleted elements.
17262 if (nod <= (capacity - nof) >> 1) {
17263 int needed_free = nof >> 1;
17264 if (nof + needed_free <= capacity) return true;
17265 }
17266 return false;
17267}
17268
17269
Ben Murdochb8a8cc12014-11-26 15:28:44 +000017270template<typename Derived, typename Shape, typename Key>
17271Handle<Derived> HashTable<Derived, Shape, Key>::Shrink(Handle<Derived> table,
17272 Key key) {
17273 int capacity = table->Capacity();
17274 int nof = table->NumberOfElements();
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000017275
17276 // Shrink to fit the number of elements if only a quarter of the
17277 // capacity is filled with elements.
Ben Murdochb8a8cc12014-11-26 15:28:44 +000017278 if (nof > (capacity >> 2)) return table;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000017279 // Allocate a new dictionary with room for at least the current
17280 // number of elements. The allocation method will make sure that
17281 // there is extra room in the dictionary for additions. Don't go
17282 // lower than room for 16 elements.
17283 int at_least_room_for = nof;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000017284 if (at_least_room_for < 16) return table;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000017285
Ben Murdochb8a8cc12014-11-26 15:28:44 +000017286 Isolate* isolate = table->GetIsolate();
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000017287 const int kMinCapacityForPretenure = 256;
17288 bool pretenure =
17289 (at_least_room_for > kMinCapacityForPretenure) &&
Ben Murdochb8a8cc12014-11-26 15:28:44 +000017290 !isolate->heap()->InNewSpace(*table);
17291 Handle<Derived> new_table = HashTable::New(
17292 isolate,
17293 at_least_room_for,
17294 USE_DEFAULT_MINIMUM_CAPACITY,
17295 pretenure ? TENURED : NOT_TENURED);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000017296
Ben Murdochb8a8cc12014-11-26 15:28:44 +000017297 table->Rehash(new_table, key);
17298 return new_table;
Steve Blocka7e24c12009-10-30 11:49:00 +000017299}
17300
17301
Ben Murdochb8a8cc12014-11-26 15:28:44 +000017302template<typename Derived, typename Shape, typename Key>
17303uint32_t HashTable<Derived, Shape, Key>::FindInsertionEntry(uint32_t hash) {
Steve Blocka7e24c12009-10-30 11:49:00 +000017304 uint32_t capacity = Capacity();
Leon Clarkee46be812010-01-19 14:06:41 +000017305 uint32_t entry = FirstProbe(hash, capacity);
17306 uint32_t count = 1;
17307 // EnsureCapacity will guarantee the hash table is never full.
17308 while (true) {
17309 Object* element = KeyAt(entry);
Ben Murdoch3ef787d2012-04-12 10:51:47 +010017310 if (element->IsUndefined() || element->IsTheHole()) break;
Leon Clarkee46be812010-01-19 14:06:41 +000017311 entry = NextProbe(entry, count++, capacity);
Steve Blocka7e24c12009-10-30 11:49:00 +000017312 }
Steve Blocka7e24c12009-10-30 11:49:00 +000017313 return entry;
17314}
17315
Ben Murdochb8a8cc12014-11-26 15:28:44 +000017316
Steve Blocka7e24c12009-10-30 11:49:00 +000017317// Force instantiation of template instances class.
17318// Please note this list is compiler dependent.
17319
Ben Murdochb8a8cc12014-11-26 15:28:44 +000017320template class HashTable<StringTable, StringTableShape, HashTableKey*>;
Steve Blocka7e24c12009-10-30 11:49:00 +000017321
Ben Murdochb8a8cc12014-11-26 15:28:44 +000017322template class HashTable<CompilationCacheTable,
17323 CompilationCacheShape,
17324 HashTableKey*>;
Steve Blocka7e24c12009-10-30 11:49:00 +000017325
Ben Murdochb8a8cc12014-11-26 15:28:44 +000017326template class HashTable<ObjectHashTable,
17327 ObjectHashTableShape,
17328 Handle<Object> >;
Ben Murdoch3ef787d2012-04-12 10:51:47 +010017329
Ben Murdochb8a8cc12014-11-26 15:28:44 +000017330template class HashTable<WeakHashTable, WeakHashTableShape<2>, Handle<Object> >;
Ben Murdoch69a99ed2011-11-30 16:03:39 +000017331
Ben Murdochb8a8cc12014-11-26 15:28:44 +000017332template class Dictionary<NameDictionary, NameDictionaryShape, Handle<Name> >;
Steve Blocka7e24c12009-10-30 11:49:00 +000017333
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000017334template class Dictionary<GlobalDictionary, GlobalDictionaryShape,
17335 Handle<Name> >;
17336
Ben Murdochb8a8cc12014-11-26 15:28:44 +000017337template class Dictionary<SeededNumberDictionary,
17338 SeededNumberDictionaryShape,
17339 uint32_t>;
Steve Blocka7e24c12009-10-30 11:49:00 +000017340
Ben Murdochb8a8cc12014-11-26 15:28:44 +000017341template class Dictionary<UnseededNumberDictionary,
17342 UnseededNumberDictionaryShape,
17343 uint32_t>;
Ben Murdochc7cc0282012-03-05 14:35:55 +000017344
Ben Murdochb8a8cc12014-11-26 15:28:44 +000017345template Handle<SeededNumberDictionary>
17346Dictionary<SeededNumberDictionary, SeededNumberDictionaryShape, uint32_t>::
17347 New(Isolate*, int at_least_space_for, PretenureFlag pretenure);
Ben Murdochc7cc0282012-03-05 14:35:55 +000017348
Ben Murdochb8a8cc12014-11-26 15:28:44 +000017349template Handle<UnseededNumberDictionary>
17350Dictionary<UnseededNumberDictionary, UnseededNumberDictionaryShape, uint32_t>::
17351 New(Isolate*, int at_least_space_for, PretenureFlag pretenure);
Steve Blocka7e24c12009-10-30 11:49:00 +000017352
Ben Murdochb8a8cc12014-11-26 15:28:44 +000017353template Handle<NameDictionary>
17354Dictionary<NameDictionary, NameDictionaryShape, Handle<Name> >::
17355 New(Isolate*, int n, PretenureFlag pretenure);
Steve Blocka7e24c12009-10-30 11:49:00 +000017356
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000017357template Handle<GlobalDictionary>
17358Dictionary<GlobalDictionary, GlobalDictionaryShape, Handle<Name> >::New(
17359 Isolate*, int n, PretenureFlag pretenure);
17360
Ben Murdochb8a8cc12014-11-26 15:28:44 +000017361template Handle<SeededNumberDictionary>
17362Dictionary<SeededNumberDictionary, SeededNumberDictionaryShape, uint32_t>::
17363 AtPut(Handle<SeededNumberDictionary>, uint32_t, Handle<Object>);
Steve Blocka7e24c12009-10-30 11:49:00 +000017364
Ben Murdochb8a8cc12014-11-26 15:28:44 +000017365template Handle<UnseededNumberDictionary>
17366Dictionary<UnseededNumberDictionary, UnseededNumberDictionaryShape, uint32_t>::
17367 AtPut(Handle<UnseededNumberDictionary>, uint32_t, Handle<Object>);
Ben Murdochc7cc0282012-03-05 14:35:55 +000017368
Ben Murdochb8a8cc12014-11-26 15:28:44 +000017369template Object*
17370Dictionary<SeededNumberDictionary, SeededNumberDictionaryShape, uint32_t>::
Ben Murdoch3ef787d2012-04-12 10:51:47 +010017371 SlowReverseLookup(Object* value);
17372
Ben Murdochb8a8cc12014-11-26 15:28:44 +000017373template Object*
17374Dictionary<NameDictionary, NameDictionaryShape, Handle<Name> >::
Ben Murdochc7cc0282012-03-05 14:35:55 +000017375 SlowReverseLookup(Object* value);
Steve Blocka7e24c12009-10-30 11:49:00 +000017376
Ben Murdochb8a8cc12014-11-26 15:28:44 +000017377template Handle<Object>
17378Dictionary<NameDictionary, NameDictionaryShape, Handle<Name> >::DeleteProperty(
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000017379 Handle<NameDictionary>, int);
Steve Blocka7e24c12009-10-30 11:49:00 +000017380
Ben Murdochb8a8cc12014-11-26 15:28:44 +000017381template Handle<Object>
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000017382Dictionary<SeededNumberDictionary, SeededNumberDictionaryShape,
17383 uint32_t>::DeleteProperty(Handle<SeededNumberDictionary>, int);
Steve Blocka7e24c12009-10-30 11:49:00 +000017384
Ben Murdochb8a8cc12014-11-26 15:28:44 +000017385template Handle<NameDictionary>
17386HashTable<NameDictionary, NameDictionaryShape, Handle<Name> >::
17387 New(Isolate*, int, MinimumCapacity, PretenureFlag);
Steve Blocka7e24c12009-10-30 11:49:00 +000017388
Ben Murdochb8a8cc12014-11-26 15:28:44 +000017389template Handle<NameDictionary>
17390HashTable<NameDictionary, NameDictionaryShape, Handle<Name> >::
17391 Shrink(Handle<NameDictionary>, Handle<Name>);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000017392
Ben Murdochb8a8cc12014-11-26 15:28:44 +000017393template Handle<SeededNumberDictionary>
17394HashTable<SeededNumberDictionary, SeededNumberDictionaryShape, uint32_t>::
17395 Shrink(Handle<SeededNumberDictionary>, uint32_t);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000017396
Ben Murdochb8a8cc12014-11-26 15:28:44 +000017397template Handle<NameDictionary>
17398Dictionary<NameDictionary, NameDictionaryShape, Handle<Name> >::Add(
17399 Handle<NameDictionary>, Handle<Name>, Handle<Object>, PropertyDetails);
Steve Blocka7e24c12009-10-30 11:49:00 +000017400
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000017401template Handle<GlobalDictionary>
17402 Dictionary<GlobalDictionary, GlobalDictionaryShape, Handle<Name> >::Add(
17403 Handle<GlobalDictionary>, Handle<Name>, Handle<Object>,
17404 PropertyDetails);
17405
Emily Bernierd0a1eb72015-03-24 16:35:39 -040017406template Handle<FixedArray> Dictionary<
17407 NameDictionary, NameDictionaryShape,
17408 Handle<Name> >::BuildIterationIndicesArray(Handle<NameDictionary>);
17409
17410template Handle<FixedArray> Dictionary<
17411 NameDictionary, NameDictionaryShape,
17412 Handle<Name> >::GenerateNewEnumerationIndices(Handle<NameDictionary>);
Ben Murdochc7cc0282012-03-05 14:35:55 +000017413
Ben Murdochb8a8cc12014-11-26 15:28:44 +000017414template Handle<SeededNumberDictionary>
17415Dictionary<SeededNumberDictionary, SeededNumberDictionaryShape, uint32_t>::
17416 Add(Handle<SeededNumberDictionary>,
17417 uint32_t,
17418 Handle<Object>,
17419 PropertyDetails);
Steve Blocka7e24c12009-10-30 11:49:00 +000017420
Ben Murdochb8a8cc12014-11-26 15:28:44 +000017421template Handle<UnseededNumberDictionary>
17422Dictionary<UnseededNumberDictionary, UnseededNumberDictionaryShape, uint32_t>::
17423 Add(Handle<UnseededNumberDictionary>,
17424 uint32_t,
17425 Handle<Object>,
17426 PropertyDetails);
Steve Blocka7e24c12009-10-30 11:49:00 +000017427
Ben Murdochb8a8cc12014-11-26 15:28:44 +000017428template Handle<SeededNumberDictionary>
17429Dictionary<SeededNumberDictionary, SeededNumberDictionaryShape, uint32_t>::
17430 EnsureCapacity(Handle<SeededNumberDictionary>, int, uint32_t);
Ben Murdochc7cc0282012-03-05 14:35:55 +000017431
Ben Murdochb8a8cc12014-11-26 15:28:44 +000017432template Handle<UnseededNumberDictionary>
17433Dictionary<UnseededNumberDictionary, UnseededNumberDictionaryShape, uint32_t>::
17434 EnsureCapacity(Handle<UnseededNumberDictionary>, int, uint32_t);
Steve Blocka7e24c12009-10-30 11:49:00 +000017435
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000017436template void Dictionary<NameDictionary, NameDictionaryShape,
17437 Handle<Name> >::SetRequiresCopyOnCapacityChange();
17438
Ben Murdochb8a8cc12014-11-26 15:28:44 +000017439template Handle<NameDictionary>
17440Dictionary<NameDictionary, NameDictionaryShape, Handle<Name> >::
17441 EnsureCapacity(Handle<NameDictionary>, int, Handle<Name>);
Steve Blocka7e24c12009-10-30 11:49:00 +000017442
Emily Bernierd0a1eb72015-03-24 16:35:39 -040017443template bool Dictionary<SeededNumberDictionary, SeededNumberDictionaryShape,
17444 uint32_t>::HasComplexElements();
17445
17446template int HashTable<SeededNumberDictionary, SeededNumberDictionaryShape,
17447 uint32_t>::FindEntry(uint32_t);
Leon Clarkee46be812010-01-19 14:06:41 +000017448
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000017449template int NameDictionaryBase<NameDictionary, NameDictionaryShape>::FindEntry(
17450 Handle<Name>);
17451
Leon Clarkee46be812010-01-19 14:06:41 +000017452
Ben Murdochb8a8cc12014-11-26 15:28:44 +000017453Handle<Object> JSObject::PrepareSlowElementsForSort(
17454 Handle<JSObject> object, uint32_t limit) {
17455 DCHECK(object->HasDictionaryElements());
17456 Isolate* isolate = object->GetIsolate();
Steve Blocka7e24c12009-10-30 11:49:00 +000017457 // Must stay in dictionary mode, either because of requires_slow_elements,
17458 // or because we are not going to sort (and therefore compact) all of the
17459 // elements.
Ben Murdochb8a8cc12014-11-26 15:28:44 +000017460 Handle<SeededNumberDictionary> dict(object->element_dictionary(), isolate);
17461 Handle<SeededNumberDictionary> new_dict =
17462 SeededNumberDictionary::New(isolate, dict->NumberOfElements());
Steve Blocka7e24c12009-10-30 11:49:00 +000017463
17464 uint32_t pos = 0;
17465 uint32_t undefs = 0;
Steve Block6ded16b2010-05-10 14:33:55 +010017466 int capacity = dict->Capacity();
Ben Murdochb8a8cc12014-11-26 15:28:44 +000017467 Handle<Smi> bailout(Smi::FromInt(-1), isolate);
17468 // Entry to the new dictionary does not cause it to grow, as we have
17469 // allocated one that is large enough for all entries.
17470 DisallowHeapAllocation no_gc;
Steve Blocka7e24c12009-10-30 11:49:00 +000017471 for (int i = 0; i < capacity; i++) {
17472 Object* k = dict->KeyAt(i);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000017473 if (!dict->IsKey(k)) continue;
17474
17475 DCHECK(k->IsNumber());
17476 DCHECK(!k->IsSmi() || Smi::cast(k)->value() >= 0);
17477 DCHECK(!k->IsHeapNumber() || HeapNumber::cast(k)->value() >= 0);
17478 DCHECK(!k->IsHeapNumber() || HeapNumber::cast(k)->value() <= kMaxUInt32);
17479
17480 HandleScope scope(isolate);
17481 Handle<Object> value(dict->ValueAt(i), isolate);
17482 PropertyDetails details = dict->DetailsAt(i);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000017483 if (details.type() == ACCESSOR_CONSTANT || details.IsReadOnly()) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000017484 // Bail out and do the sorting of undefineds and array holes in JS.
17485 // Also bail out if the element is not supposed to be moved.
17486 return bailout;
17487 }
17488
17489 uint32_t key = NumberToUint32(k);
17490 if (key < limit) {
17491 if (value->IsUndefined()) {
17492 undefs++;
17493 } else if (pos > static_cast<uint32_t>(Smi::kMaxValue)) {
17494 // Adding an entry with the key beyond smi-range requires
17495 // allocation. Bailout.
17496 return bailout;
Steve Blocka7e24c12009-10-30 11:49:00 +000017497 } else {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000017498 Handle<Object> result = SeededNumberDictionary::AddNumberEntry(
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000017499 new_dict, pos, value, details, object->map()->is_prototype_map());
Ben Murdochb8a8cc12014-11-26 15:28:44 +000017500 DCHECK(result.is_identical_to(new_dict));
17501 USE(result);
17502 pos++;
Steve Blocka7e24c12009-10-30 11:49:00 +000017503 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +000017504 } else if (key > static_cast<uint32_t>(Smi::kMaxValue)) {
17505 // Adding an entry with the key beyond smi-range requires
17506 // allocation. Bailout.
17507 return bailout;
17508 } else {
17509 Handle<Object> result = SeededNumberDictionary::AddNumberEntry(
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000017510 new_dict, key, value, details, object->map()->is_prototype_map());
Ben Murdochb8a8cc12014-11-26 15:28:44 +000017511 DCHECK(result.is_identical_to(new_dict));
17512 USE(result);
Steve Blocka7e24c12009-10-30 11:49:00 +000017513 }
17514 }
17515
17516 uint32_t result = pos;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000017517 PropertyDetails no_details = PropertyDetails::Empty();
Steve Blocka7e24c12009-10-30 11:49:00 +000017518 while (undefs > 0) {
Steve Block1e0659c2011-05-24 12:43:12 +010017519 if (pos > static_cast<uint32_t>(Smi::kMaxValue)) {
17520 // Adding an entry with the key beyond smi-range requires
17521 // allocation. Bailout.
Ben Murdochb8a8cc12014-11-26 15:28:44 +000017522 return bailout;
Steve Block1e0659c2011-05-24 12:43:12 +010017523 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +000017524 HandleScope scope(isolate);
17525 Handle<Object> result = SeededNumberDictionary::AddNumberEntry(
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000017526 new_dict, pos, isolate->factory()->undefined_value(), no_details,
17527 object->map()->is_prototype_map());
Ben Murdochb8a8cc12014-11-26 15:28:44 +000017528 DCHECK(result.is_identical_to(new_dict));
17529 USE(result);
Steve Blocka7e24c12009-10-30 11:49:00 +000017530 pos++;
17531 undefs--;
17532 }
17533
Ben Murdochb8a8cc12014-11-26 15:28:44 +000017534 object->set_elements(*new_dict);
Steve Blocka7e24c12009-10-30 11:49:00 +000017535
Ben Murdochb8a8cc12014-11-26 15:28:44 +000017536 AllowHeapAllocation allocate_return_value;
17537 return isolate->factory()->NewNumberFromUint(result);
Steve Blocka7e24c12009-10-30 11:49:00 +000017538}
17539
17540
17541// Collects all defined (non-hole) and non-undefined (array) elements at
17542// the start of the elements array.
17543// If the object is in dictionary mode, it is converted to fast elements
17544// mode.
Ben Murdochb8a8cc12014-11-26 15:28:44 +000017545Handle<Object> JSObject::PrepareElementsForSort(Handle<JSObject> object,
17546 uint32_t limit) {
17547 Isolate* isolate = object->GetIsolate();
17548 if (object->HasSloppyArgumentsElements() ||
17549 object->map()->is_observed()) {
17550 return handle(Smi::FromInt(-1), isolate);
17551 }
Ben Murdoch8b112d22011-06-08 16:22:53 +010017552
Ben Murdochb8a8cc12014-11-26 15:28:44 +000017553 if (object->HasDictionaryElements()) {
Steve Blocka7e24c12009-10-30 11:49:00 +000017554 // Convert to fast elements containing only the existing properties.
17555 // Ordering is irrelevant, since we are going to sort anyway.
Ben Murdochb8a8cc12014-11-26 15:28:44 +000017556 Handle<SeededNumberDictionary> dict(object->element_dictionary());
17557 if (object->IsJSArray() || dict->requires_slow_elements() ||
Steve Blocka7e24c12009-10-30 11:49:00 +000017558 dict->max_number_key() >= limit) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000017559 return JSObject::PrepareSlowElementsForSort(object, limit);
Steve Blocka7e24c12009-10-30 11:49:00 +000017560 }
17561 // Convert to fast elements.
17562
Ben Murdochb8a8cc12014-11-26 15:28:44 +000017563 Handle<Map> new_map =
17564 JSObject::GetElementsTransitionMap(object, FAST_HOLEY_ELEMENTS);
Steve Block8defd9f2010-07-08 12:39:36 +010017565
Ben Murdochb8a8cc12014-11-26 15:28:44 +000017566 PretenureFlag tenure = isolate->heap()->InNewSpace(*object) ?
17567 NOT_TENURED: TENURED;
17568 Handle<FixedArray> fast_elements =
17569 isolate->factory()->NewFixedArray(dict->NumberOfElements(), tenure);
17570 dict->CopyValuesTo(*fast_elements);
17571 JSObject::ValidateElements(object);
Steve Block8defd9f2010-07-08 12:39:36 +010017572
Ben Murdochb8a8cc12014-11-26 15:28:44 +000017573 JSObject::SetMapAndElements(object, new_map, fast_elements);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000017574 } else if (object->HasFixedTypedArrayElements()) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000017575 // Typed arrays cannot have holes or undefined elements.
17576 return handle(Smi::FromInt(
17577 FixedArrayBase::cast(object->elements())->length()), isolate);
17578 } else if (!object->HasFastDoubleElements()) {
17579 EnsureWritableFastElements(object);
Steve Blocka7e24c12009-10-30 11:49:00 +000017580 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +000017581 DCHECK(object->HasFastSmiOrObjectElements() ||
17582 object->HasFastDoubleElements());
Steve Blocka7e24c12009-10-30 11:49:00 +000017583
17584 // Collect holes at the end, undefined before that and the rest at the
17585 // start, and return the number of non-hole, non-undefined values.
17586
Ben Murdochb8a8cc12014-11-26 15:28:44 +000017587 Handle<FixedArrayBase> elements_base(object->elements());
Ben Murdoch69a99ed2011-11-30 16:03:39 +000017588 uint32_t elements_length = static_cast<uint32_t>(elements_base->length());
Steve Blocka7e24c12009-10-30 11:49:00 +000017589 if (limit > elements_length) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000017590 limit = elements_length;
Steve Blocka7e24c12009-10-30 11:49:00 +000017591 }
17592 if (limit == 0) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000017593 return handle(Smi::FromInt(0), isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +000017594 }
17595
Ben Murdoch69a99ed2011-11-30 16:03:39 +000017596 uint32_t result = 0;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000017597 if (elements_base->map() == isolate->heap()->fixed_double_array_map()) {
17598 FixedDoubleArray* elements = FixedDoubleArray::cast(*elements_base);
Ben Murdoch69a99ed2011-11-30 16:03:39 +000017599 // Split elements into defined and the_hole, in that order.
17600 unsigned int holes = limit;
17601 // Assume most arrays contain no holes and undefined values, so minimize the
17602 // number of stores of non-undefined, non-the-hole values.
17603 for (unsigned int i = 0; i < holes; i++) {
17604 if (elements->is_the_hole(i)) {
17605 holes--;
17606 } else {
17607 continue;
17608 }
17609 // Position i needs to be filled.
17610 while (holes > i) {
17611 if (elements->is_the_hole(holes)) {
17612 holes--;
17613 } else {
17614 elements->set(i, elements->get_scalar(holes));
17615 break;
17616 }
17617 }
Steve Blocka7e24c12009-10-30 11:49:00 +000017618 }
Ben Murdoch69a99ed2011-11-30 16:03:39 +000017619 result = holes;
17620 while (holes < limit) {
17621 elements->set_the_hole(holes);
17622 holes++;
17623 }
17624 } else {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000017625 FixedArray* elements = FixedArray::cast(*elements_base);
17626 DisallowHeapAllocation no_gc;
Ben Murdoch69a99ed2011-11-30 16:03:39 +000017627
17628 // Split elements into defined, undefined and the_hole, in that order. Only
17629 // count locations for undefined and the hole, and fill them afterwards.
Ben Murdochb8a8cc12014-11-26 15:28:44 +000017630 WriteBarrierMode write_barrier = elements->GetWriteBarrierMode(no_gc);
Ben Murdoch69a99ed2011-11-30 16:03:39 +000017631 unsigned int undefs = limit;
17632 unsigned int holes = limit;
17633 // Assume most arrays contain no holes and undefined values, so minimize the
17634 // number of stores of non-undefined, non-the-hole values.
17635 for (unsigned int i = 0; i < undefs; i++) {
17636 Object* current = elements->get(i);
Steve Blocka7e24c12009-10-30 11:49:00 +000017637 if (current->IsTheHole()) {
17638 holes--;
17639 undefs--;
17640 } else if (current->IsUndefined()) {
17641 undefs--;
17642 } else {
Ben Murdoch69a99ed2011-11-30 16:03:39 +000017643 continue;
17644 }
17645 // Position i needs to be filled.
17646 while (undefs > i) {
17647 current = elements->get(undefs);
17648 if (current->IsTheHole()) {
17649 holes--;
17650 undefs--;
17651 } else if (current->IsUndefined()) {
17652 undefs--;
17653 } else {
17654 elements->set(i, current, write_barrier);
17655 break;
17656 }
Steve Blocka7e24c12009-10-30 11:49:00 +000017657 }
17658 }
Ben Murdoch69a99ed2011-11-30 16:03:39 +000017659 result = undefs;
17660 while (undefs < holes) {
17661 elements->set_undefined(undefs);
17662 undefs++;
17663 }
17664 while (holes < limit) {
17665 elements->set_the_hole(holes);
17666 holes++;
17667 }
Steve Blocka7e24c12009-10-30 11:49:00 +000017668 }
17669
Ben Murdochb8a8cc12014-11-26 15:28:44 +000017670 return isolate->factory()->NewNumberFromUint(result);
Steve Blocka7e24c12009-10-30 11:49:00 +000017671}
17672
17673
Ben Murdochb8a8cc12014-11-26 15:28:44 +000017674ExternalArrayType JSTypedArray::type() {
17675 switch (elements()->map()->instance_type()) {
17676#define INSTANCE_TYPE_TO_ARRAY_TYPE(Type, type, TYPE, ctype, size) \
Ben Murdochb8a8cc12014-11-26 15:28:44 +000017677 case FIXED_##TYPE##_ARRAY_TYPE: \
17678 return kExternal##Type##Array;
17679
17680 TYPED_ARRAYS(INSTANCE_TYPE_TO_ARRAY_TYPE)
17681#undef INSTANCE_TYPE_TO_ARRAY_TYPE
17682
17683 default:
17684 UNREACHABLE();
17685 return static_cast<ExternalArrayType>(-1);
17686 }
17687}
17688
17689
17690size_t JSTypedArray::element_size() {
17691 switch (elements()->map()->instance_type()) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000017692#define INSTANCE_TYPE_TO_ELEMENT_SIZE(Type, type, TYPE, ctype, size) \
17693 case FIXED_##TYPE##_ARRAY_TYPE: \
17694 return size;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000017695
17696 TYPED_ARRAYS(INSTANCE_TYPE_TO_ELEMENT_SIZE)
17697#undef INSTANCE_TYPE_TO_ELEMENT_SIZE
17698
17699 default:
17700 UNREACHABLE();
17701 return 0;
17702 }
17703}
17704
17705
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000017706void JSGlobalObject::InvalidatePropertyCell(Handle<JSGlobalObject> global,
17707 Handle<Name> name) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -040017708 DCHECK(!global->HasFastProperties());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000017709 auto dictionary = handle(global->global_dictionary());
17710 int entry = dictionary->FindEntry(name);
17711 if (entry == GlobalDictionary::kNotFound) return;
17712 PropertyCell::InvalidateEntry(dictionary, entry);
Emily Bernierd0a1eb72015-03-24 16:35:39 -040017713}
17714
17715
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000017716// TODO(ishell): rename to EnsureEmptyPropertyCell or something.
Ben Murdochb8a8cc12014-11-26 15:28:44 +000017717Handle<PropertyCell> JSGlobalObject::EnsurePropertyCell(
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000017718 Handle<JSGlobalObject> global, Handle<Name> name) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000017719 DCHECK(!global->HasFastProperties());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000017720 auto dictionary = handle(global->global_dictionary());
17721 int entry = dictionary->FindEntry(name);
17722 Handle<PropertyCell> cell;
17723 if (entry != GlobalDictionary::kNotFound) {
17724 // This call should be idempotent.
17725 DCHECK(dictionary->ValueAt(entry)->IsPropertyCell());
17726 cell = handle(PropertyCell::cast(dictionary->ValueAt(entry)));
17727 DCHECK(cell->property_details().cell_type() ==
17728 PropertyCellType::kUninitialized ||
17729 cell->property_details().cell_type() ==
17730 PropertyCellType::kInvalidated);
17731 DCHECK(cell->value()->IsTheHole());
Steve Blocka7e24c12009-10-30 11:49:00 +000017732 return cell;
Steve Blocka7e24c12009-10-30 11:49:00 +000017733 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000017734 Isolate* isolate = global->GetIsolate();
17735 cell = isolate->factory()->NewPropertyCell();
17736 PropertyDetails details(NONE, DATA, 0, PropertyCellType::kUninitialized);
17737 dictionary = GlobalDictionary::Add(dictionary, name, cell, details);
17738 global->set_properties(*dictionary);
17739 return cell;
Steve Blocka7e24c12009-10-30 11:49:00 +000017740}
17741
17742
Ben Murdochb8a8cc12014-11-26 15:28:44 +000017743// This class is used for looking up two character strings in the string table.
Steve Blockd0582a62009-12-15 09:54:21 +000017744// If we don't have a hit we don't want to waste much time so we unroll the
17745// string hash calculation loop here for speed. Doesn't work if the two
17746// characters form a decimal integer, since such strings have a different hash
17747// algorithm.
17748class TwoCharHashTableKey : public HashTableKey {
17749 public:
Ben Murdochb8a8cc12014-11-26 15:28:44 +000017750 TwoCharHashTableKey(uint16_t c1, uint16_t c2, uint32_t seed)
Steve Blockd0582a62009-12-15 09:54:21 +000017751 : c1_(c1), c2_(c2) {
17752 // Char 1.
Ben Murdochc7cc0282012-03-05 14:35:55 +000017753 uint32_t hash = seed;
17754 hash += c1;
17755 hash += hash << 10;
Steve Blockd0582a62009-12-15 09:54:21 +000017756 hash ^= hash >> 6;
17757 // Char 2.
17758 hash += c2;
17759 hash += hash << 10;
17760 hash ^= hash >> 6;
17761 // GetHash.
17762 hash += hash << 3;
17763 hash ^= hash >> 11;
17764 hash += hash << 15;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000017765 if ((hash & String::kHashBitMask) == 0) hash = StringHasher::kZeroHash;
17766 hash_ = hash;
Steve Blockd0582a62009-12-15 09:54:21 +000017767#ifdef DEBUG
Steve Blockd0582a62009-12-15 09:54:21 +000017768 // If this assert fails then we failed to reproduce the two-character
17769 // version of the string hashing algorithm above. One reason could be
17770 // that we were passed two digits as characters, since the hash
17771 // algorithm is different in that case.
Ben Murdochb8a8cc12014-11-26 15:28:44 +000017772 uint16_t chars[2] = {c1, c2};
17773 uint32_t check_hash = StringHasher::HashSequentialString(chars, 2, seed);
17774 hash = (hash << String::kHashShift) | String::kIsNotArrayIndexMask;
17775 DCHECK_EQ(static_cast<int32_t>(hash), static_cast<int32_t>(check_hash));
Steve Blockd0582a62009-12-15 09:54:21 +000017776#endif
Steve Blockd0582a62009-12-15 09:54:21 +000017777 }
17778
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000017779 bool IsMatch(Object* o) override {
Steve Blockd0582a62009-12-15 09:54:21 +000017780 if (!o->IsString()) return false;
17781 String* other = String::cast(o);
17782 if (other->length() != 2) return false;
17783 if (other->Get(0) != c1_) return false;
17784 return other->Get(1) == c2_;
17785 }
17786
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000017787 uint32_t Hash() override { return hash_; }
17788 uint32_t HashForObject(Object* key) override {
Steve Blockd0582a62009-12-15 09:54:21 +000017789 if (!key->IsString()) return 0;
17790 return String::cast(key)->Hash();
17791 }
17792
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000017793 Handle<Object> AsHandle(Isolate* isolate) override {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000017794 // The TwoCharHashTableKey is only used for looking in the string
Steve Blockd0582a62009-12-15 09:54:21 +000017795 // table, not for adding to it.
17796 UNREACHABLE();
Ben Murdochb8a8cc12014-11-26 15:28:44 +000017797 return MaybeHandle<Object>().ToHandleChecked();
Steve Blockd0582a62009-12-15 09:54:21 +000017798 }
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000017799
Steve Blockd0582a62009-12-15 09:54:21 +000017800 private:
Ben Murdochb8a8cc12014-11-26 15:28:44 +000017801 uint16_t c1_;
17802 uint16_t c2_;
Steve Blockd0582a62009-12-15 09:54:21 +000017803 uint32_t hash_;
17804};
17805
17806
Ben Murdochb8a8cc12014-11-26 15:28:44 +000017807MaybeHandle<String> StringTable::InternalizeStringIfExists(
17808 Isolate* isolate,
17809 Handle<String> string) {
17810 if (string->IsInternalizedString()) {
17811 return string;
17812 }
17813 return LookupStringIfExists(isolate, string);
17814}
17815
17816
17817MaybeHandle<String> StringTable::LookupStringIfExists(
17818 Isolate* isolate,
17819 Handle<String> string) {
17820 Handle<StringTable> string_table = isolate->factory()->string_table();
17821 InternalizedStringKey key(string);
17822 int entry = string_table->FindEntry(&key);
Steve Blocka7e24c12009-10-30 11:49:00 +000017823 if (entry == kNotFound) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000017824 return MaybeHandle<String>();
Steve Blocka7e24c12009-10-30 11:49:00 +000017825 } else {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000017826 Handle<String> result(String::cast(string_table->KeyAt(entry)), isolate);
17827 DCHECK(StringShape(*result).IsInternalized());
17828 return result;
Steve Blocka7e24c12009-10-30 11:49:00 +000017829 }
17830}
17831
17832
Ben Murdochb8a8cc12014-11-26 15:28:44 +000017833MaybeHandle<String> StringTable::LookupTwoCharsStringIfExists(
17834 Isolate* isolate,
17835 uint16_t c1,
17836 uint16_t c2) {
17837 Handle<StringTable> string_table = isolate->factory()->string_table();
17838 TwoCharHashTableKey key(c1, c2, isolate->heap()->HashSeed());
17839 int entry = string_table->FindEntry(&key);
Steve Blockd0582a62009-12-15 09:54:21 +000017840 if (entry == kNotFound) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000017841 return MaybeHandle<String>();
Steve Blockd0582a62009-12-15 09:54:21 +000017842 } else {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000017843 Handle<String> result(String::cast(string_table->KeyAt(entry)), isolate);
17844 DCHECK(StringShape(*result).IsInternalized());
17845 return result;
Steve Blockd0582a62009-12-15 09:54:21 +000017846 }
17847}
17848
17849
Emily Bernierd0a1eb72015-03-24 16:35:39 -040017850void StringTable::EnsureCapacityForDeserialization(Isolate* isolate,
17851 int expected) {
17852 Handle<StringTable> table = isolate->factory()->string_table();
17853 // We need a key instance for the virtual hash function.
17854 InternalizedStringKey dummy_key(Handle<String>::null());
17855 table = StringTable::EnsureCapacity(table, expected, &dummy_key);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000017856 isolate->heap()->SetRootStringTable(*table);
Emily Bernierd0a1eb72015-03-24 16:35:39 -040017857}
17858
17859
Ben Murdochb8a8cc12014-11-26 15:28:44 +000017860Handle<String> StringTable::LookupString(Isolate* isolate,
17861 Handle<String> string) {
17862 InternalizedStringKey key(string);
17863 return LookupKey(isolate, &key);
Steve Blocka7e24c12009-10-30 11:49:00 +000017864}
17865
17866
Ben Murdochb8a8cc12014-11-26 15:28:44 +000017867Handle<String> StringTable::LookupKey(Isolate* isolate, HashTableKey* key) {
17868 Handle<StringTable> table = isolate->factory()->string_table();
17869 int entry = table->FindEntry(key);
Steve Block9fac8402011-05-12 15:51:54 +010017870
Ben Murdochb8a8cc12014-11-26 15:28:44 +000017871 // String already in table.
Steve Blocka7e24c12009-10-30 11:49:00 +000017872 if (entry != kNotFound) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000017873 return handle(String::cast(table->KeyAt(entry)), isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +000017874 }
17875
Ben Murdochb8a8cc12014-11-26 15:28:44 +000017876 // Adding new string. Grow table if needed.
17877 table = StringTable::EnsureCapacity(table, 1, key);
Steve Blocka7e24c12009-10-30 11:49:00 +000017878
Ben Murdochb8a8cc12014-11-26 15:28:44 +000017879 // Create string object.
17880 Handle<Object> string = key->AsHandle(isolate);
17881 // There must be no attempts to internalize strings that could throw
17882 // InvalidStringLength error.
17883 CHECK(!string.is_null());
Steve Blocka7e24c12009-10-30 11:49:00 +000017884
Ben Murdochb8a8cc12014-11-26 15:28:44 +000017885 // Add the new string and return it along with the string table.
Steve Blocka7e24c12009-10-30 11:49:00 +000017886 entry = table->FindInsertionEntry(key->Hash());
Ben Murdochb8a8cc12014-11-26 15:28:44 +000017887 table->set(EntryToIndex(entry), *string);
Steve Blocka7e24c12009-10-30 11:49:00 +000017888 table->ElementAdded();
Ben Murdochb8a8cc12014-11-26 15:28:44 +000017889
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000017890 isolate->heap()->SetRootStringTable(*table);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000017891 return Handle<String>::cast(string);
Steve Blocka7e24c12009-10-30 11:49:00 +000017892}
17893
17894
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000017895String* StringTable::LookupKeyIfExists(Isolate* isolate, HashTableKey* key) {
17896 Handle<StringTable> table = isolate->factory()->string_table();
17897 int entry = table->FindEntry(key);
17898 if (entry != kNotFound) return String::cast(table->KeyAt(entry));
17899 return NULL;
17900}
17901
17902
Ben Murdochb8a8cc12014-11-26 15:28:44 +000017903Handle<Object> CompilationCacheTable::Lookup(Handle<String> src,
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000017904 Handle<Context> context,
17905 LanguageMode language_mode) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000017906 Isolate* isolate = GetIsolate();
17907 Handle<SharedFunctionInfo> shared(context->closure()->shared());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000017908 StringSharedKey key(src, shared, language_mode, RelocInfo::kNoPosition);
Steve Blocka7e24c12009-10-30 11:49:00 +000017909 int entry = FindEntry(&key);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000017910 if (entry == kNotFound) return isolate->factory()->undefined_value();
Emily Bernierd0a1eb72015-03-24 16:35:39 -040017911 int index = EntryToIndex(entry);
17912 if (!get(index)->IsFixedArray()) return isolate->factory()->undefined_value();
17913 return Handle<Object>(get(index + 1), isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +000017914}
17915
17916
Ben Murdochb8a8cc12014-11-26 15:28:44 +000017917Handle<Object> CompilationCacheTable::LookupEval(
17918 Handle<String> src, Handle<SharedFunctionInfo> outer_info,
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000017919 LanguageMode language_mode, int scope_position) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000017920 Isolate* isolate = GetIsolate();
17921 // Cache key is the tuple (source, outer shared function info, scope position)
17922 // to unambiguously identify the context chain the cached eval code assumes.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000017923 StringSharedKey key(src, outer_info, language_mode, scope_position);
Steve Blocka7e24c12009-10-30 11:49:00 +000017924 int entry = FindEntry(&key);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000017925 if (entry == kNotFound) return isolate->factory()->undefined_value();
Emily Bernierd0a1eb72015-03-24 16:35:39 -040017926 int index = EntryToIndex(entry);
17927 if (!get(index)->IsFixedArray()) return isolate->factory()->undefined_value();
Ben Murdochb8a8cc12014-11-26 15:28:44 +000017928 return Handle<Object>(get(EntryToIndex(entry) + 1), isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +000017929}
17930
17931
Ben Murdochb8a8cc12014-11-26 15:28:44 +000017932Handle<Object> CompilationCacheTable::LookupRegExp(Handle<String> src,
17933 JSRegExp::Flags flags) {
17934 Isolate* isolate = GetIsolate();
17935 DisallowHeapAllocation no_allocation;
Steve Blocka7e24c12009-10-30 11:49:00 +000017936 RegExpKey key(src, flags);
17937 int entry = FindEntry(&key);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000017938 if (entry == kNotFound) return isolate->factory()->undefined_value();
17939 return Handle<Object>(get(EntryToIndex(entry) + 1), isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +000017940}
17941
17942
Ben Murdochb8a8cc12014-11-26 15:28:44 +000017943Handle<CompilationCacheTable> CompilationCacheTable::Put(
17944 Handle<CompilationCacheTable> cache, Handle<String> src,
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000017945 Handle<Context> context, LanguageMode language_mode, Handle<Object> value) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000017946 Isolate* isolate = cache->GetIsolate();
17947 Handle<SharedFunctionInfo> shared(context->closure()->shared());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000017948 StringSharedKey key(src, shared, language_mode, RelocInfo::kNoPosition);
Emily Bernierd0a1eb72015-03-24 16:35:39 -040017949 {
17950 Handle<Object> k = key.AsHandle(isolate);
17951 DisallowHeapAllocation no_allocation_scope;
17952 int entry = cache->FindEntry(&key);
17953 if (entry != kNotFound) {
17954 cache->set(EntryToIndex(entry), *k);
17955 cache->set(EntryToIndex(entry) + 1, *value);
17956 return cache;
17957 }
17958 }
17959
Ben Murdochb8a8cc12014-11-26 15:28:44 +000017960 cache = EnsureCapacity(cache, 1, &key);
Steve Blocka7e24c12009-10-30 11:49:00 +000017961 int entry = cache->FindInsertionEntry(key.Hash());
Emily Bernierd0a1eb72015-03-24 16:35:39 -040017962 Handle<Object> k =
17963 isolate->factory()->NewNumber(static_cast<double>(key.Hash()));
Ben Murdochb8a8cc12014-11-26 15:28:44 +000017964 cache->set(EntryToIndex(entry), *k);
Emily Bernierd0a1eb72015-03-24 16:35:39 -040017965 cache->set(EntryToIndex(entry) + 1, Smi::FromInt(kHashGenerations));
Steve Blocka7e24c12009-10-30 11:49:00 +000017966 cache->ElementAdded();
17967 return cache;
17968}
17969
17970
Ben Murdochb8a8cc12014-11-26 15:28:44 +000017971Handle<CompilationCacheTable> CompilationCacheTable::PutEval(
17972 Handle<CompilationCacheTable> cache, Handle<String> src,
17973 Handle<SharedFunctionInfo> outer_info, Handle<SharedFunctionInfo> value,
17974 int scope_position) {
17975 Isolate* isolate = cache->GetIsolate();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000017976 StringSharedKey key(src, outer_info, value->language_mode(), scope_position);
Emily Bernierd0a1eb72015-03-24 16:35:39 -040017977 {
17978 Handle<Object> k = key.AsHandle(isolate);
17979 DisallowHeapAllocation no_allocation_scope;
17980 int entry = cache->FindEntry(&key);
17981 if (entry != kNotFound) {
17982 cache->set(EntryToIndex(entry), *k);
17983 cache->set(EntryToIndex(entry) + 1, *value);
17984 return cache;
17985 }
17986 }
17987
Ben Murdochb8a8cc12014-11-26 15:28:44 +000017988 cache = EnsureCapacity(cache, 1, &key);
Steve Blocka7e24c12009-10-30 11:49:00 +000017989 int entry = cache->FindInsertionEntry(key.Hash());
Emily Bernierd0a1eb72015-03-24 16:35:39 -040017990 Handle<Object> k =
17991 isolate->factory()->NewNumber(static_cast<double>(key.Hash()));
Ben Murdochb8a8cc12014-11-26 15:28:44 +000017992 cache->set(EntryToIndex(entry), *k);
Emily Bernierd0a1eb72015-03-24 16:35:39 -040017993 cache->set(EntryToIndex(entry) + 1, Smi::FromInt(kHashGenerations));
Steve Blocka7e24c12009-10-30 11:49:00 +000017994 cache->ElementAdded();
17995 return cache;
17996}
17997
17998
Ben Murdochb8a8cc12014-11-26 15:28:44 +000017999Handle<CompilationCacheTable> CompilationCacheTable::PutRegExp(
18000 Handle<CompilationCacheTable> cache, Handle<String> src,
18001 JSRegExp::Flags flags, Handle<FixedArray> value) {
Steve Blocka7e24c12009-10-30 11:49:00 +000018002 RegExpKey key(src, flags);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000018003 cache = EnsureCapacity(cache, 1, &key);
Steve Blocka7e24c12009-10-30 11:49:00 +000018004 int entry = cache->FindInsertionEntry(key.Hash());
Steve Block3ce2e202009-11-05 08:53:23 +000018005 // We store the value in the key slot, and compare the search key
18006 // to the stored value with a custon IsMatch function during lookups.
Ben Murdochb8a8cc12014-11-26 15:28:44 +000018007 cache->set(EntryToIndex(entry), *value);
18008 cache->set(EntryToIndex(entry) + 1, *value);
Steve Blocka7e24c12009-10-30 11:49:00 +000018009 cache->ElementAdded();
18010 return cache;
18011}
18012
18013
Emily Bernierd0a1eb72015-03-24 16:35:39 -040018014void CompilationCacheTable::Age() {
18015 DisallowHeapAllocation no_allocation;
18016 Object* the_hole_value = GetHeap()->the_hole_value();
18017 for (int entry = 0, size = Capacity(); entry < size; entry++) {
18018 int entry_index = EntryToIndex(entry);
18019 int value_index = entry_index + 1;
18020
18021 if (get(entry_index)->IsNumber()) {
18022 Smi* count = Smi::cast(get(value_index));
18023 count = Smi::FromInt(count->value() - 1);
18024 if (count->value() == 0) {
18025 NoWriteBarrierSet(this, entry_index, the_hole_value);
18026 NoWriteBarrierSet(this, value_index, the_hole_value);
18027 ElementRemoved();
18028 } else {
18029 NoWriteBarrierSet(this, value_index, count);
18030 }
18031 } else if (get(entry_index)->IsFixedArray()) {
18032 SharedFunctionInfo* info = SharedFunctionInfo::cast(get(value_index));
18033 if (info->code()->kind() != Code::FUNCTION || info->code()->IsOld()) {
18034 NoWriteBarrierSet(this, entry_index, the_hole_value);
18035 NoWriteBarrierSet(this, value_index, the_hole_value);
18036 ElementRemoved();
18037 }
18038 }
18039 }
18040}
18041
18042
Ben Murdochb0fe1622011-05-05 13:52:32 +010018043void CompilationCacheTable::Remove(Object* value) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000018044 DisallowHeapAllocation no_allocation;
Ben Murdoch3ef787d2012-04-12 10:51:47 +010018045 Object* the_hole_value = GetHeap()->the_hole_value();
Ben Murdochb0fe1622011-05-05 13:52:32 +010018046 for (int entry = 0, size = Capacity(); entry < size; entry++) {
18047 int entry_index = EntryToIndex(entry);
18048 int value_index = entry_index + 1;
18049 if (get(value_index) == value) {
Ben Murdoch3ef787d2012-04-12 10:51:47 +010018050 NoWriteBarrierSet(this, entry_index, the_hole_value);
18051 NoWriteBarrierSet(this, value_index, the_hole_value);
Ben Murdochb0fe1622011-05-05 13:52:32 +010018052 ElementRemoved();
18053 }
18054 }
18055 return;
18056}
18057
18058
Ben Murdochb8a8cc12014-11-26 15:28:44 +000018059// StringsKey used for HashTable where key is array of internalized strings.
18060class StringsKey : public HashTableKey {
Steve Blocka7e24c12009-10-30 11:49:00 +000018061 public:
Ben Murdochb8a8cc12014-11-26 15:28:44 +000018062 explicit StringsKey(Handle<FixedArray> strings) : strings_(strings) { }
Steve Blocka7e24c12009-10-30 11:49:00 +000018063
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000018064 bool IsMatch(Object* strings) override {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000018065 FixedArray* o = FixedArray::cast(strings);
18066 int len = strings_->length();
Steve Blocka7e24c12009-10-30 11:49:00 +000018067 if (o->length() != len) return false;
18068 for (int i = 0; i < len; i++) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000018069 if (o->get(i) != strings_->get(i)) return false;
Steve Blocka7e24c12009-10-30 11:49:00 +000018070 }
18071 return true;
18072 }
18073
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000018074 uint32_t Hash() override { return HashForObject(*strings_); }
Steve Blocka7e24c12009-10-30 11:49:00 +000018075
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000018076 uint32_t HashForObject(Object* obj) override {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000018077 FixedArray* strings = FixedArray::cast(obj);
18078 int len = strings->length();
Steve Blocka7e24c12009-10-30 11:49:00 +000018079 uint32_t hash = 0;
18080 for (int i = 0; i < len; i++) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000018081 hash ^= String::cast(strings->get(i))->Hash();
Steve Blocka7e24c12009-10-30 11:49:00 +000018082 }
18083 return hash;
18084 }
18085
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000018086 Handle<Object> AsHandle(Isolate* isolate) override { return strings_; }
Steve Blocka7e24c12009-10-30 11:49:00 +000018087
18088 private:
Ben Murdochb8a8cc12014-11-26 15:28:44 +000018089 Handle<FixedArray> strings_;
Steve Blocka7e24c12009-10-30 11:49:00 +000018090};
18091
18092
Ben Murdochb8a8cc12014-11-26 15:28:44 +000018093template<typename Derived, typename Shape, typename Key>
18094Handle<Derived> Dictionary<Derived, Shape, Key>::New(
18095 Isolate* isolate,
18096 int at_least_space_for,
18097 PretenureFlag pretenure) {
18098 DCHECK(0 <= at_least_space_for);
18099 Handle<Derived> dict = DerivedHashTable::New(isolate,
18100 at_least_space_for,
18101 USE_DEFAULT_MINIMUM_CAPACITY,
18102 pretenure);
18103
John Reck59135872010-11-02 12:39:01 -070018104 // Initialize the next enumeration index.
Ben Murdochb8a8cc12014-11-26 15:28:44 +000018105 dict->SetNextEnumerationIndex(PropertyDetails::kInitialIndex);
18106 return dict;
Steve Blocka7e24c12009-10-30 11:49:00 +000018107}
18108
18109
Emily Bernierd0a1eb72015-03-24 16:35:39 -040018110template <typename Derived, typename Shape, typename Key>
18111Handle<FixedArray> Dictionary<Derived, Shape, Key>::BuildIterationIndicesArray(
Ben Murdochb8a8cc12014-11-26 15:28:44 +000018112 Handle<Derived> dictionary) {
18113 Factory* factory = dictionary->GetIsolate()->factory();
18114 int length = dictionary->NumberOfElements();
Steve Blocka7e24c12009-10-30 11:49:00 +000018115
Ben Murdochb8a8cc12014-11-26 15:28:44 +000018116 Handle<FixedArray> iteration_order = factory->NewFixedArray(length);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000018117 Handle<FixedArray> enumeration_order = factory->NewFixedArray(length);
Steve Blocka7e24c12009-10-30 11:49:00 +000018118
Emily Bernierd0a1eb72015-03-24 16:35:39 -040018119 // Fill both the iteration order array and the enumeration order array
18120 // with property details.
Ben Murdochb8a8cc12014-11-26 15:28:44 +000018121 int capacity = dictionary->Capacity();
Steve Blocka7e24c12009-10-30 11:49:00 +000018122 int pos = 0;
18123 for (int i = 0; i < capacity; i++) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000018124 if (dictionary->IsKey(dictionary->KeyAt(i))) {
18125 int index = dictionary->DetailsAt(i).dictionary_index();
Emily Bernierd0a1eb72015-03-24 16:35:39 -040018126 iteration_order->set(pos, Smi::FromInt(i));
18127 enumeration_order->set(pos, Smi::FromInt(index));
18128 pos++;
Steve Blocka7e24c12009-10-30 11:49:00 +000018129 }
18130 }
Emily Bernierd0a1eb72015-03-24 16:35:39 -040018131 DCHECK(pos == length);
Steve Blocka7e24c12009-10-30 11:49:00 +000018132
18133 // Sort the arrays wrt. enumeration order.
Ben Murdochb8a8cc12014-11-26 15:28:44 +000018134 iteration_order->SortPairs(*enumeration_order, enumeration_order->length());
Emily Bernierd0a1eb72015-03-24 16:35:39 -040018135 return iteration_order;
18136}
Steve Blocka7e24c12009-10-30 11:49:00 +000018137
Emily Bernierd0a1eb72015-03-24 16:35:39 -040018138
18139template <typename Derived, typename Shape, typename Key>
18140Handle<FixedArray>
18141Dictionary<Derived, Shape, Key>::GenerateNewEnumerationIndices(
18142 Handle<Derived> dictionary) {
18143 int length = dictionary->NumberOfElements();
18144
18145 Handle<FixedArray> iteration_order = BuildIterationIndicesArray(dictionary);
18146 DCHECK(iteration_order->length() == length);
18147
18148 // Iterate over the dictionary using the enumeration order and update
18149 // the dictionary with new enumeration indices.
Steve Blocka7e24c12009-10-30 11:49:00 +000018150 for (int i = 0; i < length; i++) {
18151 int index = Smi::cast(iteration_order->get(i))->value();
Emily Bernierd0a1eb72015-03-24 16:35:39 -040018152 DCHECK(dictionary->IsKey(dictionary->KeyAt(index)));
Steve Blocka7e24c12009-10-30 11:49:00 +000018153
Emily Bernierd0a1eb72015-03-24 16:35:39 -040018154 int enum_index = PropertyDetails::kInitialIndex + i;
18155
18156 PropertyDetails details = dictionary->DetailsAt(index);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000018157 PropertyDetails new_details = details.set_index(enum_index);
Emily Bernierd0a1eb72015-03-24 16:35:39 -040018158 dictionary->DetailsAtPut(index, new_details);
Steve Blocka7e24c12009-10-30 11:49:00 +000018159 }
18160
18161 // Set the next enumeration index.
Ben Murdochb8a8cc12014-11-26 15:28:44 +000018162 dictionary->SetNextEnumerationIndex(PropertyDetails::kInitialIndex+length);
Emily Bernierd0a1eb72015-03-24 16:35:39 -040018163 return iteration_order;
Steve Blocka7e24c12009-10-30 11:49:00 +000018164}
18165
Ben Murdochb8a8cc12014-11-26 15:28:44 +000018166
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000018167template <typename Derived, typename Shape, typename Key>
18168void Dictionary<Derived, Shape, Key>::SetRequiresCopyOnCapacityChange() {
18169 DCHECK_EQ(0, DerivedHashTable::NumberOfElements());
18170 DCHECK_EQ(0, DerivedHashTable::NumberOfDeletedElements());
18171 // Make sure that HashTable::EnsureCapacity will create a copy.
18172 DerivedHashTable::SetNumberOfDeletedElements(DerivedHashTable::Capacity());
18173 DCHECK(!DerivedHashTable::HasSufficientCapacity(1));
18174}
18175
18176
18177template <typename Derived, typename Shape, typename Key>
Ben Murdochb8a8cc12014-11-26 15:28:44 +000018178Handle<Derived> Dictionary<Derived, Shape, Key>::EnsureCapacity(
18179 Handle<Derived> dictionary, int n, Key key) {
Steve Blocka7e24c12009-10-30 11:49:00 +000018180 // Check whether there are enough enumeration indices to add n elements.
18181 if (Shape::kIsEnumerable &&
Ben Murdochb8a8cc12014-11-26 15:28:44 +000018182 !PropertyDetails::IsValidIndex(dictionary->NextEnumerationIndex() + n)) {
Steve Blocka7e24c12009-10-30 11:49:00 +000018183 // If not, we generate new indices for the properties.
Ben Murdochb8a8cc12014-11-26 15:28:44 +000018184 GenerateNewEnumerationIndices(dictionary);
Steve Blocka7e24c12009-10-30 11:49:00 +000018185 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +000018186 return DerivedHashTable::EnsureCapacity(dictionary, n, key);
Steve Blocka7e24c12009-10-30 11:49:00 +000018187}
18188
18189
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000018190template <typename Derived, typename Shape, typename Key>
Ben Murdochb8a8cc12014-11-26 15:28:44 +000018191Handle<Object> Dictionary<Derived, Shape, Key>::DeleteProperty(
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000018192 Handle<Derived> dictionary, int entry) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000018193 Factory* factory = dictionary->GetIsolate()->factory();
18194 PropertyDetails details = dictionary->DetailsAt(entry);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000018195 if (!details.IsConfigurable()) return factory->false_value();
Ben Murdochb8a8cc12014-11-26 15:28:44 +000018196
18197 dictionary->SetEntry(
18198 entry, factory->the_hole_value(), factory->the_hole_value());
18199 dictionary->ElementRemoved();
18200 return factory->true_value();
Steve Blocka7e24c12009-10-30 11:49:00 +000018201}
18202
18203
Ben Murdochb8a8cc12014-11-26 15:28:44 +000018204template<typename Derived, typename Shape, typename Key>
18205Handle<Derived> Dictionary<Derived, Shape, Key>::AtPut(
18206 Handle<Derived> dictionary, Key key, Handle<Object> value) {
18207 int entry = dictionary->FindEntry(key);
Steve Blocka7e24c12009-10-30 11:49:00 +000018208
18209 // If the entry is present set the value;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000018210 if (entry != Dictionary::kNotFound) {
18211 dictionary->ValueAtPut(entry, *value);
18212 return dictionary;
Steve Blocka7e24c12009-10-30 11:49:00 +000018213 }
18214
18215 // Check whether the dictionary should be extended.
Ben Murdochb8a8cc12014-11-26 15:28:44 +000018216 dictionary = EnsureCapacity(dictionary, 1, key);
18217#ifdef DEBUG
18218 USE(Shape::AsHandle(dictionary->GetIsolate(), key));
18219#endif
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000018220 PropertyDetails details = PropertyDetails::Empty();
Steve Blocka7e24c12009-10-30 11:49:00 +000018221
Ben Murdochb8a8cc12014-11-26 15:28:44 +000018222 AddEntry(dictionary, key, value, details, dictionary->Hash(key));
18223 return dictionary;
Steve Blocka7e24c12009-10-30 11:49:00 +000018224}
18225
18226
Ben Murdochb8a8cc12014-11-26 15:28:44 +000018227template<typename Derived, typename Shape, typename Key>
18228Handle<Derived> Dictionary<Derived, Shape, Key>::Add(
18229 Handle<Derived> dictionary,
18230 Key key,
18231 Handle<Object> value,
18232 PropertyDetails details) {
Steve Blocka7e24c12009-10-30 11:49:00 +000018233 // Valdate key is absent.
Ben Murdochb8a8cc12014-11-26 15:28:44 +000018234 SLOW_DCHECK((dictionary->FindEntry(key) == Dictionary::kNotFound));
Steve Blocka7e24c12009-10-30 11:49:00 +000018235 // Check whether the dictionary should be extended.
Ben Murdochb8a8cc12014-11-26 15:28:44 +000018236 dictionary = EnsureCapacity(dictionary, 1, key);
Ben Murdochc7cc0282012-03-05 14:35:55 +000018237
Ben Murdochb8a8cc12014-11-26 15:28:44 +000018238 AddEntry(dictionary, key, value, details, dictionary->Hash(key));
18239 return dictionary;
Steve Blocka7e24c12009-10-30 11:49:00 +000018240}
18241
18242
18243// Add a key, value pair to the dictionary.
Ben Murdochb8a8cc12014-11-26 15:28:44 +000018244template<typename Derived, typename Shape, typename Key>
18245void Dictionary<Derived, Shape, Key>::AddEntry(
18246 Handle<Derived> dictionary,
18247 Key key,
18248 Handle<Object> value,
18249 PropertyDetails details,
18250 uint32_t hash) {
Steve Blocka7e24c12009-10-30 11:49:00 +000018251 // Compute the key object.
Ben Murdochb8a8cc12014-11-26 15:28:44 +000018252 Handle<Object> k = Shape::AsHandle(dictionary->GetIsolate(), key);
Steve Blocka7e24c12009-10-30 11:49:00 +000018253
Ben Murdochb8a8cc12014-11-26 15:28:44 +000018254 uint32_t entry = dictionary->FindInsertionEntry(hash);
Steve Blocka7e24c12009-10-30 11:49:00 +000018255 // Insert element at empty or deleted entry
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000018256 if (details.dictionary_index() == 0 && Shape::kIsEnumerable) {
Steve Blocka7e24c12009-10-30 11:49:00 +000018257 // Assign an enumeration index to the property and update
18258 // SetNextEnumerationIndex.
Ben Murdochb8a8cc12014-11-26 15:28:44 +000018259 int index = dictionary->NextEnumerationIndex();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000018260 details = details.set_index(index);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000018261 dictionary->SetNextEnumerationIndex(index + 1);
Steve Blocka7e24c12009-10-30 11:49:00 +000018262 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +000018263 dictionary->SetEntry(entry, k, value, details);
18264 DCHECK((dictionary->KeyAt(entry)->IsNumber() ||
18265 dictionary->KeyAt(entry)->IsName()));
18266 dictionary->ElementAdded();
Steve Blocka7e24c12009-10-30 11:49:00 +000018267}
18268
18269
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000018270void SeededNumberDictionary::UpdateMaxNumberKey(uint32_t key,
18271 bool used_as_prototype) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000018272 DisallowHeapAllocation no_allocation;
Steve Blocka7e24c12009-10-30 11:49:00 +000018273 // If the dictionary requires slow elements an element has already
18274 // been added at a high index.
18275 if (requires_slow_elements()) return;
18276 // Check if this index is high enough that we should require slow
18277 // elements.
18278 if (key > kRequiresSlowElementsLimit) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000018279 if (used_as_prototype) {
18280 // TODO(verwaest): Remove this hack.
18281 TypeFeedbackVector::ClearAllKeyedStoreICs(GetIsolate());
18282 }
Steve Blocka7e24c12009-10-30 11:49:00 +000018283 set_requires_slow_elements();
18284 return;
18285 }
18286 // Update max key value.
18287 Object* max_index_object = get(kMaxNumberKeyIndex);
18288 if (!max_index_object->IsSmi() || max_number_key() < key) {
18289 FixedArray::set(kMaxNumberKeyIndex,
Leon Clarke4515c472010-02-03 11:58:03 +000018290 Smi::FromInt(key << kRequiresSlowElementsTagSize));
Steve Blocka7e24c12009-10-30 11:49:00 +000018291 }
18292}
18293
18294
Ben Murdochb8a8cc12014-11-26 15:28:44 +000018295Handle<SeededNumberDictionary> SeededNumberDictionary::AddNumberEntry(
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000018296 Handle<SeededNumberDictionary> dictionary, uint32_t key,
18297 Handle<Object> value, PropertyDetails details, bool used_as_prototype) {
18298 dictionary->UpdateMaxNumberKey(key, used_as_prototype);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000018299 SLOW_DCHECK(dictionary->FindEntry(key) == kNotFound);
18300 return Add(dictionary, key, value, details);
Steve Blocka7e24c12009-10-30 11:49:00 +000018301}
18302
18303
Ben Murdochb8a8cc12014-11-26 15:28:44 +000018304Handle<UnseededNumberDictionary> UnseededNumberDictionary::AddNumberEntry(
18305 Handle<UnseededNumberDictionary> dictionary,
18306 uint32_t key,
18307 Handle<Object> value) {
18308 SLOW_DCHECK(dictionary->FindEntry(key) == kNotFound);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000018309 return Add(dictionary, key, value, PropertyDetails::Empty());
Ben Murdochc7cc0282012-03-05 14:35:55 +000018310}
18311
18312
Ben Murdochb8a8cc12014-11-26 15:28:44 +000018313Handle<SeededNumberDictionary> SeededNumberDictionary::AtNumberPut(
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000018314 Handle<SeededNumberDictionary> dictionary, uint32_t key,
18315 Handle<Object> value, bool used_as_prototype) {
18316 dictionary->UpdateMaxNumberKey(key, used_as_prototype);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000018317 return AtPut(dictionary, key, value);
Steve Blocka7e24c12009-10-30 11:49:00 +000018318}
18319
18320
Ben Murdochb8a8cc12014-11-26 15:28:44 +000018321Handle<UnseededNumberDictionary> UnseededNumberDictionary::AtNumberPut(
18322 Handle<UnseededNumberDictionary> dictionary,
18323 uint32_t key,
18324 Handle<Object> value) {
18325 return AtPut(dictionary, key, value);
Ben Murdochc7cc0282012-03-05 14:35:55 +000018326}
18327
18328
Ben Murdoch3ef787d2012-04-12 10:51:47 +010018329Handle<SeededNumberDictionary> SeededNumberDictionary::Set(
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000018330 Handle<SeededNumberDictionary> dictionary, uint32_t key,
18331 Handle<Object> value, PropertyDetails details, bool used_as_prototype) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000018332 int entry = dictionary->FindEntry(key);
18333 if (entry == kNotFound) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000018334 return AddNumberEntry(dictionary, key, value, details, used_as_prototype);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000018335 }
18336 // Preserve enumeration index.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000018337 details = details.set_index(dictionary->DetailsAt(entry).dictionary_index());
Ben Murdochb8a8cc12014-11-26 15:28:44 +000018338 Handle<Object> object_key =
18339 SeededNumberDictionaryShape::AsHandle(dictionary->GetIsolate(), key);
18340 dictionary->SetEntry(entry, object_key, value, details);
18341 return dictionary;
Ben Murdoch3ef787d2012-04-12 10:51:47 +010018342}
18343
18344
18345Handle<UnseededNumberDictionary> UnseededNumberDictionary::Set(
18346 Handle<UnseededNumberDictionary> dictionary,
Ben Murdochb8a8cc12014-11-26 15:28:44 +000018347 uint32_t key,
Ben Murdoch3ef787d2012-04-12 10:51:47 +010018348 Handle<Object> value) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000018349 int entry = dictionary->FindEntry(key);
18350 if (entry == kNotFound) return AddNumberEntry(dictionary, key, value);
18351 Handle<Object> object_key =
18352 UnseededNumberDictionaryShape::AsHandle(dictionary->GetIsolate(), key);
18353 dictionary->SetEntry(entry, object_key, value);
18354 return dictionary;
Ben Murdochc7cc0282012-03-05 14:35:55 +000018355}
18356
18357
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000018358template <typename Derived, typename Shape, typename Key>
Ben Murdochb8a8cc12014-11-26 15:28:44 +000018359int Dictionary<Derived, Shape, Key>::NumberOfElementsFilterAttributes(
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000018360 PropertyFilter filter) {
18361 int capacity = this->Capacity();
Steve Blocka7e24c12009-10-30 11:49:00 +000018362 int result = 0;
18363 for (int i = 0; i < capacity; i++) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000018364 Object* k = this->KeyAt(i);
18365 if (this->IsKey(k) && !k->FilterKey(filter)) {
18366 if (this->IsDeleted(i)) continue;
18367 PropertyDetails details = this->DetailsAt(i);
Steve Blocka7e24c12009-10-30 11:49:00 +000018368 PropertyAttributes attr = details.attributes();
18369 if ((attr & filter) == 0) result++;
18370 }
18371 }
18372 return result;
18373}
18374
18375
Emily Bernierd0a1eb72015-03-24 16:35:39 -040018376template <typename Derived, typename Shape, typename Key>
18377bool Dictionary<Derived, Shape, Key>::HasComplexElements() {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000018378 int capacity = this->Capacity();
Emily Bernierd0a1eb72015-03-24 16:35:39 -040018379 for (int i = 0; i < capacity; i++) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000018380 Object* k = this->KeyAt(i);
18381 if (this->IsKey(k) && !k->FilterKey(ALL_PROPERTIES)) {
18382 if (this->IsDeleted(i)) continue;
18383 PropertyDetails details = this->DetailsAt(i);
18384 if (details.type() == ACCESSOR_CONSTANT) return true;
Emily Bernierd0a1eb72015-03-24 16:35:39 -040018385 PropertyAttributes attr = details.attributes();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000018386 if (attr & ALL_ATTRIBUTES_MASK) return true;
Emily Bernierd0a1eb72015-03-24 16:35:39 -040018387 }
18388 }
18389 return false;
18390}
18391
18392
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000018393template <typename Dictionary>
Ben Murdochb8a8cc12014-11-26 15:28:44 +000018394struct EnumIndexComparator {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000018395 explicit EnumIndexComparator(Dictionary* dict) : dict(dict) {}
Ben Murdochb8a8cc12014-11-26 15:28:44 +000018396 bool operator() (Smi* a, Smi* b) {
18397 PropertyDetails da(dict->DetailsAt(a->value()));
18398 PropertyDetails db(dict->DetailsAt(b->value()));
18399 return da.dictionary_index() < db.dictionary_index();
18400 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000018401 Dictionary* dict;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000018402};
18403
18404
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000018405template <typename Derived, typename Shape, typename Key>
18406void Dictionary<Derived, Shape, Key>::CopyEnumKeysTo(FixedArray* storage) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000018407 int length = storage->length();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000018408 int capacity = this->Capacity();
Ben Murdochb8a8cc12014-11-26 15:28:44 +000018409 int properties = 0;
Steve Blocka7e24c12009-10-30 11:49:00 +000018410 for (int i = 0; i < capacity; i++) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000018411 Object* k = this->KeyAt(i);
18412 if (this->IsKey(k) && !k->IsSymbol()) {
18413 PropertyDetails details = this->DetailsAt(i);
18414 if (details.IsDontEnum() || this->IsDeleted(i)) continue;
18415 storage->set(properties, Smi::FromInt(i));
18416 properties++;
18417 if (properties == length) break;
18418 }
Steve Blocka7e24c12009-10-30 11:49:00 +000018419 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +000018420 CHECK_EQ(length, properties);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000018421 EnumIndexComparator<Derived> cmp(static_cast<Derived*>(this));
Ben Murdochb8a8cc12014-11-26 15:28:44 +000018422 Smi** start = reinterpret_cast<Smi**>(storage->GetFirstElementAddress());
18423 std::sort(start, start + length, cmp);
18424 for (int i = 0; i < length; i++) {
18425 int index = Smi::cast(storage->get(i))->value();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000018426 storage->set(i, this->KeyAt(index));
Ben Murdochb8a8cc12014-11-26 15:28:44 +000018427 }
Steve Blocka7e24c12009-10-30 11:49:00 +000018428}
18429
18430
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000018431template <typename Derived, typename Shape, typename Key>
18432int Dictionary<Derived, Shape, Key>::CopyKeysTo(
18433 FixedArray* storage, int index, PropertyFilter filter,
Ben Murdochb8a8cc12014-11-26 15:28:44 +000018434 typename Dictionary<Derived, Shape, Key>::SortMode sort_mode) {
18435 DCHECK(storage->length() >= NumberOfElementsFilterAttributes(filter));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000018436 int start_index = index;
18437 int capacity = this->Capacity();
Steve Blocka7e24c12009-10-30 11:49:00 +000018438 for (int i = 0; i < capacity; i++) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000018439 Object* k = this->KeyAt(i);
18440 if (!this->IsKey(k) || k->FilterKey(filter)) continue;
18441 if (this->IsDeleted(i)) continue;
18442 PropertyDetails details = this->DetailsAt(i);
18443 PropertyAttributes attr = details.attributes();
18444 if ((attr & filter) != 0) continue;
18445 storage->set(index++, k);
Steve Blocka7e24c12009-10-30 11:49:00 +000018446 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +000018447 if (sort_mode == Dictionary::SORTED) {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000018448 storage->SortPairs(storage, index);
18449 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +000018450 DCHECK(storage->length() >= index);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000018451 return index - start_index;
18452}
18453
18454
18455template <typename Derived, typename Shape, typename Key>
18456void Dictionary<Derived, Shape, Key>::CollectKeysTo(
18457 Handle<Dictionary<Derived, Shape, Key> > dictionary, KeyAccumulator* keys,
18458 PropertyFilter filter) {
18459 int capacity = dictionary->Capacity();
18460 Handle<FixedArray> array =
18461 keys->isolate()->factory()->NewFixedArray(dictionary->NumberOfElements());
18462 int array_size = 0;
18463
18464 {
18465 DisallowHeapAllocation no_gc;
18466 Dictionary<Derived, Shape, Key>* raw_dict = *dictionary;
18467 for (int i = 0; i < capacity; i++) {
18468 Object* k = raw_dict->KeyAt(i);
18469 if (!raw_dict->IsKey(k) || k->FilterKey(filter)) continue;
18470 if (raw_dict->IsDeleted(i)) continue;
18471 PropertyDetails details = raw_dict->DetailsAt(i);
18472 if ((details.attributes() & filter) != 0) continue;
18473 if (filter & ONLY_ALL_CAN_READ) {
18474 if (details.kind() != kAccessor) continue;
18475 Object* accessors = raw_dict->ValueAt(i);
18476 if (accessors->IsPropertyCell()) {
18477 accessors = PropertyCell::cast(accessors)->value();
18478 }
18479 if (!accessors->IsAccessorInfo()) continue;
18480 if (!AccessorInfo::cast(accessors)->all_can_read()) continue;
18481 }
18482 array->set(array_size++, Smi::FromInt(i));
18483 }
18484
18485 EnumIndexComparator<Derived> cmp(static_cast<Derived*>(raw_dict));
18486 Smi** start = reinterpret_cast<Smi**>(array->GetFirstElementAddress());
18487 std::sort(start, start + array_size, cmp);
18488 }
18489
18490 for (int i = 0; i < array_size; i++) {
18491 int index = Smi::cast(array->get(i))->value();
18492 keys->AddKey(dictionary->KeyAt(index));
18493 }
Steve Blocka7e24c12009-10-30 11:49:00 +000018494}
18495
18496
18497// Backwards lookup (slow).
Ben Murdochb8a8cc12014-11-26 15:28:44 +000018498template<typename Derived, typename Shape, typename Key>
18499Object* Dictionary<Derived, Shape, Key>::SlowReverseLookup(Object* value) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000018500 int capacity = this->Capacity();
Steve Blocka7e24c12009-10-30 11:49:00 +000018501 for (int i = 0; i < capacity; i++) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000018502 Object* k = this->KeyAt(i);
18503 if (this->IsKey(k)) {
18504 Object* e = this->ValueAt(i);
18505 // TODO(dcarney): this should be templatized.
Ben Murdochb8a8cc12014-11-26 15:28:44 +000018506 if (e->IsPropertyCell()) {
18507 e = PropertyCell::cast(e)->value();
Steve Blocka7e24c12009-10-30 11:49:00 +000018508 }
18509 if (e == value) return k;
18510 }
18511 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +000018512 Heap* heap = Dictionary::GetHeap();
Steve Block44f0eee2011-05-26 01:26:41 +010018513 return heap->undefined_value();
Steve Blocka7e24c12009-10-30 11:49:00 +000018514}
18515
18516
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000018517Object* ObjectHashTable::Lookup(Isolate* isolate, Handle<Object> key,
18518 int32_t hash) {
18519 DisallowHeapAllocation no_gc;
18520 DCHECK(IsKey(*key));
18521
18522 int entry = FindEntry(isolate, key, hash);
18523 if (entry == kNotFound) return isolate->heap()->the_hole_value();
18524 return get(EntryToIndex(entry) + 1);
18525}
18526
18527
Ben Murdochb8a8cc12014-11-26 15:28:44 +000018528Object* ObjectHashTable::Lookup(Handle<Object> key) {
18529 DisallowHeapAllocation no_gc;
18530 DCHECK(IsKey(*key));
Ben Murdoch3ef787d2012-04-12 10:51:47 +010018531
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000018532 Isolate* isolate = GetIsolate();
18533
Ben Murdoch69a99ed2011-11-30 16:03:39 +000018534 // If the object does not have an identity hash, it was never used as a key.
Ben Murdochb8a8cc12014-11-26 15:28:44 +000018535 Object* hash = key->GetHash();
18536 if (hash->IsUndefined()) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000018537 return isolate->heap()->the_hole_value();
Ben Murdoch3ef787d2012-04-12 10:51:47 +010018538 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000018539 return Lookup(isolate, key, Smi::cast(hash)->value());
18540}
18541
18542
18543Object* ObjectHashTable::Lookup(Handle<Object> key, int32_t hash) {
18544 return Lookup(GetIsolate(), key, hash);
Ben Murdoch69a99ed2011-11-30 16:03:39 +000018545}
18546
18547
Ben Murdochb8a8cc12014-11-26 15:28:44 +000018548Handle<ObjectHashTable> ObjectHashTable::Put(Handle<ObjectHashTable> table,
18549 Handle<Object> key,
18550 Handle<Object> value) {
18551 DCHECK(table->IsKey(*key));
18552 DCHECK(!value->IsTheHole());
18553
18554 Isolate* isolate = table->GetIsolate();
Ben Murdoch69a99ed2011-11-30 16:03:39 +000018555 // Make sure the key object has an identity hash code.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000018556 int32_t hash = Object::GetOrCreateHash(isolate, key)->value();
Ben Murdoch69a99ed2011-11-30 16:03:39 +000018557
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000018558 return Put(table, key, value, hash);
18559}
18560
18561
18562Handle<ObjectHashTable> ObjectHashTable::Put(Handle<ObjectHashTable> table,
18563 Handle<Object> key,
18564 Handle<Object> value,
18565 int32_t hash) {
18566 DCHECK(table->IsKey(*key));
18567 DCHECK(!value->IsTheHole());
18568
18569 Isolate* isolate = table->GetIsolate();
18570
18571 int entry = table->FindEntry(isolate, key, hash);
Ben Murdoch69a99ed2011-11-30 16:03:39 +000018572
18573 // Key is already in table, just overwrite value.
18574 if (entry != kNotFound) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000018575 table->set(EntryToIndex(entry) + 1, *value);
18576 return table;
Ben Murdoch69a99ed2011-11-30 16:03:39 +000018577 }
18578
18579 // Check whether the hash table should be extended.
Ben Murdochb8a8cc12014-11-26 15:28:44 +000018580 table = EnsureCapacity(table, 1, key);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000018581 table->AddEntry(table->FindInsertionEntry(hash), *key, *value);
Ben Murdoch69a99ed2011-11-30 16:03:39 +000018582 return table;
18583}
18584
18585
Ben Murdochb8a8cc12014-11-26 15:28:44 +000018586Handle<ObjectHashTable> ObjectHashTable::Remove(Handle<ObjectHashTable> table,
18587 Handle<Object> key,
18588 bool* was_present) {
18589 DCHECK(table->IsKey(*key));
18590
18591 Object* hash = key->GetHash();
18592 if (hash->IsUndefined()) {
18593 *was_present = false;
18594 return table;
18595 }
18596
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000018597 return Remove(table, key, was_present, Smi::cast(hash)->value());
18598}
18599
18600
18601Handle<ObjectHashTable> ObjectHashTable::Remove(Handle<ObjectHashTable> table,
18602 Handle<Object> key,
18603 bool* was_present,
18604 int32_t hash) {
18605 DCHECK(table->IsKey(*key));
18606
18607 int entry = table->FindEntry(table->GetIsolate(), key, hash);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000018608 if (entry == kNotFound) {
18609 *was_present = false;
18610 return table;
18611 }
18612
18613 *was_present = true;
18614 table->RemoveEntry(entry);
18615 return Shrink(table, key);
18616}
18617
18618
Ben Murdoch3ef787d2012-04-12 10:51:47 +010018619void ObjectHashTable::AddEntry(int entry, Object* key, Object* value) {
Ben Murdoch69a99ed2011-11-30 16:03:39 +000018620 set(EntryToIndex(entry), key);
18621 set(EntryToIndex(entry) + 1, value);
18622 ElementAdded();
18623}
18624
18625
Ben Murdoch3ef787d2012-04-12 10:51:47 +010018626void ObjectHashTable::RemoveEntry(int entry) {
18627 set_the_hole(EntryToIndex(entry));
18628 set_the_hole(EntryToIndex(entry) + 1);
Ben Murdoch69a99ed2011-11-30 16:03:39 +000018629 ElementRemoved();
18630}
18631
18632
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000018633Object* WeakHashTable::Lookup(Handle<HeapObject> key) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000018634 DisallowHeapAllocation no_gc;
18635 DCHECK(IsKey(*key));
18636 int entry = FindEntry(key);
18637 if (entry == kNotFound) return GetHeap()->the_hole_value();
18638 return get(EntryToValueIndex(entry));
18639}
18640
18641
18642Handle<WeakHashTable> WeakHashTable::Put(Handle<WeakHashTable> table,
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000018643 Handle<HeapObject> key,
18644 Handle<HeapObject> value) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000018645 DCHECK(table->IsKey(*key));
18646 int entry = table->FindEntry(key);
18647 // Key is already in table, just overwrite value.
18648 if (entry != kNotFound) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000018649 table->set(EntryToValueIndex(entry), *value);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000018650 return table;
18651 }
18652
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000018653 Handle<WeakCell> key_cell = key->GetIsolate()->factory()->NewWeakCell(key);
18654
Ben Murdochb8a8cc12014-11-26 15:28:44 +000018655 // Check whether the hash table should be extended.
18656 table = EnsureCapacity(table, 1, key, TENURED);
18657
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000018658 table->AddEntry(table->FindInsertionEntry(table->Hash(key)), key_cell, value);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000018659 return table;
18660}
18661
18662
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000018663void WeakHashTable::AddEntry(int entry, Handle<WeakCell> key_cell,
18664 Handle<HeapObject> value) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000018665 DisallowHeapAllocation no_allocation;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000018666 set(EntryToIndex(entry), *key_cell);
18667 set(EntryToValueIndex(entry), *value);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000018668 ElementAdded();
18669}
18670
18671
18672template<class Derived, class Iterator, int entrysize>
18673Handle<Derived> OrderedHashTable<Derived, Iterator, entrysize>::Allocate(
18674 Isolate* isolate, int capacity, PretenureFlag pretenure) {
18675 // Capacity must be a power of two, since we depend on being able
18676 // to divide and multiple by 2 (kLoadFactor) to derive capacity
18677 // from number of buckets. If we decide to change kLoadFactor
18678 // to something other than 2, capacity should be stored as another
18679 // field of this object.
18680 capacity = base::bits::RoundUpToPowerOfTwo32(Max(kMinCapacity, capacity));
18681 if (capacity > kMaxCapacity) {
18682 v8::internal::Heap::FatalProcessOutOfMemory("invalid table size", true);
18683 }
18684 int num_buckets = capacity / kLoadFactor;
18685 Handle<FixedArray> backing_store = isolate->factory()->NewFixedArray(
18686 kHashTableStartIndex + num_buckets + (capacity * kEntrySize), pretenure);
18687 backing_store->set_map_no_write_barrier(
18688 isolate->heap()->ordered_hash_table_map());
18689 Handle<Derived> table = Handle<Derived>::cast(backing_store);
18690 for (int i = 0; i < num_buckets; ++i) {
18691 table->set(kHashTableStartIndex + i, Smi::FromInt(kNotFound));
18692 }
18693 table->SetNumberOfBuckets(num_buckets);
18694 table->SetNumberOfElements(0);
18695 table->SetNumberOfDeletedElements(0);
18696 return table;
18697}
18698
18699
18700template<class Derived, class Iterator, int entrysize>
18701Handle<Derived> OrderedHashTable<Derived, Iterator, entrysize>::EnsureGrowable(
18702 Handle<Derived> table) {
18703 DCHECK(!table->IsObsolete());
18704
18705 int nof = table->NumberOfElements();
18706 int nod = table->NumberOfDeletedElements();
18707 int capacity = table->Capacity();
18708 if ((nof + nod) < capacity) return table;
18709 // Don't need to grow if we can simply clear out deleted entries instead.
18710 // Note that we can't compact in place, though, so we always allocate
18711 // a new table.
18712 return Rehash(table, (nod < (capacity >> 1)) ? capacity << 1 : capacity);
18713}
18714
18715
18716template<class Derived, class Iterator, int entrysize>
18717Handle<Derived> OrderedHashTable<Derived, Iterator, entrysize>::Shrink(
18718 Handle<Derived> table) {
18719 DCHECK(!table->IsObsolete());
18720
18721 int nof = table->NumberOfElements();
18722 int capacity = table->Capacity();
18723 if (nof >= (capacity >> 2)) return table;
18724 return Rehash(table, capacity / 2);
18725}
18726
18727
18728template<class Derived, class Iterator, int entrysize>
18729Handle<Derived> OrderedHashTable<Derived, Iterator, entrysize>::Clear(
18730 Handle<Derived> table) {
18731 DCHECK(!table->IsObsolete());
18732
18733 Handle<Derived> new_table =
18734 Allocate(table->GetIsolate(),
18735 kMinCapacity,
18736 table->GetHeap()->InNewSpace(*table) ? NOT_TENURED : TENURED);
18737
18738 table->SetNextTable(*new_table);
Emily Bernierd0a1eb72015-03-24 16:35:39 -040018739 table->SetNumberOfDeletedElements(kClearedTableSentinel);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000018740
18741 return new_table;
18742}
18743
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000018744template <class Derived, class Iterator, int entrysize>
18745bool OrderedHashTable<Derived, Iterator, entrysize>::HasKey(
18746 Handle<Derived> table, Handle<Object> key) {
18747 int entry = table->KeyToFirstEntry(*key);
18748 // Walk the chain in the bucket to find the key.
18749 while (entry != kNotFound) {
18750 Object* candidate_key = table->KeyAt(entry);
18751 if (candidate_key->SameValueZero(*key)) return true;
18752 entry = table->NextChainEntry(entry);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000018753 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000018754 return false;
18755}
18756
18757
18758Handle<OrderedHashSet> OrderedHashSet::Add(Handle<OrderedHashSet> table,
18759 Handle<Object> key) {
18760 int hash = Object::GetOrCreateHash(table->GetIsolate(), key)->value();
18761 int entry = table->HashToEntry(hash);
18762 // Walk the chain of the bucket and try finding the key.
18763 while (entry != kNotFound) {
18764 Object* candidate_key = table->KeyAt(entry);
18765 // Do not add if we have the key already
18766 if (candidate_key->SameValueZero(*key)) return table;
18767 entry = table->NextChainEntry(entry);
18768 }
18769
18770 table = OrderedHashSet::EnsureGrowable(table);
18771 // Read the existing bucket values.
18772 int bucket = table->HashToBucket(hash);
18773 int previous_entry = table->HashToEntry(hash);
18774 int nof = table->NumberOfElements();
18775 // Insert a new entry at the end,
18776 int new_entry = nof + table->NumberOfDeletedElements();
18777 int new_index = table->EntryToIndex(new_entry);
18778 table->set(new_index, *key);
18779 table->set(new_index + kChainOffset, Smi::FromInt(previous_entry));
18780 // and point the bucket to the new entry.
18781 table->set(kHashTableStartIndex + bucket, Smi::FromInt(new_entry));
18782 table->SetNumberOfElements(nof + 1);
18783 return table;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000018784}
18785
18786
18787template<class Derived, class Iterator, int entrysize>
18788Handle<Derived> OrderedHashTable<Derived, Iterator, entrysize>::Rehash(
18789 Handle<Derived> table, int new_capacity) {
18790 DCHECK(!table->IsObsolete());
18791
18792 Handle<Derived> new_table =
18793 Allocate(table->GetIsolate(),
18794 new_capacity,
18795 table->GetHeap()->InNewSpace(*table) ? NOT_TENURED : TENURED);
18796 int nof = table->NumberOfElements();
18797 int nod = table->NumberOfDeletedElements();
18798 int new_buckets = new_table->NumberOfBuckets();
18799 int new_entry = 0;
18800 int removed_holes_index = 0;
18801
18802 for (int old_entry = 0; old_entry < (nof + nod); ++old_entry) {
18803 Object* key = table->KeyAt(old_entry);
18804 if (key->IsTheHole()) {
18805 table->SetRemovedIndexAt(removed_holes_index++, old_entry);
18806 continue;
18807 }
18808
18809 Object* hash = key->GetHash();
18810 int bucket = Smi::cast(hash)->value() & (new_buckets - 1);
18811 Object* chain_entry = new_table->get(kHashTableStartIndex + bucket);
18812 new_table->set(kHashTableStartIndex + bucket, Smi::FromInt(new_entry));
18813 int new_index = new_table->EntryToIndex(new_entry);
18814 int old_index = table->EntryToIndex(old_entry);
18815 for (int i = 0; i < entrysize; ++i) {
18816 Object* value = table->get(old_index + i);
18817 new_table->set(new_index + i, value);
18818 }
18819 new_table->set(new_index + kChainOffset, chain_entry);
18820 ++new_entry;
18821 }
18822
18823 DCHECK_EQ(nod, removed_holes_index);
18824
18825 new_table->SetNumberOfElements(nof);
18826 table->SetNextTable(*new_table);
18827
18828 return new_table;
18829}
18830
18831
Ben Murdochb8a8cc12014-11-26 15:28:44 +000018832template Handle<OrderedHashSet>
18833OrderedHashTable<OrderedHashSet, JSSetIterator, 1>::Allocate(
18834 Isolate* isolate, int capacity, PretenureFlag pretenure);
18835
18836template Handle<OrderedHashSet>
18837OrderedHashTable<OrderedHashSet, JSSetIterator, 1>::EnsureGrowable(
18838 Handle<OrderedHashSet> table);
18839
18840template Handle<OrderedHashSet>
18841OrderedHashTable<OrderedHashSet, JSSetIterator, 1>::Shrink(
18842 Handle<OrderedHashSet> table);
18843
18844template Handle<OrderedHashSet>
18845OrderedHashTable<OrderedHashSet, JSSetIterator, 1>::Clear(
18846 Handle<OrderedHashSet> table);
18847
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000018848template bool OrderedHashTable<OrderedHashSet, JSSetIterator, 1>::HasKey(
18849 Handle<OrderedHashSet> table, Handle<Object> key);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000018850
18851
18852template Handle<OrderedHashMap>
18853OrderedHashTable<OrderedHashMap, JSMapIterator, 2>::Allocate(
18854 Isolate* isolate, int capacity, PretenureFlag pretenure);
18855
18856template Handle<OrderedHashMap>
18857OrderedHashTable<OrderedHashMap, JSMapIterator, 2>::EnsureGrowable(
18858 Handle<OrderedHashMap> table);
18859
18860template Handle<OrderedHashMap>
18861OrderedHashTable<OrderedHashMap, JSMapIterator, 2>::Shrink(
18862 Handle<OrderedHashMap> table);
18863
18864template Handle<OrderedHashMap>
18865OrderedHashTable<OrderedHashMap, JSMapIterator, 2>::Clear(
18866 Handle<OrderedHashMap> table);
18867
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000018868template bool OrderedHashTable<OrderedHashMap, JSMapIterator, 2>::HasKey(
18869 Handle<OrderedHashMap> table, Handle<Object> key);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000018870
18871
18872template<class Derived, class TableType>
18873void OrderedHashTableIterator<Derived, TableType>::Transition() {
18874 DisallowHeapAllocation no_allocation;
18875 TableType* table = TableType::cast(this->table());
18876 if (!table->IsObsolete()) return;
18877
18878 int index = Smi::cast(this->index())->value();
18879 while (table->IsObsolete()) {
18880 TableType* next_table = table->NextTable();
18881
18882 if (index > 0) {
18883 int nod = table->NumberOfDeletedElements();
18884
Emily Bernierd0a1eb72015-03-24 16:35:39 -040018885 if (nod == TableType::kClearedTableSentinel) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000018886 index = 0;
18887 } else {
18888 int old_index = index;
18889 for (int i = 0; i < nod; ++i) {
18890 int removed_index = table->RemovedIndexAt(i);
18891 if (removed_index >= old_index) break;
18892 --index;
18893 }
18894 }
18895 }
18896
18897 table = next_table;
18898 }
18899
18900 set_table(table);
18901 set_index(Smi::FromInt(index));
18902}
18903
18904
18905template<class Derived, class TableType>
18906bool OrderedHashTableIterator<Derived, TableType>::HasMore() {
18907 DisallowHeapAllocation no_allocation;
18908 if (this->table()->IsUndefined()) return false;
18909
18910 Transition();
18911
18912 TableType* table = TableType::cast(this->table());
18913 int index = Smi::cast(this->index())->value();
18914 int used_capacity = table->UsedCapacity();
18915
18916 while (index < used_capacity && table->KeyAt(index)->IsTheHole()) {
18917 index++;
18918 }
18919
18920 set_index(Smi::FromInt(index));
18921
18922 if (index < used_capacity) return true;
18923
18924 set_table(GetHeap()->undefined_value());
18925 return false;
18926}
18927
18928
18929template<class Derived, class TableType>
18930Smi* OrderedHashTableIterator<Derived, TableType>::Next(JSArray* value_array) {
18931 DisallowHeapAllocation no_allocation;
18932 if (HasMore()) {
18933 FixedArray* array = FixedArray::cast(value_array->elements());
18934 static_cast<Derived*>(this)->PopulateValueArray(array);
18935 MoveNext();
18936 return Smi::cast(kind());
18937 }
18938 return Smi::FromInt(0);
18939}
18940
18941
18942template Smi*
18943OrderedHashTableIterator<JSSetIterator, OrderedHashSet>::Next(
18944 JSArray* value_array);
18945
18946template bool
18947OrderedHashTableIterator<JSSetIterator, OrderedHashSet>::HasMore();
18948
18949template void
18950OrderedHashTableIterator<JSSetIterator, OrderedHashSet>::MoveNext();
18951
18952template Object*
18953OrderedHashTableIterator<JSSetIterator, OrderedHashSet>::CurrentKey();
18954
18955template void
18956OrderedHashTableIterator<JSSetIterator, OrderedHashSet>::Transition();
18957
18958
18959template Smi*
18960OrderedHashTableIterator<JSMapIterator, OrderedHashMap>::Next(
18961 JSArray* value_array);
18962
18963template bool
18964OrderedHashTableIterator<JSMapIterator, OrderedHashMap>::HasMore();
18965
18966template void
18967OrderedHashTableIterator<JSMapIterator, OrderedHashMap>::MoveNext();
18968
18969template Object*
18970OrderedHashTableIterator<JSMapIterator, OrderedHashMap>::CurrentKey();
18971
18972template void
18973OrderedHashTableIterator<JSMapIterator, OrderedHashMap>::Transition();
18974
18975
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000018976void JSSet::Initialize(Handle<JSSet> set, Isolate* isolate) {
18977 Handle<OrderedHashSet> table = isolate->factory()->NewOrderedHashSet();
18978 set->set_table(*table);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000018979}
18980
18981
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000018982void JSSet::Clear(Handle<JSSet> set) {
18983 Handle<OrderedHashSet> table(OrderedHashSet::cast(set->table()));
18984 table = OrderedHashSet::Clear(table);
18985 set->set_table(*table);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000018986}
18987
18988
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000018989void JSMap::Initialize(Handle<JSMap> map, Isolate* isolate) {
18990 Handle<OrderedHashMap> table = isolate->factory()->NewOrderedHashMap();
18991 map->set_table(*table);
18992}
18993
18994
18995void JSMap::Clear(Handle<JSMap> map) {
18996 Handle<OrderedHashMap> table(OrderedHashMap::cast(map->table()));
18997 table = OrderedHashMap::Clear(table);
18998 map->set_table(*table);
18999}
19000
19001
19002void JSWeakCollection::Initialize(Handle<JSWeakCollection> weak_collection,
19003 Isolate* isolate) {
19004 Handle<ObjectHashTable> table = ObjectHashTable::New(isolate, 0);
19005 weak_collection->set_table(*table);
19006}
19007
19008
19009void JSWeakCollection::Set(Handle<JSWeakCollection> weak_collection,
19010 Handle<Object> key, Handle<Object> value,
19011 int32_t hash) {
19012 DCHECK(key->IsJSReceiver() || key->IsSymbol());
19013 Handle<ObjectHashTable> table(
19014 ObjectHashTable::cast(weak_collection->table()));
19015 DCHECK(table->IsKey(*key));
19016 Handle<ObjectHashTable> new_table =
19017 ObjectHashTable::Put(table, key, value, hash);
19018 weak_collection->set_table(*new_table);
19019 if (*table != *new_table) {
19020 // Zap the old table since we didn't record slots for its elements.
19021 table->FillWithHoles(0, table->length());
Ben Murdochb8a8cc12014-11-26 15:28:44 +000019022 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000019023}
19024
19025
19026bool JSWeakCollection::Delete(Handle<JSWeakCollection> weak_collection,
19027 Handle<Object> key, int32_t hash) {
19028 DCHECK(key->IsJSReceiver() || key->IsSymbol());
19029 Handle<ObjectHashTable> table(
19030 ObjectHashTable::cast(weak_collection->table()));
19031 DCHECK(table->IsKey(*key));
19032 bool was_present = false;
19033 Handle<ObjectHashTable> new_table =
19034 ObjectHashTable::Remove(table, key, &was_present, hash);
19035 weak_collection->set_table(*new_table);
19036 if (*table != *new_table) {
19037 // Zap the old table since we didn't record slots for its elements.
19038 table->FillWithHoles(0, table->length());
19039 }
19040 return was_present;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000019041}
19042
19043
Steve Blocka7e24c12009-10-30 11:49:00 +000019044// Check if there is a break point at this code position.
19045bool DebugInfo::HasBreakPoint(int code_position) {
19046 // Get the break point info object for this code position.
19047 Object* break_point_info = GetBreakPointInfo(code_position);
19048
19049 // If there is no break point info object or no break points in the break
19050 // point info object there is no break point at this code position.
19051 if (break_point_info->IsUndefined()) return false;
19052 return BreakPointInfo::cast(break_point_info)->GetBreakPointCount() > 0;
19053}
19054
19055
19056// Get the break point info object for this code position.
19057Object* DebugInfo::GetBreakPointInfo(int code_position) {
19058 // Find the index of the break point info object for this code position.
19059 int index = GetBreakPointInfoIndex(code_position);
19060
19061 // Return the break point info object if any.
Ben Murdoch8b112d22011-06-08 16:22:53 +010019062 if (index == kNoBreakPointInfo) return GetHeap()->undefined_value();
Steve Blocka7e24c12009-10-30 11:49:00 +000019063 return BreakPointInfo::cast(break_points()->get(index));
19064}
19065
19066
19067// Clear a break point at the specified code position.
19068void DebugInfo::ClearBreakPoint(Handle<DebugInfo> debug_info,
19069 int code_position,
19070 Handle<Object> break_point_object) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000019071 Handle<Object> break_point_info(debug_info->GetBreakPointInfo(code_position),
19072 debug_info->GetIsolate());
Steve Blocka7e24c12009-10-30 11:49:00 +000019073 if (break_point_info->IsUndefined()) return;
19074 BreakPointInfo::ClearBreakPoint(
19075 Handle<BreakPointInfo>::cast(break_point_info),
19076 break_point_object);
19077}
19078
19079
19080void DebugInfo::SetBreakPoint(Handle<DebugInfo> debug_info,
19081 int code_position,
19082 int source_position,
19083 int statement_position,
19084 Handle<Object> break_point_object) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000019085 Isolate* isolate = debug_info->GetIsolate();
19086 Handle<Object> break_point_info(debug_info->GetBreakPointInfo(code_position),
19087 isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +000019088 if (!break_point_info->IsUndefined()) {
19089 BreakPointInfo::SetBreakPoint(
19090 Handle<BreakPointInfo>::cast(break_point_info),
19091 break_point_object);
19092 return;
19093 }
19094
19095 // Adding a new break point for a code position which did not have any
19096 // break points before. Try to find a free slot.
19097 int index = kNoBreakPointInfo;
19098 for (int i = 0; i < debug_info->break_points()->length(); i++) {
19099 if (debug_info->break_points()->get(i)->IsUndefined()) {
19100 index = i;
19101 break;
19102 }
19103 }
19104 if (index == kNoBreakPointInfo) {
19105 // No free slot - extend break point info array.
19106 Handle<FixedArray> old_break_points =
19107 Handle<FixedArray>(FixedArray::cast(debug_info->break_points()));
Steve Blocka7e24c12009-10-30 11:49:00 +000019108 Handle<FixedArray> new_break_points =
Steve Block44f0eee2011-05-26 01:26:41 +010019109 isolate->factory()->NewFixedArray(
19110 old_break_points->length() +
Ben Murdochb8a8cc12014-11-26 15:28:44 +000019111 DebugInfo::kEstimatedNofBreakPointsInFunction);
Kristian Monsen0d5e1162010-09-30 15:31:59 +010019112
19113 debug_info->set_break_points(*new_break_points);
Steve Blocka7e24c12009-10-30 11:49:00 +000019114 for (int i = 0; i < old_break_points->length(); i++) {
19115 new_break_points->set(i, old_break_points->get(i));
19116 }
19117 index = old_break_points->length();
19118 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +000019119 DCHECK(index != kNoBreakPointInfo);
Steve Blocka7e24c12009-10-30 11:49:00 +000019120
19121 // Allocate new BreakPointInfo object and set the break point.
Steve Block44f0eee2011-05-26 01:26:41 +010019122 Handle<BreakPointInfo> new_break_point_info = Handle<BreakPointInfo>::cast(
19123 isolate->factory()->NewStruct(BREAK_POINT_INFO_TYPE));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000019124 new_break_point_info->set_code_position(code_position);
19125 new_break_point_info->set_source_position(source_position);
19126 new_break_point_info->set_statement_position(statement_position);
Steve Block44f0eee2011-05-26 01:26:41 +010019127 new_break_point_info->set_break_point_objects(
19128 isolate->heap()->undefined_value());
Steve Blocka7e24c12009-10-30 11:49:00 +000019129 BreakPointInfo::SetBreakPoint(new_break_point_info, break_point_object);
19130 debug_info->break_points()->set(index, *new_break_point_info);
19131}
19132
19133
19134// Get the break point objects for a code position.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000019135Handle<Object> DebugInfo::GetBreakPointObjects(int code_position) {
Steve Blocka7e24c12009-10-30 11:49:00 +000019136 Object* break_point_info = GetBreakPointInfo(code_position);
19137 if (break_point_info->IsUndefined()) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000019138 return GetIsolate()->factory()->undefined_value();
Steve Blocka7e24c12009-10-30 11:49:00 +000019139 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000019140 return Handle<Object>(
19141 BreakPointInfo::cast(break_point_info)->break_point_objects(),
19142 GetIsolate());
Steve Blocka7e24c12009-10-30 11:49:00 +000019143}
19144
19145
19146// Get the total number of break points.
19147int DebugInfo::GetBreakPointCount() {
19148 if (break_points()->IsUndefined()) return 0;
19149 int count = 0;
19150 for (int i = 0; i < break_points()->length(); i++) {
19151 if (!break_points()->get(i)->IsUndefined()) {
19152 BreakPointInfo* break_point_info =
19153 BreakPointInfo::cast(break_points()->get(i));
19154 count += break_point_info->GetBreakPointCount();
19155 }
19156 }
19157 return count;
19158}
19159
19160
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000019161Handle<Object> DebugInfo::FindBreakPointInfo(
19162 Handle<DebugInfo> debug_info, Handle<Object> break_point_object) {
19163 Isolate* isolate = debug_info->GetIsolate();
19164 if (!debug_info->break_points()->IsUndefined()) {
19165 for (int i = 0; i < debug_info->break_points()->length(); i++) {
19166 if (!debug_info->break_points()->get(i)->IsUndefined()) {
19167 Handle<BreakPointInfo> break_point_info = Handle<BreakPointInfo>(
19168 BreakPointInfo::cast(debug_info->break_points()->get(i)), isolate);
19169 if (BreakPointInfo::HasBreakPointObject(break_point_info,
19170 break_point_object)) {
19171 return break_point_info;
19172 }
Steve Blocka7e24c12009-10-30 11:49:00 +000019173 }
19174 }
19175 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000019176 return isolate->factory()->undefined_value();
Steve Blocka7e24c12009-10-30 11:49:00 +000019177}
19178
19179
19180// Find the index of the break point info object for the specified code
19181// position.
19182int DebugInfo::GetBreakPointInfoIndex(int code_position) {
19183 if (break_points()->IsUndefined()) return kNoBreakPointInfo;
19184 for (int i = 0; i < break_points()->length(); i++) {
19185 if (!break_points()->get(i)->IsUndefined()) {
19186 BreakPointInfo* break_point_info =
19187 BreakPointInfo::cast(break_points()->get(i));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000019188 if (break_point_info->code_position() == code_position) {
Steve Blocka7e24c12009-10-30 11:49:00 +000019189 return i;
19190 }
19191 }
19192 }
19193 return kNoBreakPointInfo;
19194}
19195
19196
19197// Remove the specified break point object.
19198void BreakPointInfo::ClearBreakPoint(Handle<BreakPointInfo> break_point_info,
19199 Handle<Object> break_point_object) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000019200 Isolate* isolate = break_point_info->GetIsolate();
Steve Blocka7e24c12009-10-30 11:49:00 +000019201 // If there are no break points just ignore.
19202 if (break_point_info->break_point_objects()->IsUndefined()) return;
19203 // If there is a single break point clear it if it is the same.
19204 if (!break_point_info->break_point_objects()->IsFixedArray()) {
19205 if (break_point_info->break_point_objects() == *break_point_object) {
Steve Block44f0eee2011-05-26 01:26:41 +010019206 break_point_info->set_break_point_objects(
19207 isolate->heap()->undefined_value());
Steve Blocka7e24c12009-10-30 11:49:00 +000019208 }
19209 return;
19210 }
19211 // If there are multiple break points shrink the array
Ben Murdochb8a8cc12014-11-26 15:28:44 +000019212 DCHECK(break_point_info->break_point_objects()->IsFixedArray());
Steve Blocka7e24c12009-10-30 11:49:00 +000019213 Handle<FixedArray> old_array =
19214 Handle<FixedArray>(
19215 FixedArray::cast(break_point_info->break_point_objects()));
19216 Handle<FixedArray> new_array =
Steve Block44f0eee2011-05-26 01:26:41 +010019217 isolate->factory()->NewFixedArray(old_array->length() - 1);
Steve Blocka7e24c12009-10-30 11:49:00 +000019218 int found_count = 0;
19219 for (int i = 0; i < old_array->length(); i++) {
19220 if (old_array->get(i) == *break_point_object) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000019221 DCHECK(found_count == 0);
Steve Blocka7e24c12009-10-30 11:49:00 +000019222 found_count++;
19223 } else {
19224 new_array->set(i - found_count, old_array->get(i));
19225 }
19226 }
19227 // If the break point was found in the list change it.
19228 if (found_count > 0) break_point_info->set_break_point_objects(*new_array);
19229}
19230
19231
19232// Add the specified break point object.
19233void BreakPointInfo::SetBreakPoint(Handle<BreakPointInfo> break_point_info,
19234 Handle<Object> break_point_object) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000019235 Isolate* isolate = break_point_info->GetIsolate();
19236
Steve Blocka7e24c12009-10-30 11:49:00 +000019237 // If there was no break point objects before just set it.
19238 if (break_point_info->break_point_objects()->IsUndefined()) {
19239 break_point_info->set_break_point_objects(*break_point_object);
19240 return;
19241 }
19242 // If the break point object is the same as before just ignore.
19243 if (break_point_info->break_point_objects() == *break_point_object) return;
19244 // If there was one break point object before replace with array.
19245 if (!break_point_info->break_point_objects()->IsFixedArray()) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000019246 Handle<FixedArray> array = isolate->factory()->NewFixedArray(2);
Steve Blocka7e24c12009-10-30 11:49:00 +000019247 array->set(0, break_point_info->break_point_objects());
19248 array->set(1, *break_point_object);
19249 break_point_info->set_break_point_objects(*array);
19250 return;
19251 }
19252 // If there was more than one break point before extend array.
19253 Handle<FixedArray> old_array =
19254 Handle<FixedArray>(
19255 FixedArray::cast(break_point_info->break_point_objects()));
19256 Handle<FixedArray> new_array =
Ben Murdochb8a8cc12014-11-26 15:28:44 +000019257 isolate->factory()->NewFixedArray(old_array->length() + 1);
Steve Blocka7e24c12009-10-30 11:49:00 +000019258 for (int i = 0; i < old_array->length(); i++) {
19259 // If the break point was there before just ignore.
19260 if (old_array->get(i) == *break_point_object) return;
19261 new_array->set(i, old_array->get(i));
19262 }
19263 // Add the new break point.
19264 new_array->set(old_array->length(), *break_point_object);
19265 break_point_info->set_break_point_objects(*new_array);
19266}
19267
19268
19269bool BreakPointInfo::HasBreakPointObject(
19270 Handle<BreakPointInfo> break_point_info,
19271 Handle<Object> break_point_object) {
19272 // No break point.
19273 if (break_point_info->break_point_objects()->IsUndefined()) return false;
Ben Murdoch69a99ed2011-11-30 16:03:39 +000019274 // Single break point.
Steve Blocka7e24c12009-10-30 11:49:00 +000019275 if (!break_point_info->break_point_objects()->IsFixedArray()) {
19276 return break_point_info->break_point_objects() == *break_point_object;
19277 }
19278 // Multiple break points.
19279 FixedArray* array = FixedArray::cast(break_point_info->break_point_objects());
19280 for (int i = 0; i < array->length(); i++) {
19281 if (array->get(i) == *break_point_object) {
19282 return true;
19283 }
19284 }
19285 return false;
19286}
19287
19288
19289// Get the number of break points.
19290int BreakPointInfo::GetBreakPointCount() {
19291 // No break point.
19292 if (break_point_objects()->IsUndefined()) return 0;
Ben Murdoch69a99ed2011-11-30 16:03:39 +000019293 // Single break point.
Steve Blocka7e24c12009-10-30 11:49:00 +000019294 if (!break_point_objects()->IsFixedArray()) return 1;
19295 // Multiple break points.
19296 return FixedArray::cast(break_point_objects())->length();
19297}
Steve Blocka7e24c12009-10-30 11:49:00 +000019298
19299
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000019300// static
19301MaybeHandle<JSDate> JSDate::New(Handle<JSFunction> constructor,
19302 Handle<JSReceiver> new_target, double tv) {
19303 Isolate* const isolate = constructor->GetIsolate();
19304 Handle<JSObject> result;
19305 ASSIGN_RETURN_ON_EXCEPTION(isolate, result,
19306 JSObject::New(constructor, new_target), JSDate);
19307 if (-DateCache::kMaxTimeInMs <= tv && tv <= DateCache::kMaxTimeInMs) {
19308 tv = DoubleToInteger(tv) + 0.0;
19309 } else {
19310 tv = std::numeric_limits<double>::quiet_NaN();
19311 }
19312 Handle<Object> value = isolate->factory()->NewNumber(tv);
19313 Handle<JSDate>::cast(result)->SetValue(*value, std::isnan(tv));
19314 return Handle<JSDate>::cast(result);
19315}
19316
19317
19318// static
19319double JSDate::CurrentTimeValue(Isolate* isolate) {
19320 if (FLAG_log_timer_events || FLAG_prof_cpp) LOG(isolate, CurrentTimeEvent());
19321
19322 // According to ECMA-262, section 15.9.1, page 117, the precision of
19323 // the number in a Date object representing a particular instant in
19324 // time is milliseconds. Therefore, we floor the result of getting
19325 // the OS time.
19326 return Floor(FLAG_verify_predictable
19327 ? isolate->heap()->MonotonicallyIncreasingTimeInMs()
19328 : base::OS::TimeCurrentMillis());
19329}
19330
19331
19332// static
Ben Murdochb8a8cc12014-11-26 15:28:44 +000019333Object* JSDate::GetField(Object* object, Smi* index) {
Ben Murdoch3ef787d2012-04-12 10:51:47 +010019334 return JSDate::cast(object)->DoGetField(
19335 static_cast<FieldIndex>(index->value()));
19336}
19337
19338
19339Object* JSDate::DoGetField(FieldIndex index) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000019340 DCHECK(index != kDateValue);
Ben Murdoch3ef787d2012-04-12 10:51:47 +010019341
19342 DateCache* date_cache = GetIsolate()->date_cache();
19343
19344 if (index < kFirstUncachedField) {
19345 Object* stamp = cache_stamp();
19346 if (stamp != date_cache->stamp() && stamp->IsSmi()) {
19347 // Since the stamp is not NaN, the value is also not NaN.
19348 int64_t local_time_ms =
19349 date_cache->ToLocal(static_cast<int64_t>(value()->Number()));
Ben Murdochb8a8cc12014-11-26 15:28:44 +000019350 SetCachedFields(local_time_ms, date_cache);
Ben Murdoch3ef787d2012-04-12 10:51:47 +010019351 }
19352 switch (index) {
19353 case kYear: return year();
19354 case kMonth: return month();
19355 case kDay: return day();
19356 case kWeekday: return weekday();
19357 case kHour: return hour();
19358 case kMinute: return min();
19359 case kSecond: return sec();
19360 default: UNREACHABLE();
19361 }
19362 }
19363
19364 if (index >= kFirstUTCField) {
19365 return GetUTCField(index, value()->Number(), date_cache);
19366 }
19367
19368 double time = value()->Number();
Ben Murdochb8a8cc12014-11-26 15:28:44 +000019369 if (std::isnan(time)) return GetIsolate()->heap()->nan_value();
Ben Murdoch3ef787d2012-04-12 10:51:47 +010019370
19371 int64_t local_time_ms = date_cache->ToLocal(static_cast<int64_t>(time));
19372 int days = DateCache::DaysFromTime(local_time_ms);
19373
19374 if (index == kDays) return Smi::FromInt(days);
19375
19376 int time_in_day_ms = DateCache::TimeInDay(local_time_ms, days);
19377 if (index == kMillisecond) return Smi::FromInt(time_in_day_ms % 1000);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000019378 DCHECK(index == kTimeInDay);
Ben Murdoch3ef787d2012-04-12 10:51:47 +010019379 return Smi::FromInt(time_in_day_ms);
19380}
19381
19382
19383Object* JSDate::GetUTCField(FieldIndex index,
19384 double value,
19385 DateCache* date_cache) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000019386 DCHECK(index >= kFirstUTCField);
Ben Murdoch3ef787d2012-04-12 10:51:47 +010019387
Ben Murdochb8a8cc12014-11-26 15:28:44 +000019388 if (std::isnan(value)) return GetIsolate()->heap()->nan_value();
Ben Murdoch3ef787d2012-04-12 10:51:47 +010019389
19390 int64_t time_ms = static_cast<int64_t>(value);
19391
19392 if (index == kTimezoneOffset) {
19393 return Smi::FromInt(date_cache->TimezoneOffset(time_ms));
19394 }
19395
19396 int days = DateCache::DaysFromTime(time_ms);
19397
19398 if (index == kWeekdayUTC) return Smi::FromInt(date_cache->Weekday(days));
19399
19400 if (index <= kDayUTC) {
19401 int year, month, day;
19402 date_cache->YearMonthDayFromDays(days, &year, &month, &day);
19403 if (index == kYearUTC) return Smi::FromInt(year);
19404 if (index == kMonthUTC) return Smi::FromInt(month);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000019405 DCHECK(index == kDayUTC);
Ben Murdoch3ef787d2012-04-12 10:51:47 +010019406 return Smi::FromInt(day);
19407 }
19408
19409 int time_in_day_ms = DateCache::TimeInDay(time_ms, days);
19410 switch (index) {
19411 case kHourUTC: return Smi::FromInt(time_in_day_ms / (60 * 60 * 1000));
19412 case kMinuteUTC: return Smi::FromInt((time_in_day_ms / (60 * 1000)) % 60);
19413 case kSecondUTC: return Smi::FromInt((time_in_day_ms / 1000) % 60);
19414 case kMillisecondUTC: return Smi::FromInt(time_in_day_ms % 1000);
19415 case kDaysUTC: return Smi::FromInt(days);
19416 case kTimeInDayUTC: return Smi::FromInt(time_in_day_ms);
19417 default: UNREACHABLE();
19418 }
19419
19420 UNREACHABLE();
19421 return NULL;
19422}
19423
19424
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000019425// static
19426Handle<Object> JSDate::SetValue(Handle<JSDate> date, double v) {
19427 Isolate* const isolate = date->GetIsolate();
19428 Handle<Object> value = isolate->factory()->NewNumber(v);
19429 bool value_is_nan = std::isnan(v);
19430 date->SetValue(*value, value_is_nan);
19431 return value;
19432}
19433
19434
Ben Murdoch3ef787d2012-04-12 10:51:47 +010019435void JSDate::SetValue(Object* value, bool is_value_nan) {
19436 set_value(value);
19437 if (is_value_nan) {
19438 HeapNumber* nan = GetIsolate()->heap()->nan_value();
19439 set_cache_stamp(nan, SKIP_WRITE_BARRIER);
19440 set_year(nan, SKIP_WRITE_BARRIER);
19441 set_month(nan, SKIP_WRITE_BARRIER);
19442 set_day(nan, SKIP_WRITE_BARRIER);
19443 set_hour(nan, SKIP_WRITE_BARRIER);
19444 set_min(nan, SKIP_WRITE_BARRIER);
19445 set_sec(nan, SKIP_WRITE_BARRIER);
19446 set_weekday(nan, SKIP_WRITE_BARRIER);
19447 } else {
19448 set_cache_stamp(Smi::FromInt(DateCache::kInvalidStamp), SKIP_WRITE_BARRIER);
19449 }
19450}
19451
19452
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000019453// static
19454MaybeHandle<Object> JSDate::ToPrimitive(Handle<JSReceiver> receiver,
19455 Handle<Object> hint) {
19456 Isolate* const isolate = receiver->GetIsolate();
19457 if (hint->IsString()) {
19458 Handle<String> hint_string = Handle<String>::cast(hint);
19459 if (hint_string->Equals(isolate->heap()->number_string())) {
19460 return JSReceiver::OrdinaryToPrimitive(receiver,
19461 OrdinaryToPrimitiveHint::kNumber);
19462 }
19463 if (hint_string->Equals(isolate->heap()->default_string()) ||
19464 hint_string->Equals(isolate->heap()->string_string())) {
19465 return JSReceiver::OrdinaryToPrimitive(receiver,
19466 OrdinaryToPrimitiveHint::kString);
19467 }
19468 }
19469 THROW_NEW_ERROR(isolate, NewTypeError(MessageTemplate::kInvalidHint, hint),
19470 Object);
19471}
19472
19473
Ben Murdochb8a8cc12014-11-26 15:28:44 +000019474void JSDate::SetCachedFields(int64_t local_time_ms, DateCache* date_cache) {
Ben Murdoch3ef787d2012-04-12 10:51:47 +010019475 int days = DateCache::DaysFromTime(local_time_ms);
19476 int time_in_day_ms = DateCache::TimeInDay(local_time_ms, days);
19477 int year, month, day;
19478 date_cache->YearMonthDayFromDays(days, &year, &month, &day);
19479 int weekday = date_cache->Weekday(days);
19480 int hour = time_in_day_ms / (60 * 60 * 1000);
19481 int min = (time_in_day_ms / (60 * 1000)) % 60;
19482 int sec = (time_in_day_ms / 1000) % 60;
19483 set_cache_stamp(date_cache->stamp());
19484 set_year(Smi::FromInt(year), SKIP_WRITE_BARRIER);
19485 set_month(Smi::FromInt(month), SKIP_WRITE_BARRIER);
19486 set_day(Smi::FromInt(day), SKIP_WRITE_BARRIER);
19487 set_weekday(Smi::FromInt(weekday), SKIP_WRITE_BARRIER);
19488 set_hour(Smi::FromInt(hour), SKIP_WRITE_BARRIER);
19489 set_min(Smi::FromInt(min), SKIP_WRITE_BARRIER);
19490 set_sec(Smi::FromInt(sec), SKIP_WRITE_BARRIER);
19491}
19492
Ben Murdochb8a8cc12014-11-26 15:28:44 +000019493
19494void JSArrayBuffer::Neuter() {
Emily Bernierd0a1eb72015-03-24 16:35:39 -040019495 CHECK(is_neuterable());
19496 CHECK(is_external());
Ben Murdochb8a8cc12014-11-26 15:28:44 +000019497 set_backing_store(NULL);
19498 set_byte_length(Smi::FromInt(0));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000019499 set_was_neutered(true);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000019500}
19501
19502
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000019503void JSArrayBuffer::Setup(Handle<JSArrayBuffer> array_buffer, Isolate* isolate,
19504 bool is_external, void* data, size_t allocated_length,
19505 SharedFlag shared) {
19506 DCHECK(array_buffer->GetInternalFieldCount() ==
19507 v8::ArrayBuffer::kInternalFieldCount);
19508 for (int i = 0; i < v8::ArrayBuffer::kInternalFieldCount; i++) {
19509 array_buffer->SetInternalField(i, Smi::FromInt(0));
Ben Murdochb8a8cc12014-11-26 15:28:44 +000019510 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000019511 array_buffer->set_bit_field(0);
19512 array_buffer->set_is_external(is_external);
19513 array_buffer->set_is_neuterable(shared == SharedFlag::kNotShared);
19514 array_buffer->set_is_shared(shared == SharedFlag::kShared);
19515
19516 Handle<Object> byte_length =
19517 isolate->factory()->NewNumberFromSize(allocated_length);
19518 CHECK(byte_length->IsSmi() || byte_length->IsHeapNumber());
19519 array_buffer->set_byte_length(*byte_length);
19520 // Initialize backing store at last to avoid handling of |JSArrayBuffers| that
19521 // are currently being constructed in the |ArrayBufferTracker|. The
19522 // registration method below handles the case of registering a buffer that has
19523 // already been promoted.
19524 array_buffer->set_backing_store(data);
19525
19526 if (data && !is_external) {
19527 isolate->heap()->RegisterNewArrayBuffer(*array_buffer);
19528 }
19529}
19530
19531
19532bool JSArrayBuffer::SetupAllocatingData(Handle<JSArrayBuffer> array_buffer,
19533 Isolate* isolate,
19534 size_t allocated_length,
19535 bool initialize, SharedFlag shared) {
19536 void* data;
19537 CHECK(isolate->array_buffer_allocator() != NULL);
19538 // Prevent creating array buffers when serializing.
19539 DCHECK(!isolate->serializer_enabled());
19540 if (allocated_length != 0) {
19541 if (initialize) {
19542 data = isolate->array_buffer_allocator()->Allocate(allocated_length);
19543 } else {
19544 data = isolate->array_buffer_allocator()->AllocateUninitialized(
19545 allocated_length);
19546 }
19547 if (data == NULL) return false;
19548 } else {
19549 data = NULL;
19550 }
19551
19552 JSArrayBuffer::Setup(array_buffer, isolate, false, data, allocated_length,
19553 shared);
19554 return true;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000019555}
19556
19557
19558Handle<JSArrayBuffer> JSTypedArray::MaterializeArrayBuffer(
19559 Handle<JSTypedArray> typed_array) {
19560
19561 Handle<Map> map(typed_array->map());
19562 Isolate* isolate = typed_array->GetIsolate();
19563
19564 DCHECK(IsFixedTypedArrayElementsKind(map->elements_kind()));
19565
Ben Murdochb8a8cc12014-11-26 15:28:44 +000019566 Handle<FixedTypedArrayBase> fixed_typed_array(
19567 FixedTypedArrayBase::cast(typed_array->elements()));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000019568
19569 Handle<JSArrayBuffer> buffer(JSArrayBuffer::cast(typed_array->buffer()),
19570 isolate);
19571 void* backing_store =
19572 isolate->array_buffer_allocator()->AllocateUninitialized(
19573 fixed_typed_array->DataSize());
19574 buffer->set_is_external(false);
19575 DCHECK(buffer->byte_length()->IsSmi() ||
19576 buffer->byte_length()->IsHeapNumber());
19577 DCHECK(NumberToInt32(buffer->byte_length()) == fixed_typed_array->DataSize());
19578 // Initialize backing store at last to avoid handling of |JSArrayBuffers| that
19579 // are currently being constructed in the |ArrayBufferTracker|. The
19580 // registration method below handles the case of registering a buffer that has
19581 // already been promoted.
19582 buffer->set_backing_store(backing_store);
19583 isolate->heap()->RegisterNewArrayBuffer(*buffer);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000019584 memcpy(buffer->backing_store(),
19585 fixed_typed_array->DataPtr(),
19586 fixed_typed_array->DataSize());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000019587 Handle<FixedTypedArrayBase> new_elements =
19588 isolate->factory()->NewFixedTypedArrayWithExternalPointer(
Ben Murdochb8a8cc12014-11-26 15:28:44 +000019589 fixed_typed_array->length(), typed_array->type(),
19590 static_cast<uint8_t*>(buffer->backing_store()));
19591
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000019592 typed_array->set_elements(*new_elements);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000019593
19594 return buffer;
19595}
19596
19597
19598Handle<JSArrayBuffer> JSTypedArray::GetBuffer() {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000019599 Handle<JSArrayBuffer> array_buffer(JSArrayBuffer::cast(buffer()),
19600 GetIsolate());
19601 if (array_buffer->was_neutered() ||
19602 array_buffer->backing_store() != nullptr) {
19603 return array_buffer;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000019604 }
19605 Handle<JSTypedArray> self(this);
19606 return MaterializeArrayBuffer(self);
19607}
19608
19609
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000019610Handle<PropertyCell> PropertyCell::InvalidateEntry(
19611 Handle<GlobalDictionary> dictionary, int entry) {
19612 Isolate* isolate = dictionary->GetIsolate();
19613 // Swap with a copy.
19614 DCHECK(dictionary->ValueAt(entry)->IsPropertyCell());
19615 Handle<PropertyCell> cell(PropertyCell::cast(dictionary->ValueAt(entry)));
19616 auto new_cell = isolate->factory()->NewPropertyCell();
19617 new_cell->set_value(cell->value());
19618 dictionary->ValueAtPut(entry, *new_cell);
19619 bool is_the_hole = cell->value()->IsTheHole();
19620 // Cell is officially mutable henceforth.
19621 PropertyDetails details = cell->property_details();
19622 details = details.set_cell_type(is_the_hole ? PropertyCellType::kInvalidated
19623 : PropertyCellType::kMutable);
19624 new_cell->set_property_details(details);
19625 // Old cell is ready for invalidation.
19626 if (is_the_hole) {
19627 cell->set_value(isolate->heap()->undefined_value());
19628 } else {
19629 cell->set_value(isolate->heap()->the_hole_value());
19630 }
19631 details = details.set_cell_type(PropertyCellType::kInvalidated);
19632 cell->set_property_details(details);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000019633 cell->dependent_code()->DeoptimizeDependentCodeGroup(
19634 isolate, DependentCode::kPropertyCellChangedGroup);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000019635 return new_cell;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000019636}
19637
19638
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000019639PropertyCellConstantType PropertyCell::GetConstantType() {
19640 if (value()->IsSmi()) return PropertyCellConstantType::kSmi;
19641 return PropertyCellConstantType::kStableMap;
19642}
19643
19644
19645static bool RemainsConstantType(Handle<PropertyCell> cell,
19646 Handle<Object> value) {
19647 // TODO(dcarney): double->smi and smi->double transition from kConstant
19648 if (cell->value()->IsSmi() && value->IsSmi()) {
19649 return true;
19650 } else if (cell->value()->IsHeapObject() && value->IsHeapObject()) {
19651 return HeapObject::cast(cell->value())->map() ==
19652 HeapObject::cast(*value)->map() &&
19653 HeapObject::cast(*value)->map()->is_stable();
Emily Bernierd0a1eb72015-03-24 16:35:39 -040019654 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000019655 return false;
19656}
19657
19658
19659PropertyCellType PropertyCell::UpdatedType(Handle<PropertyCell> cell,
19660 Handle<Object> value,
19661 PropertyDetails details) {
19662 PropertyCellType type = details.cell_type();
19663 DCHECK(!value->IsTheHole());
19664 if (cell->value()->IsTheHole()) {
19665 switch (type) {
19666 // Only allow a cell to transition once into constant state.
19667 case PropertyCellType::kUninitialized:
19668 if (value->IsUndefined()) return PropertyCellType::kUndefined;
19669 return PropertyCellType::kConstant;
19670 case PropertyCellType::kInvalidated:
19671 return PropertyCellType::kMutable;
19672 default:
19673 UNREACHABLE();
19674 return PropertyCellType::kMutable;
19675 }
19676 }
19677 switch (type) {
19678 case PropertyCellType::kUndefined:
19679 return PropertyCellType::kConstant;
19680 case PropertyCellType::kConstant:
19681 if (*value == cell->value()) return PropertyCellType::kConstant;
19682 // Fall through.
19683 case PropertyCellType::kConstantType:
19684 if (RemainsConstantType(cell, value)) {
19685 return PropertyCellType::kConstantType;
19686 }
19687 // Fall through.
19688 case PropertyCellType::kMutable:
19689 return PropertyCellType::kMutable;
19690 }
19691 UNREACHABLE();
19692 return PropertyCellType::kMutable;
19693}
19694
19695
19696void PropertyCell::UpdateCell(Handle<GlobalDictionary> dictionary, int entry,
19697 Handle<Object> value, PropertyDetails details) {
19698 DCHECK(!value->IsTheHole());
19699 DCHECK(dictionary->ValueAt(entry)->IsPropertyCell());
19700 Handle<PropertyCell> cell(PropertyCell::cast(dictionary->ValueAt(entry)));
19701 const PropertyDetails original_details = cell->property_details();
19702 // Data accesses could be cached in ics or optimized code.
19703 bool invalidate =
19704 original_details.kind() == kData && details.kind() == kAccessor;
19705 int index = original_details.dictionary_index();
19706 PropertyCellType old_type = original_details.cell_type();
19707 // Preserve the enumeration index unless the property was deleted or never
19708 // initialized.
19709 if (cell->value()->IsTheHole()) {
19710 index = dictionary->NextEnumerationIndex();
19711 dictionary->SetNextEnumerationIndex(index + 1);
19712 // Negative lookup cells must be invalidated.
19713 invalidate = true;
19714 }
19715 DCHECK(index > 0);
19716 details = details.set_index(index);
19717
19718 PropertyCellType new_type = UpdatedType(cell, value, original_details);
19719 if (invalidate) cell = PropertyCell::InvalidateEntry(dictionary, entry);
19720
19721 // Install new property details and cell value.
19722 details = details.set_cell_type(new_type);
19723 cell->set_property_details(details);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000019724 cell->set_value(*value);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000019725
19726 // Deopt when transitioning from a constant type.
19727 if (!invalidate && (old_type != new_type ||
19728 original_details.IsReadOnly() != details.IsReadOnly())) {
19729 Isolate* isolate = dictionary->GetIsolate();
19730 cell->dependent_code()->DeoptimizeDependentCodeGroup(
19731 isolate, DependentCode::kPropertyCellChangedGroup);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000019732 }
19733}
19734
19735
19736// static
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000019737void PropertyCell::SetValueWithInvalidation(Handle<PropertyCell> cell,
19738 Handle<Object> new_value) {
19739 if (cell->value() != *new_value) {
19740 cell->set_value(*new_value);
19741 Isolate* isolate = cell->GetIsolate();
19742 cell->dependent_code()->DeoptimizeDependentCodeGroup(
19743 isolate, DependentCode::kPropertyCellChangedGroup);
19744 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +000019745}
19746
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000019747} // namespace internal
19748} // namespace v8