blob: f577d5e4d3ec4d9449ab1e5dd88e6a8963798980 [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"
Ben Murdoch097c5b22016-05-18 11:27:45 +010014#include "src/api-natives.h"
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015#include "src/arguments.h"
16#include "src/base/bits.h"
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000017#include "src/base/utils/random-number-generator.h"
Ben Murdochb8a8cc12014-11-26 15:28:44 +000018#include "src/bootstrapper.h"
19#include "src/code-stubs.h"
20#include "src/codegen.h"
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000021#include "src/compilation-dependencies.h"
22#include "src/compiler.h"
Ben Murdochb8a8cc12014-11-26 15:28:44 +000023#include "src/date.h"
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000024#include "src/debug/debug.h"
Ben Murdochb8a8cc12014-11-26 15:28:44 +000025#include "src/deoptimizer.h"
26#include "src/elements.h"
27#include "src/execution.h"
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000028#include "src/field-index-inl.h"
Ben Murdoch097c5b22016-05-18 11:27:45 +010029#include "src/field-index.h"
30#include "src/field-type.h"
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000031#include "src/full-codegen/full-codegen.h"
Ben Murdochb8a8cc12014-11-26 15:28:44 +000032#include "src/ic/ic.h"
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000033#include "src/identity-map.h"
34#include "src/interpreter/bytecodes.h"
Ben Murdoch097c5b22016-05-18 11:27:45 +010035#include "src/interpreter/source-position-table.h"
Ben Murdochb8a8cc12014-11-26 15:28:44 +000036#include "src/isolate-inl.h"
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000037#include "src/key-accumulator.h"
38#include "src/list.h"
Ben Murdochb8a8cc12014-11-26 15:28:44 +000039#include "src/log.h"
40#include "src/lookup.h"
41#include "src/macro-assembler.h"
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000042#include "src/messages.h"
Ben Murdochb8a8cc12014-11-26 15:28:44 +000043#include "src/objects-inl.h"
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000044#include "src/objects-body-descriptors-inl.h"
45#include "src/profiler/cpu-profiler.h"
46#include "src/property-descriptor.h"
Ben Murdochb8a8cc12014-11-26 15:28:44 +000047#include "src/prototype.h"
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000048#include "src/regexp/jsregexp.h"
Ben Murdochb8a8cc12014-11-26 15:28:44 +000049#include "src/safepoint-table.h"
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000050#include "src/string-builder.h"
Ben Murdochb8a8cc12014-11-26 15:28:44 +000051#include "src/string-search.h"
52#include "src/string-stream.h"
53#include "src/utils.h"
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000054#include "src/zone.h"
Steve Blocka7e24c12009-10-30 11:49:00 +000055
56#ifdef ENABLE_DISASSEMBLER
Ben Murdochb8a8cc12014-11-26 15:28:44 +000057#include "src/disasm.h"
58#include "src/disassembler.h"
Steve Blocka7e24c12009-10-30 11:49:00 +000059#endif
60
Steve Blocka7e24c12009-10-30 11:49:00 +000061namespace v8 {
62namespace internal {
63
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000064std::ostream& operator<<(std::ostream& os, InstanceType instance_type) {
65 switch (instance_type) {
66#define WRITE_TYPE(TYPE) \
67 case TYPE: \
68 return os << #TYPE;
69 INSTANCE_TYPE_LIST(WRITE_TYPE)
70#undef WRITE_TYPE
71 }
72 UNREACHABLE();
73 return os << "UNKNOWN"; // Keep the compiler happy.
74}
75
Ben Murdoch097c5b22016-05-18 11:27:45 +010076Handle<FieldType> Object::OptimalType(Isolate* isolate,
77 Representation representation) {
78 if (representation.IsNone()) return FieldType::None(isolate);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000079 if (FLAG_track_field_types) {
80 if (representation.IsHeapObject() && IsHeapObject()) {
81 // We can track only JavaScript objects with stable maps.
82 Handle<Map> map(HeapObject::cast(this)->map(), isolate);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000083 if (map->is_stable() && map->IsJSReceiverMap()) {
Ben Murdoch097c5b22016-05-18 11:27:45 +010084 return FieldType::Class(map, isolate);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000085 }
86 }
87 }
Ben Murdoch097c5b22016-05-18 11:27:45 +010088 return FieldType::Any(isolate);
Ben Murdoch3ef787d2012-04-12 10:51:47 +010089}
90
Steve Blocka7e24c12009-10-30 11:49:00 +000091
Ben Murdochb8a8cc12014-11-26 15:28:44 +000092MaybeHandle<JSReceiver> Object::ToObject(Isolate* isolate,
93 Handle<Object> object,
94 Handle<Context> native_context) {
95 if (object->IsJSReceiver()) return Handle<JSReceiver>::cast(object);
96 Handle<JSFunction> constructor;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000097 if (object->IsSmi()) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000098 constructor = handle(native_context->number_function(), isolate);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000099 } else {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000100 int constructor_function_index =
101 Handle<HeapObject>::cast(object)->map()->GetConstructorFunctionIndex();
102 if (constructor_function_index == Map::kNoConstructorFunctionIndex) {
Ben Murdoch097c5b22016-05-18 11:27:45 +0100103 THROW_NEW_ERROR(isolate,
104 NewTypeError(MessageTemplate::kUndefinedOrNullToObject),
105 JSReceiver);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000106 }
107 constructor = handle(
108 JSFunction::cast(native_context->get(constructor_function_index)),
109 isolate);
John Reck59135872010-11-02 12:39:01 -0700110 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000111 Handle<JSObject> result = isolate->factory()->NewJSObject(constructor);
112 Handle<JSValue>::cast(result)->set_value(*object);
Steve Blocka7e24c12009-10-30 11:49:00 +0000113 return result;
114}
115
116
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000117// static
118MaybeHandle<Name> Object::ToName(Isolate* isolate, Handle<Object> input) {
119 ASSIGN_RETURN_ON_EXCEPTION(
120 isolate, input, Object::ToPrimitive(input, ToPrimitiveHint::kString),
121 Name);
122 if (input->IsName()) return Handle<Name>::cast(input);
123 return ToString(isolate, input);
124}
125
126
127// static
128MaybeHandle<Object> Object::ToNumber(Handle<Object> input) {
129 while (true) {
130 if (input->IsNumber()) {
131 return input;
132 }
133 if (input->IsString()) {
134 return String::ToNumber(Handle<String>::cast(input));
135 }
136 if (input->IsOddball()) {
137 return Oddball::ToNumber(Handle<Oddball>::cast(input));
138 }
139 Isolate* const isolate = Handle<HeapObject>::cast(input)->GetIsolate();
140 if (input->IsSymbol()) {
141 THROW_NEW_ERROR(isolate, NewTypeError(MessageTemplate::kSymbolToNumber),
142 Object);
143 }
144 if (input->IsSimd128Value()) {
145 THROW_NEW_ERROR(isolate, NewTypeError(MessageTemplate::kSimdToNumber),
146 Object);
147 }
148 ASSIGN_RETURN_ON_EXCEPTION(
149 isolate, input, JSReceiver::ToPrimitive(Handle<JSReceiver>::cast(input),
150 ToPrimitiveHint::kNumber),
151 Object);
152 }
153}
154
155
156// static
157MaybeHandle<Object> Object::ToInteger(Isolate* isolate, Handle<Object> input) {
158 ASSIGN_RETURN_ON_EXCEPTION(isolate, input, ToNumber(input), Object);
159 return isolate->factory()->NewNumber(DoubleToInteger(input->Number()));
160}
161
162
163// static
164MaybeHandle<Object> Object::ToInt32(Isolate* isolate, Handle<Object> input) {
165 ASSIGN_RETURN_ON_EXCEPTION(isolate, input, ToNumber(input), Object);
166 return isolate->factory()->NewNumberFromInt(DoubleToInt32(input->Number()));
167}
168
169
170// static
171MaybeHandle<Object> Object::ToUint32(Isolate* isolate, Handle<Object> input) {
172 ASSIGN_RETURN_ON_EXCEPTION(isolate, input, ToNumber(input), Object);
173 return isolate->factory()->NewNumberFromUint(DoubleToUint32(input->Number()));
174}
175
176
177// static
178MaybeHandle<String> Object::ToString(Isolate* isolate, Handle<Object> input) {
179 while (true) {
180 if (input->IsString()) {
181 return Handle<String>::cast(input);
182 }
183 if (input->IsOddball()) {
184 return handle(Handle<Oddball>::cast(input)->to_string(), isolate);
185 }
186 if (input->IsNumber()) {
187 return isolate->factory()->NumberToString(input);
188 }
189 if (input->IsSymbol()) {
190 THROW_NEW_ERROR(isolate, NewTypeError(MessageTemplate::kSymbolToString),
191 String);
192 }
193 if (input->IsSimd128Value()) {
194 return Simd128Value::ToString(Handle<Simd128Value>::cast(input));
195 }
196 ASSIGN_RETURN_ON_EXCEPTION(
197 isolate, input, JSReceiver::ToPrimitive(Handle<JSReceiver>::cast(input),
198 ToPrimitiveHint::kString),
199 String);
200 }
201}
202
203
204// static
205MaybeHandle<Object> Object::ToLength(Isolate* isolate, Handle<Object> input) {
206 ASSIGN_RETURN_ON_EXCEPTION(isolate, input, ToNumber(input), Object);
207 double len = DoubleToInteger(input->Number());
208 if (len <= 0.0) {
209 len = 0.0;
210 } else if (len >= kMaxSafeInteger) {
211 len = kMaxSafeInteger;
212 }
213 return isolate->factory()->NewNumber(len);
214}
215
216
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000217bool Object::BooleanValue() {
218 if (IsBoolean()) return IsTrue();
219 if (IsSmi()) return Smi::cast(this)->value() != 0;
220 if (IsUndefined() || IsNull()) return false;
221 if (IsUndetectableObject()) return false; // Undetectable object is false.
222 if (IsString()) return String::cast(this)->length() != 0;
223 if (IsHeapNumber()) return HeapNumber::cast(this)->HeapNumberBooleanValue();
224 return true;
Steve Blocka7e24c12009-10-30 11:49:00 +0000225}
226
227
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000228namespace {
229
230// TODO(bmeurer): Maybe we should introduce a marker interface Number,
231// where we put all these methods at some point?
232ComparisonResult NumberCompare(double x, double y) {
233 if (std::isnan(x) || std::isnan(y)) {
234 return ComparisonResult::kUndefined;
235 } else if (x < y) {
236 return ComparisonResult::kLessThan;
237 } else if (x > y) {
238 return ComparisonResult::kGreaterThan;
239 } else {
240 return ComparisonResult::kEqual;
Steve Blocka7e24c12009-10-30 11:49:00 +0000241 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000242}
243
244
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000245bool NumberEquals(double x, double y) {
246 // Must check explicitly for NaN's on Windows, but -0 works fine.
247 if (std::isnan(x)) return false;
248 if (std::isnan(y)) return false;
249 return x == y;
250}
251
252
253bool NumberEquals(const Object* x, const Object* y) {
254 return NumberEquals(x->Number(), y->Number());
255}
256
257
258bool NumberEquals(Handle<Object> x, Handle<Object> y) {
259 return NumberEquals(*x, *y);
260}
261
262} // namespace
263
264
265// static
Ben Murdoch097c5b22016-05-18 11:27:45 +0100266Maybe<ComparisonResult> Object::Compare(Handle<Object> x, Handle<Object> y) {
267 // ES6 section 7.2.11 Abstract Relational Comparison step 3 and 4.
268 if (!Object::ToPrimitive(x, ToPrimitiveHint::kNumber).ToHandle(&x) ||
269 !Object::ToPrimitive(y, ToPrimitiveHint::kNumber).ToHandle(&y)) {
270 return Nothing<ComparisonResult>();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000271 }
272 if (x->IsString() && y->IsString()) {
273 // ES6 section 7.2.11 Abstract Relational Comparison step 5.
274 return Just(
275 String::Compare(Handle<String>::cast(x), Handle<String>::cast(y)));
276 }
277 // ES6 section 7.2.11 Abstract Relational Comparison step 6.
Ben Murdoch097c5b22016-05-18 11:27:45 +0100278 if (!Object::ToNumber(x).ToHandle(&x) || !Object::ToNumber(y).ToHandle(&y)) {
279 return Nothing<ComparisonResult>();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000280 }
281 return Just(NumberCompare(x->Number(), y->Number()));
282}
283
284
285// static
286Maybe<bool> Object::Equals(Handle<Object> x, Handle<Object> y) {
287 while (true) {
288 if (x->IsNumber()) {
289 if (y->IsNumber()) {
290 return Just(NumberEquals(x, y));
291 } else if (y->IsBoolean()) {
292 return Just(NumberEquals(*x, Handle<Oddball>::cast(y)->to_number()));
293 } else if (y->IsString()) {
294 return Just(NumberEquals(x, String::ToNumber(Handle<String>::cast(y))));
295 } else if (y->IsJSReceiver() && !y->IsUndetectableObject()) {
296 if (!JSReceiver::ToPrimitive(Handle<JSReceiver>::cast(y))
297 .ToHandle(&y)) {
298 return Nothing<bool>();
299 }
300 } else {
301 return Just(false);
302 }
303 } else if (x->IsString()) {
304 if (y->IsString()) {
305 return Just(
306 String::Equals(Handle<String>::cast(x), Handle<String>::cast(y)));
307 } else if (y->IsNumber()) {
308 x = String::ToNumber(Handle<String>::cast(x));
309 return Just(NumberEquals(x, y));
310 } else if (y->IsBoolean()) {
311 x = String::ToNumber(Handle<String>::cast(x));
312 return Just(NumberEquals(*x, Handle<Oddball>::cast(y)->to_number()));
313 } else if (y->IsJSReceiver() && !y->IsUndetectableObject()) {
314 if (!JSReceiver::ToPrimitive(Handle<JSReceiver>::cast(y))
315 .ToHandle(&y)) {
316 return Nothing<bool>();
317 }
318 } else {
319 return Just(false);
320 }
321 } else if (x->IsBoolean()) {
322 if (y->IsOddball()) {
323 return Just(x.is_identical_to(y));
324 } else if (y->IsNumber()) {
325 return Just(NumberEquals(Handle<Oddball>::cast(x)->to_number(), *y));
326 } else if (y->IsString()) {
327 y = String::ToNumber(Handle<String>::cast(y));
328 return Just(NumberEquals(Handle<Oddball>::cast(x)->to_number(), *y));
329 } else if (y->IsJSReceiver() && !y->IsUndetectableObject()) {
330 if (!JSReceiver::ToPrimitive(Handle<JSReceiver>::cast(y))
331 .ToHandle(&y)) {
332 return Nothing<bool>();
333 }
334 x = Oddball::ToNumber(Handle<Oddball>::cast(x));
335 } else {
336 return Just(false);
337 }
338 } else if (x->IsSymbol()) {
339 if (y->IsSymbol()) {
340 return Just(x.is_identical_to(y));
341 } else if (y->IsJSReceiver() && !y->IsUndetectableObject()) {
342 if (!JSReceiver::ToPrimitive(Handle<JSReceiver>::cast(y))
343 .ToHandle(&y)) {
344 return Nothing<bool>();
345 }
346 } else {
347 return Just(false);
348 }
349 } else if (x->IsSimd128Value()) {
350 if (y->IsSimd128Value()) {
351 return Just(Simd128Value::Equals(Handle<Simd128Value>::cast(x),
352 Handle<Simd128Value>::cast(y)));
353 } else if (y->IsJSReceiver() && !y->IsUndetectableObject()) {
354 if (!JSReceiver::ToPrimitive(Handle<JSReceiver>::cast(y))
355 .ToHandle(&y)) {
356 return Nothing<bool>();
357 }
358 } else {
359 return Just(false);
360 }
361 } else if (x->IsJSReceiver() && !x->IsUndetectableObject()) {
362 if (y->IsJSReceiver()) {
363 return Just(x.is_identical_to(y));
364 } else if (y->IsNull() || y->IsUndefined()) {
365 return Just(false);
366 } else if (y->IsBoolean()) {
367 y = Oddball::ToNumber(Handle<Oddball>::cast(y));
368 } else if (!JSReceiver::ToPrimitive(Handle<JSReceiver>::cast(x))
369 .ToHandle(&x)) {
370 return Nothing<bool>();
371 }
372 } else {
373 return Just(
374 (x->IsNull() || x->IsUndefined() || x->IsUndetectableObject()) &&
375 (y->IsNull() || y->IsUndefined() || y->IsUndetectableObject()));
376 }
377 }
378}
379
380
381bool Object::StrictEquals(Object* that) {
382 if (this->IsNumber()) {
383 if (!that->IsNumber()) return false;
384 return NumberEquals(this, that);
385 } else if (this->IsString()) {
386 if (!that->IsString()) return false;
387 return String::cast(this)->Equals(String::cast(that));
388 } else if (this->IsSimd128Value()) {
389 if (!that->IsSimd128Value()) return false;
390 return Simd128Value::cast(this)->Equals(Simd128Value::cast(that));
391 }
392 return this == that;
393}
394
395
396// static
397Handle<String> Object::TypeOf(Isolate* isolate, Handle<Object> object) {
398 if (object->IsNumber()) return isolate->factory()->number_string();
Ben Murdoch097c5b22016-05-18 11:27:45 +0100399 if (object->IsOddball()) return handle(Oddball::cast(*object)->type_of());
400 if (object->IsUndetectableObject()) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000401 return isolate->factory()->undefined_string();
402 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000403 if (object->IsString()) return isolate->factory()->string_string();
404 if (object->IsSymbol()) return isolate->factory()->symbol_string();
405 if (object->IsString()) return isolate->factory()->string_string();
406#define SIMD128_TYPE(TYPE, Type, type, lane_count, lane_type) \
407 if (object->Is##Type()) return isolate->factory()->type##_string();
408 SIMD128_TYPES(SIMD128_TYPE)
409#undef SIMD128_TYPE
410 if (object->IsCallable()) return isolate->factory()->function_string();
411 return isolate->factory()->object_string();
412}
413
414
415// static
416MaybeHandle<Object> Object::Multiply(Isolate* isolate, Handle<Object> lhs,
Ben Murdoch097c5b22016-05-18 11:27:45 +0100417 Handle<Object> rhs) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000418 if (!lhs->IsNumber() || !rhs->IsNumber()) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000419 ASSIGN_RETURN_ON_EXCEPTION(isolate, lhs, Object::ToNumber(lhs), Object);
420 ASSIGN_RETURN_ON_EXCEPTION(isolate, rhs, Object::ToNumber(rhs), Object);
421 }
422 return isolate->factory()->NewNumber(lhs->Number() * rhs->Number());
423}
424
425
426// static
427MaybeHandle<Object> Object::Divide(Isolate* isolate, Handle<Object> lhs,
Ben Murdoch097c5b22016-05-18 11:27:45 +0100428 Handle<Object> rhs) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000429 if (!lhs->IsNumber() || !rhs->IsNumber()) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000430 ASSIGN_RETURN_ON_EXCEPTION(isolate, lhs, Object::ToNumber(lhs), Object);
431 ASSIGN_RETURN_ON_EXCEPTION(isolate, rhs, Object::ToNumber(rhs), Object);
432 }
433 return isolate->factory()->NewNumber(lhs->Number() / rhs->Number());
434}
435
436
437// static
438MaybeHandle<Object> Object::Modulus(Isolate* isolate, Handle<Object> lhs,
Ben Murdoch097c5b22016-05-18 11:27:45 +0100439 Handle<Object> rhs) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000440 if (!lhs->IsNumber() || !rhs->IsNumber()) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000441 ASSIGN_RETURN_ON_EXCEPTION(isolate, lhs, Object::ToNumber(lhs), Object);
442 ASSIGN_RETURN_ON_EXCEPTION(isolate, rhs, Object::ToNumber(rhs), Object);
443 }
444 return isolate->factory()->NewNumber(modulo(lhs->Number(), rhs->Number()));
445}
446
447
448// static
449MaybeHandle<Object> Object::Add(Isolate* isolate, Handle<Object> lhs,
Ben Murdoch097c5b22016-05-18 11:27:45 +0100450 Handle<Object> rhs) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000451 if (lhs->IsNumber() && rhs->IsNumber()) {
452 return isolate->factory()->NewNumber(lhs->Number() + rhs->Number());
453 } else if (lhs->IsString() && rhs->IsString()) {
454 return isolate->factory()->NewConsString(Handle<String>::cast(lhs),
455 Handle<String>::cast(rhs));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000456 }
457 ASSIGN_RETURN_ON_EXCEPTION(isolate, lhs, Object::ToPrimitive(lhs), Object);
458 ASSIGN_RETURN_ON_EXCEPTION(isolate, rhs, Object::ToPrimitive(rhs), Object);
459 if (lhs->IsString() || rhs->IsString()) {
460 ASSIGN_RETURN_ON_EXCEPTION(isolate, rhs, Object::ToString(isolate, rhs),
461 Object);
462 ASSIGN_RETURN_ON_EXCEPTION(isolate, lhs, Object::ToString(isolate, lhs),
463 Object);
464 return isolate->factory()->NewConsString(Handle<String>::cast(lhs),
465 Handle<String>::cast(rhs));
466 }
467 ASSIGN_RETURN_ON_EXCEPTION(isolate, rhs, Object::ToNumber(rhs), Object);
468 ASSIGN_RETURN_ON_EXCEPTION(isolate, lhs, Object::ToNumber(lhs), Object);
469 return isolate->factory()->NewNumber(lhs->Number() + rhs->Number());
470}
471
472
473// static
474MaybeHandle<Object> Object::Subtract(Isolate* isolate, Handle<Object> lhs,
Ben Murdoch097c5b22016-05-18 11:27:45 +0100475 Handle<Object> rhs) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000476 if (!lhs->IsNumber() || !rhs->IsNumber()) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000477 ASSIGN_RETURN_ON_EXCEPTION(isolate, lhs, Object::ToNumber(lhs), Object);
478 ASSIGN_RETURN_ON_EXCEPTION(isolate, rhs, Object::ToNumber(rhs), Object);
479 }
480 return isolate->factory()->NewNumber(lhs->Number() - rhs->Number());
481}
482
483
484// static
485MaybeHandle<Object> Object::ShiftLeft(Isolate* isolate, Handle<Object> lhs,
Ben Murdoch097c5b22016-05-18 11:27:45 +0100486 Handle<Object> rhs) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000487 if (!lhs->IsNumber() || !rhs->IsNumber()) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000488 ASSIGN_RETURN_ON_EXCEPTION(isolate, lhs, Object::ToNumber(lhs), Object);
489 ASSIGN_RETURN_ON_EXCEPTION(isolate, rhs, Object::ToNumber(rhs), Object);
490 }
491 return isolate->factory()->NewNumberFromInt(NumberToInt32(*lhs)
492 << (NumberToUint32(*rhs) & 0x1F));
493}
494
495
496// static
497MaybeHandle<Object> Object::ShiftRight(Isolate* isolate, Handle<Object> lhs,
Ben Murdoch097c5b22016-05-18 11:27:45 +0100498 Handle<Object> rhs) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000499 if (!lhs->IsNumber() || !rhs->IsNumber()) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000500 ASSIGN_RETURN_ON_EXCEPTION(isolate, lhs, Object::ToNumber(lhs), Object);
501 ASSIGN_RETURN_ON_EXCEPTION(isolate, rhs, Object::ToNumber(rhs), Object);
502 }
503 return isolate->factory()->NewNumberFromInt(NumberToInt32(*lhs) >>
504 (NumberToUint32(*rhs) & 0x1F));
505}
506
507
508// static
509MaybeHandle<Object> Object::ShiftRightLogical(Isolate* isolate,
510 Handle<Object> lhs,
Ben Murdoch097c5b22016-05-18 11:27:45 +0100511 Handle<Object> rhs) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000512 if (!lhs->IsNumber() || !rhs->IsNumber()) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000513 ASSIGN_RETURN_ON_EXCEPTION(isolate, lhs, Object::ToNumber(lhs), Object);
514 ASSIGN_RETURN_ON_EXCEPTION(isolate, rhs, Object::ToNumber(rhs), Object);
515 }
516 return isolate->factory()->NewNumberFromUint(NumberToUint32(*lhs) >>
517 (NumberToUint32(*rhs) & 0x1F));
518}
519
520
521// static
522MaybeHandle<Object> Object::BitwiseAnd(Isolate* isolate, Handle<Object> lhs,
Ben Murdoch097c5b22016-05-18 11:27:45 +0100523 Handle<Object> rhs) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000524 if (!lhs->IsNumber() || !rhs->IsNumber()) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000525 ASSIGN_RETURN_ON_EXCEPTION(isolate, lhs, Object::ToNumber(lhs), Object);
526 ASSIGN_RETURN_ON_EXCEPTION(isolate, rhs, Object::ToNumber(rhs), Object);
527 }
528 return isolate->factory()->NewNumberFromInt(NumberToInt32(*lhs) &
529 NumberToInt32(*rhs));
530}
531
532
533// static
534MaybeHandle<Object> Object::BitwiseOr(Isolate* isolate, Handle<Object> lhs,
Ben Murdoch097c5b22016-05-18 11:27:45 +0100535 Handle<Object> rhs) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000536 if (!lhs->IsNumber() || !rhs->IsNumber()) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000537 ASSIGN_RETURN_ON_EXCEPTION(isolate, lhs, Object::ToNumber(lhs), Object);
538 ASSIGN_RETURN_ON_EXCEPTION(isolate, rhs, Object::ToNumber(rhs), Object);
539 }
540 return isolate->factory()->NewNumberFromInt(NumberToInt32(*lhs) |
541 NumberToInt32(*rhs));
542}
543
544
545// static
546MaybeHandle<Object> Object::BitwiseXor(Isolate* isolate, Handle<Object> lhs,
Ben Murdoch097c5b22016-05-18 11:27:45 +0100547 Handle<Object> rhs) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000548 if (!lhs->IsNumber() || !rhs->IsNumber()) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000549 ASSIGN_RETURN_ON_EXCEPTION(isolate, lhs, Object::ToNumber(lhs), Object);
550 ASSIGN_RETURN_ON_EXCEPTION(isolate, rhs, Object::ToNumber(rhs), Object);
551 }
552 return isolate->factory()->NewNumberFromInt(NumberToInt32(*lhs) ^
553 NumberToInt32(*rhs));
554}
555
556
557Maybe<bool> Object::IsArray(Handle<Object> object) {
558 if (object->IsJSArray()) return Just(true);
559 if (object->IsJSProxy()) {
560 Handle<JSProxy> proxy = Handle<JSProxy>::cast(object);
561 Isolate* isolate = proxy->GetIsolate();
562 if (proxy->IsRevoked()) {
563 isolate->Throw(*isolate->factory()->NewTypeError(
564 MessageTemplate::kProxyRevoked,
565 isolate->factory()->NewStringFromAsciiChecked("IsArray")));
566 return Nothing<bool>();
567 }
568 return Object::IsArray(handle(proxy->target(), isolate));
569 }
570 return Just(false);
571}
572
573
574bool Object::IsPromise(Handle<Object> object) {
575 if (!object->IsJSObject()) return false;
576 auto js_object = Handle<JSObject>::cast(object);
577 // Promises can't have access checks.
578 if (js_object->map()->is_access_check_needed()) return false;
579 auto isolate = js_object->GetIsolate();
580 // TODO(dcarney): this should just be read from the symbol registry so as not
581 // to be context dependent.
582 auto key = isolate->factory()->promise_status_symbol();
583 // Shouldn't be possible to throw here.
584 return JSObject::HasRealNamedProperty(js_object, key).FromJust();
585}
586
587
588// static
589MaybeHandle<Object> Object::GetMethod(Handle<JSReceiver> receiver,
590 Handle<Name> name) {
591 Handle<Object> func;
592 Isolate* isolate = receiver->GetIsolate();
593 ASSIGN_RETURN_ON_EXCEPTION(isolate, func,
594 JSReceiver::GetProperty(receiver, name), Object);
595 if (func->IsNull() || func->IsUndefined()) {
596 return isolate->factory()->undefined_value();
597 }
598 if (!func->IsCallable()) {
599 THROW_NEW_ERROR(isolate, NewTypeError(MessageTemplate::kPropertyNotFunction,
600 func, name, receiver),
601 Object);
602 }
603 return func;
604}
605
606
607// static
608MaybeHandle<FixedArray> Object::CreateListFromArrayLike(
609 Isolate* isolate, Handle<Object> object, ElementTypes element_types) {
610 // 1. ReturnIfAbrupt(object).
611 // 2. (default elementTypes -- not applicable.)
612 // 3. If Type(obj) is not Object, throw a TypeError exception.
613 if (!object->IsJSReceiver()) {
614 THROW_NEW_ERROR(isolate,
615 NewTypeError(MessageTemplate::kCalledOnNonObject,
616 isolate->factory()->NewStringFromAsciiChecked(
617 "CreateListFromArrayLike")),
618 FixedArray);
619 }
620 // 4. Let len be ? ToLength(? Get(obj, "length")).
621 Handle<Object> raw_length_obj;
622 ASSIGN_RETURN_ON_EXCEPTION(
623 isolate, raw_length_obj,
624 JSReceiver::GetProperty(object, isolate->factory()->length_string()),
625 FixedArray);
626 Handle<Object> raw_length_number;
627 ASSIGN_RETURN_ON_EXCEPTION(isolate, raw_length_number,
628 Object::ToLength(isolate, raw_length_obj),
629 FixedArray);
630 uint32_t len;
631 if (!raw_length_number->ToUint32(&len) ||
632 len > static_cast<uint32_t>(FixedArray::kMaxLength)) {
633 THROW_NEW_ERROR(isolate,
634 NewRangeError(MessageTemplate::kInvalidArrayLength),
635 FixedArray);
636 }
637 // 5. Let list be an empty List.
638 Handle<FixedArray> list = isolate->factory()->NewFixedArray(len);
639 // 6. Let index be 0.
640 // 7. Repeat while index < len:
641 for (uint32_t index = 0; index < len; ++index) {
642 // 7a. Let indexName be ToString(index).
643 // 7b. Let next be ? Get(obj, indexName).
644 Handle<Object> next;
645 ASSIGN_RETURN_ON_EXCEPTION(
646 isolate, next, Object::GetElement(isolate, object, index), FixedArray);
647 switch (element_types) {
648 case ElementTypes::kAll:
649 // Nothing to do.
650 break;
651 case ElementTypes::kStringAndSymbol: {
652 // 7c. If Type(next) is not an element of elementTypes, throw a
653 // TypeError exception.
654 if (!next->IsName()) {
655 THROW_NEW_ERROR(isolate,
656 NewTypeError(MessageTemplate::kNotPropertyName, next),
657 FixedArray);
658 }
659 // 7d. Append next as the last element of list.
660 // Internalize on the fly so we can use pointer identity later.
661 next = isolate->factory()->InternalizeName(Handle<Name>::cast(next));
662 break;
663 }
664 }
665 list->set(index, *next);
666 // 7e. Set index to index + 1. (See loop header.)
667 }
668 // 8. Return list.
669 return list;
670}
671
672
673// static
674Maybe<bool> JSReceiver::HasProperty(LookupIterator* it) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000675 for (; it->IsFound(); it->Next()) {
676 switch (it->state()) {
677 case LookupIterator::NOT_FOUND:
678 case LookupIterator::TRANSITION:
679 UNREACHABLE();
680 case LookupIterator::JSPROXY:
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000681 // Call the "has" trap on proxies.
682 return JSProxy::HasProperty(it->isolate(), it->GetHolder<JSProxy>(),
683 it->GetName());
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000684 case LookupIterator::INTERCEPTOR: {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000685 Maybe<PropertyAttributes> result =
686 JSObject::GetPropertyAttributesWithInterceptor(it);
687 if (!result.IsJust()) return Nothing<bool>();
688 if (result.FromJust() != ABSENT) return Just(true);
689 break;
690 }
691 case LookupIterator::ACCESS_CHECK: {
692 if (it->HasAccess()) break;
693 Maybe<PropertyAttributes> result =
694 JSObject::GetPropertyAttributesWithFailedAccessCheck(it);
695 if (!result.IsJust()) return Nothing<bool>();
696 return Just(result.FromJust() != ABSENT);
697 }
698 case LookupIterator::INTEGER_INDEXED_EXOTIC:
699 // TypedArray out-of-bounds access.
700 return Just(false);
701 case LookupIterator::ACCESSOR:
702 case LookupIterator::DATA:
703 return Just(true);
704 }
705 }
706 return Just(false);
707}
708
709
710// static
Ben Murdoch097c5b22016-05-18 11:27:45 +0100711MaybeHandle<Object> Object::GetProperty(LookupIterator* it) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000712 for (; it->IsFound(); it->Next()) {
713 switch (it->state()) {
714 case LookupIterator::NOT_FOUND:
715 case LookupIterator::TRANSITION:
716 UNREACHABLE();
717 case LookupIterator::JSPROXY:
718 return JSProxy::GetProperty(it->isolate(), it->GetHolder<JSProxy>(),
Ben Murdoch097c5b22016-05-18 11:27:45 +0100719 it->GetName(), it->GetReceiver());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000720 case LookupIterator::INTERCEPTOR: {
721 bool done;
722 Handle<Object> result;
723 ASSIGN_RETURN_ON_EXCEPTION(
724 it->isolate(), result,
725 JSObject::GetPropertyWithInterceptor(it, &done), Object);
726 if (done) return result;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000727 break;
728 }
729 case LookupIterator::ACCESS_CHECK:
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000730 if (it->HasAccess()) break;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000731 return JSObject::GetPropertyWithFailedAccessCheck(it);
732 case LookupIterator::ACCESSOR:
Ben Murdoch097c5b22016-05-18 11:27:45 +0100733 return GetPropertyWithAccessor(it);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000734 case LookupIterator::INTEGER_INDEXED_EXOTIC:
Ben Murdoch097c5b22016-05-18 11:27:45 +0100735 return ReadAbsentProperty(it);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000736 case LookupIterator::DATA:
737 return it->GetDataValue();
Ben Murdoch8b112d22011-06-08 16:22:53 +0100738 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000739 }
Ben Murdoch097c5b22016-05-18 11:27:45 +0100740 return ReadAbsentProperty(it);
Steve Blocka7e24c12009-10-30 11:49:00 +0000741}
742
743
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000744#define STACK_CHECK(result_value) \
745 do { \
746 StackLimitCheck stack_check(isolate); \
747 if (stack_check.HasOverflowed()) { \
748 isolate->Throw(*isolate->factory()->NewRangeError( \
749 MessageTemplate::kStackOverflow)); \
750 return result_value; \
751 } \
752 } while (false)
753
754
755// static
756MaybeHandle<Object> JSProxy::GetProperty(Isolate* isolate,
757 Handle<JSProxy> proxy,
758 Handle<Name> name,
Ben Murdoch097c5b22016-05-18 11:27:45 +0100759 Handle<Object> receiver) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000760 if (receiver->IsJSGlobalObject()) {
761 THROW_NEW_ERROR(
762 isolate,
763 NewTypeError(MessageTemplate::kReadGlobalReferenceThroughProxy, name),
764 Object);
765 }
766
767 DCHECK(!name->IsPrivate());
768 STACK_CHECK(MaybeHandle<Object>());
769 Handle<Name> trap_name = isolate->factory()->get_string();
770 // 1. Assert: IsPropertyKey(P) is true.
771 // 2. Let handler be the value of the [[ProxyHandler]] internal slot of O.
772 Handle<Object> handler(proxy->handler(), isolate);
773 // 3. If handler is null, throw a TypeError exception.
774 // 4. Assert: Type(handler) is Object.
775 if (proxy->IsRevoked()) {
776 THROW_NEW_ERROR(isolate,
777 NewTypeError(MessageTemplate::kProxyRevoked, trap_name),
778 Object);
779 }
780 // 5. Let target be the value of the [[ProxyTarget]] internal slot of O.
781 Handle<JSReceiver> target(proxy->target(), isolate);
782 // 6. Let trap be ? GetMethod(handler, "get").
783 Handle<Object> trap;
784 ASSIGN_RETURN_ON_EXCEPTION(
785 isolate, trap,
786 Object::GetMethod(Handle<JSReceiver>::cast(handler), trap_name), Object);
787 // 7. If trap is undefined, then
788 if (trap->IsUndefined()) {
789 // 7.a Return target.[[Get]](P, Receiver).
790 LookupIterator it =
791 LookupIterator::PropertyOrElement(isolate, receiver, name, target);
Ben Murdoch097c5b22016-05-18 11:27:45 +0100792 return Object::GetProperty(&it);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000793 }
794 // 8. Let trapResult be ? Call(trap, handler, «target, P, Receiver»).
795 Handle<Object> trap_result;
796 Handle<Object> args[] = {target, name, receiver};
797 ASSIGN_RETURN_ON_EXCEPTION(
798 isolate, trap_result,
799 Execution::Call(isolate, trap, handler, arraysize(args), args), Object);
800 // 9. Let targetDesc be ? target.[[GetOwnProperty]](P).
801 PropertyDescriptor target_desc;
802 Maybe<bool> target_found =
803 JSReceiver::GetOwnPropertyDescriptor(isolate, target, name, &target_desc);
804 MAYBE_RETURN_NULL(target_found);
805 // 10. If targetDesc is not undefined, then
806 if (target_found.FromJust()) {
807 // 10.a. If IsDataDescriptor(targetDesc) and targetDesc.[[Configurable]] is
808 // false and targetDesc.[[Writable]] is false, then
809 // 10.a.i. If SameValue(trapResult, targetDesc.[[Value]]) is false,
810 // throw a TypeError exception.
811 bool inconsistent = PropertyDescriptor::IsDataDescriptor(&target_desc) &&
812 !target_desc.configurable() &&
813 !target_desc.writable() &&
814 !trap_result->SameValue(*target_desc.value());
815 if (inconsistent) {
816 THROW_NEW_ERROR(
817 isolate, NewTypeError(MessageTemplate::kProxyGetNonConfigurableData,
818 name, target_desc.value(), trap_result),
819 Object);
820 }
821 // 10.b. If IsAccessorDescriptor(targetDesc) and targetDesc.[[Configurable]]
822 // is false and targetDesc.[[Get]] is undefined, then
823 // 10.b.i. If trapResult is not undefined, throw a TypeError exception.
824 inconsistent = PropertyDescriptor::IsAccessorDescriptor(&target_desc) &&
825 !target_desc.configurable() &&
826 target_desc.get()->IsUndefined() &&
827 !trap_result->IsUndefined();
828 if (inconsistent) {
829 THROW_NEW_ERROR(
830 isolate,
831 NewTypeError(MessageTemplate::kProxyGetNonConfigurableAccessor, name,
832 trap_result),
833 Object);
834 }
835 }
836 // 11. Return trap_result
837 return trap_result;
838}
839
840
841Handle<Object> JSReceiver::GetDataProperty(Handle<JSReceiver> object,
842 Handle<Name> name) {
843 LookupIterator it(object, name,
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000844 LookupIterator::PROTOTYPE_CHAIN_SKIP_INTERCEPTOR);
845 return GetDataProperty(&it);
Steve Blocka7e24c12009-10-30 11:49:00 +0000846}
847
848
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000849Handle<Object> JSReceiver::GetDataProperty(LookupIterator* it) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000850 for (; it->IsFound(); it->Next()) {
851 switch (it->state()) {
852 case LookupIterator::INTERCEPTOR:
853 case LookupIterator::NOT_FOUND:
854 case LookupIterator::TRANSITION:
855 UNREACHABLE();
856 case LookupIterator::ACCESS_CHECK:
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000857 // Support calling this method without an active context, but refuse
858 // access to access-checked objects in that case.
859 if (it->isolate()->context() != nullptr && it->HasAccess()) continue;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000860 // Fall through.
861 case LookupIterator::JSPROXY:
862 it->NotFound();
863 return it->isolate()->factory()->undefined_value();
864 case LookupIterator::ACCESSOR:
Ben Murdoch097c5b22016-05-18 11:27:45 +0100865 // TODO(verwaest): For now this doesn't call into AccessorInfo, since
866 // clients don't need it. Update once relevant.
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000867 it->NotFound();
868 return it->isolate()->factory()->undefined_value();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000869 case LookupIterator::INTEGER_INDEXED_EXOTIC:
870 return it->isolate()->factory()->undefined_value();
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000871 case LookupIterator::DATA:
872 return it->GetDataValue();
873 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000874 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000875 return it->isolate()->factory()->undefined_value();
876}
Steve Blocka7e24c12009-10-30 11:49:00 +0000877
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000878
879bool Object::ToInt32(int32_t* value) {
880 if (IsSmi()) {
881 *value = Smi::cast(this)->value();
882 return true;
883 }
884 if (IsHeapNumber()) {
885 double num = HeapNumber::cast(this)->value();
886 if (FastI2D(FastD2I(num)) == num) {
887 *value = FastD2I(num);
888 return true;
889 }
890 }
891 return false;
892}
893
894
895bool Object::ToUint32(uint32_t* value) {
896 if (IsSmi()) {
897 int num = Smi::cast(this)->value();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000898 if (num < 0) return false;
899 *value = static_cast<uint32_t>(num);
900 return true;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000901 }
902 if (IsHeapNumber()) {
903 double num = HeapNumber::cast(this)->value();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000904 if (num < 0) return false;
905 uint32_t uint_value = FastD2UI(num);
906 if (FastUI2D(uint_value) == num) {
907 *value = uint_value;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000908 return true;
909 }
910 }
911 return false;
912}
913
914
915bool FunctionTemplateInfo::IsTemplateFor(Object* object) {
916 if (!object->IsHeapObject()) return false;
917 return IsTemplateFor(HeapObject::cast(object)->map());
918}
919
920
921bool FunctionTemplateInfo::IsTemplateFor(Map* map) {
922 // There is a constraint on the object; check.
923 if (!map->IsJSObjectMap()) return false;
924 // Fetch the constructor function of the object.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000925 Object* cons_obj = map->GetConstructor();
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000926 if (!cons_obj->IsJSFunction()) return false;
927 JSFunction* fun = JSFunction::cast(cons_obj);
928 // Iterate through the chain of inheriting function templates to
929 // see if the required one occurs.
930 for (Object* type = fun->shared()->function_data();
931 type->IsFunctionTemplateInfo();
932 type = FunctionTemplateInfo::cast(type)->parent_template()) {
933 if (type == this) return true;
934 }
935 // Didn't find the required type in the inheritance chain.
936 return false;
937}
938
939
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000940// TODO(dcarney): CallOptimization duplicates this logic, merge.
941Object* FunctionTemplateInfo::GetCompatibleReceiver(Isolate* isolate,
942 Object* receiver) {
943 // API calls are only supported with JSObject receivers.
944 if (!receiver->IsJSObject()) return isolate->heap()->null_value();
945 Object* recv_type = this->signature();
946 // No signature, return holder.
947 if (recv_type->IsUndefined()) return receiver;
948 FunctionTemplateInfo* signature = FunctionTemplateInfo::cast(recv_type);
949 // Check the receiver.
Ben Murdoch097c5b22016-05-18 11:27:45 +0100950 for (PrototypeIterator iter(isolate, JSObject::cast(receiver),
951 PrototypeIterator::START_AT_RECEIVER,
952 PrototypeIterator::END_AT_NON_HIDDEN);
953 !iter.IsAtEnd(); iter.Advance()) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000954 if (signature->IsTemplateFor(iter.GetCurrent())) return iter.GetCurrent();
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000955 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000956 return isolate->heap()->null_value();
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000957}
958
959
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000960// static
961MaybeHandle<JSObject> JSObject::New(Handle<JSFunction> constructor,
962 Handle<JSReceiver> new_target,
963 Handle<AllocationSite> site) {
964 // If called through new, new.target can be:
965 // - a subclass of constructor,
966 // - a proxy wrapper around constructor, or
967 // - the constructor itself.
968 // If called through Reflect.construct, it's guaranteed to be a constructor.
969 Isolate* const isolate = constructor->GetIsolate();
970 DCHECK(constructor->IsConstructor());
971 DCHECK(new_target->IsConstructor());
972 DCHECK(!constructor->has_initial_map() ||
973 constructor->initial_map()->instance_type() != JS_FUNCTION_TYPE);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000974
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000975 Handle<Map> initial_map;
976 ASSIGN_RETURN_ON_EXCEPTION(
977 isolate, initial_map,
978 JSFunction::GetDerivedMap(isolate, constructor, new_target), JSObject);
979 Handle<JSObject> result =
980 isolate->factory()->NewJSObjectFromMap(initial_map, NOT_TENURED, site);
981 isolate->counters()->constructed_objects()->Increment();
982 isolate->counters()->constructed_objects_runtime()->Increment();
983 return result;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000984}
985
986
987Handle<FixedArray> JSObject::EnsureWritableFastElements(
988 Handle<JSObject> object) {
Ben Murdoch097c5b22016-05-18 11:27:45 +0100989 DCHECK(object->HasFastSmiOrObjectElements() ||
990 object->HasFastStringWrapperElements());
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000991 Isolate* isolate = object->GetIsolate();
992 Handle<FixedArray> elems(FixedArray::cast(object->elements()), isolate);
993 if (elems->map() != isolate->heap()->fixed_cow_array_map()) return elems;
994 Handle<FixedArray> writable_elems = isolate->factory()->CopyFixedArrayWithMap(
995 elems, isolate->factory()->fixed_array_map());
996 object->set_elements(*writable_elems);
997 isolate->counters()->cow_arrays_converted()->Increment();
998 return writable_elems;
999}
1000
1001
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001002// ES6 9.5.1
1003// static
1004MaybeHandle<Object> JSProxy::GetPrototype(Handle<JSProxy> proxy) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001005 Isolate* isolate = proxy->GetIsolate();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001006 Handle<String> trap_name = isolate->factory()->getPrototypeOf_string();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001007
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001008 STACK_CHECK(MaybeHandle<Object>());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001009
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001010 // 1. Let handler be the value of the [[ProxyHandler]] internal slot.
1011 // 2. If handler is null, throw a TypeError exception.
1012 // 3. Assert: Type(handler) is Object.
1013 // 4. Let target be the value of the [[ProxyTarget]] internal slot.
1014 if (proxy->IsRevoked()) {
1015 THROW_NEW_ERROR(isolate,
1016 NewTypeError(MessageTemplate::kProxyRevoked, trap_name),
1017 Object);
1018 }
1019 Handle<JSReceiver> target(proxy->target(), isolate);
1020 Handle<JSReceiver> handler(JSReceiver::cast(proxy->handler()), isolate);
1021
1022 // 5. Let trap be ? GetMethod(handler, "getPrototypeOf").
1023 Handle<Object> trap;
1024 ASSIGN_RETURN_ON_EXCEPTION(isolate, trap, GetMethod(handler, trap_name),
1025 Object);
1026 // 6. If trap is undefined, then return target.[[GetPrototypeOf]]().
1027 if (trap->IsUndefined()) {
Ben Murdoch097c5b22016-05-18 11:27:45 +01001028 return JSReceiver::GetPrototype(isolate, target);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001029 }
1030 // 7. Let handlerProto be ? Call(trap, handler, «target»).
1031 Handle<Object> argv[] = {target};
1032 Handle<Object> handler_proto;
1033 ASSIGN_RETURN_ON_EXCEPTION(
1034 isolate, handler_proto,
1035 Execution::Call(isolate, trap, handler, arraysize(argv), argv), Object);
1036 // 8. If Type(handlerProto) is neither Object nor Null, throw a TypeError.
1037 if (!(handler_proto->IsJSReceiver() || handler_proto->IsNull())) {
1038 THROW_NEW_ERROR(isolate,
1039 NewTypeError(MessageTemplate::kProxyGetPrototypeOfInvalid),
1040 Object);
1041 }
1042 // 9. Let extensibleTarget be ? IsExtensible(target).
1043 Maybe<bool> is_extensible = JSReceiver::IsExtensible(target);
1044 MAYBE_RETURN_NULL(is_extensible);
1045 // 10. If extensibleTarget is true, return handlerProto.
1046 if (is_extensible.FromJust()) return handler_proto;
1047 // 11. Let targetProto be ? target.[[GetPrototypeOf]]().
1048 Handle<Object> target_proto;
1049 ASSIGN_RETURN_ON_EXCEPTION(isolate, target_proto,
Ben Murdoch097c5b22016-05-18 11:27:45 +01001050 JSReceiver::GetPrototype(isolate, target), Object);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001051 // 12. If SameValue(handlerProto, targetProto) is false, throw a TypeError.
1052 if (!handler_proto->SameValue(*target_proto)) {
1053 THROW_NEW_ERROR(
1054 isolate,
1055 NewTypeError(MessageTemplate::kProxyGetPrototypeOfNonExtensible),
1056 Object);
1057 }
1058 // 13. Return handlerProto.
1059 return handler_proto;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001060}
1061
Ben Murdoch097c5b22016-05-18 11:27:45 +01001062MaybeHandle<Object> Object::GetPropertyWithAccessor(LookupIterator* it) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001063 Isolate* isolate = it->isolate();
1064 Handle<Object> structure = it->GetAccessors();
1065 Handle<Object> receiver = it->GetReceiver();
1066
1067 // We should never get here to initialize a const with the hole value since a
1068 // const declaration would conflict with the getter.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001069 DCHECK(!structure->IsForeign());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001070
1071 // API style callbacks.
Steve Blocka7e24c12009-10-30 11:49:00 +00001072 if (structure->IsAccessorInfo()) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001073 Handle<JSObject> holder = it->GetHolder<JSObject>();
1074 Handle<Name> name = it->GetName();
Ben Murdoch097c5b22016-05-18 11:27:45 +01001075 Handle<AccessorInfo> info = Handle<AccessorInfo>::cast(structure);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001076 if (!info->IsCompatibleReceiver(*receiver)) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001077 THROW_NEW_ERROR(isolate,
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001078 NewTypeError(MessageTemplate::kIncompatibleMethodReceiver,
1079 name, receiver),
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001080 Object);
Steve Blocka7e24c12009-10-30 11:49:00 +00001081 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001082
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001083 v8::AccessorNameGetterCallback call_fun =
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001084 v8::ToCData<v8::AccessorNameGetterCallback>(info->getter());
1085 if (call_fun == nullptr) return isolate->factory()->undefined_value();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001086
1087 LOG(isolate, ApiNamedPropertyAccess("load", *holder, *name));
Ben Murdoch097c5b22016-05-18 11:27:45 +01001088 PropertyCallbackArguments args(isolate, info->data(), *receiver, *holder,
1089 Object::DONT_THROW);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001090 v8::Local<v8::Value> result = args.Call(call_fun, v8::Utils::ToLocal(name));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001091 RETURN_EXCEPTION_IF_SCHEDULED_EXCEPTION(isolate, Object);
Steve Block44f0eee2011-05-26 01:26:41 +01001092 if (result.IsEmpty()) {
Ben Murdoch097c5b22016-05-18 11:27:45 +01001093 return ReadAbsentProperty(isolate, receiver, name);
Steve Block44f0eee2011-05-26 01:26:41 +01001094 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001095 Handle<Object> return_value = v8::Utils::OpenHandle(*result);
1096 return_value->VerifyApiCallResultType();
1097 // Rebox handle before return.
1098 return handle(*return_value, isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00001099 }
1100
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001101 // Regular accessor.
1102 Handle<Object> getter(AccessorPair::cast(*structure)->getter(), isolate);
Ben Murdoch097c5b22016-05-18 11:27:45 +01001103 if (getter->IsFunctionTemplateInfo()) {
1104 auto result = Builtins::InvokeApiFunction(
1105 Handle<FunctionTemplateInfo>::cast(getter), receiver, 0, nullptr);
1106 if (isolate->has_pending_exception()) {
1107 return MaybeHandle<Object>();
1108 }
1109 Handle<Object> return_value;
1110 if (result.ToHandle(&return_value)) {
1111 return_value->VerifyApiCallResultType();
1112 return handle(*return_value, isolate);
1113 }
1114 } else if (getter->IsCallable()) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001115 // TODO(rossberg): nicer would be to cast to some JSCallable here...
1116 return Object::GetPropertyWithDefinedGetter(
1117 receiver, Handle<JSReceiver>::cast(getter));
1118 }
1119 // Getter is not a function.
Ben Murdoch097c5b22016-05-18 11:27:45 +01001120 return ReadAbsentProperty(isolate, receiver, it->GetName());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001121}
1122
1123
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001124bool AccessorInfo::IsCompatibleReceiverMap(Isolate* isolate,
1125 Handle<AccessorInfo> info,
1126 Handle<Map> map) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001127 if (!info->HasExpectedReceiverType()) return true;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001128 if (!map->IsJSObjectMap()) return false;
1129 return FunctionTemplateInfo::cast(info->expected_receiver_type())
1130 ->IsTemplateFor(*map);
1131}
1132
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001133Maybe<bool> Object::SetPropertyWithAccessor(LookupIterator* it,
1134 Handle<Object> value,
1135 ShouldThrow should_throw) {
1136 Isolate* isolate = it->isolate();
1137 Handle<Object> structure = it->GetAccessors();
1138 Handle<Object> receiver = it->GetReceiver();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001139
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001140 // We should never get here to initialize a const with the hole value since a
1141 // const declaration would conflict with the setter.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001142 DCHECK(!structure->IsForeign());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001143
1144 // API style callbacks.
Ben Murdoch097c5b22016-05-18 11:27:45 +01001145 if (structure->IsAccessorInfo()) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001146 Handle<JSObject> holder = it->GetHolder<JSObject>();
1147 Handle<Name> name = it->GetName();
Ben Murdoch097c5b22016-05-18 11:27:45 +01001148 Handle<AccessorInfo> info = Handle<AccessorInfo>::cast(structure);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001149 if (!info->IsCompatibleReceiver(*receiver)) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001150 isolate->Throw(*isolate->factory()->NewTypeError(
1151 MessageTemplate::kIncompatibleMethodReceiver, name, receiver));
1152 return Nothing<bool>();
Steve Blocka7e24c12009-10-30 11:49:00 +00001153 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001154
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001155 v8::AccessorNameSetterCallback call_fun =
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001156 v8::ToCData<v8::AccessorNameSetterCallback>(info->setter());
Ben Murdoch097c5b22016-05-18 11:27:45 +01001157 // TODO(verwaest): We should not get here anymore once all AccessorInfos are
1158 // marked as special_data_property. They cannot both be writable and not
1159 // have a setter.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001160 if (call_fun == nullptr) return Just(true);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001161
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001162 LOG(isolate, ApiNamedPropertyAccess("store", *holder, *name));
Ben Murdoch097c5b22016-05-18 11:27:45 +01001163 PropertyCallbackArguments args(isolate, info->data(), *receiver, *holder,
1164 should_throw);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001165 args.Call(call_fun, v8::Utils::ToLocal(name), v8::Utils::ToLocal(value));
1166 RETURN_VALUE_IF_SCHEDULED_EXCEPTION(isolate, Nothing<bool>());
1167 return Just(true);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001168 }
1169
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001170 // Regular accessor.
1171 Handle<Object> setter(AccessorPair::cast(*structure)->setter(), isolate);
Ben Murdoch097c5b22016-05-18 11:27:45 +01001172 if (setter->IsFunctionTemplateInfo()) {
1173 Handle<Object> argv[] = {value};
1174 auto result =
1175 Builtins::InvokeApiFunction(Handle<FunctionTemplateInfo>::cast(setter),
1176 receiver, arraysize(argv), argv);
1177 if (isolate->has_pending_exception()) {
1178 return Nothing<bool>();
1179 }
1180 return Just(true);
1181 } else if (setter->IsCallable()) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001182 // TODO(rossberg): nicer would be to cast to some JSCallable here...
1183 return SetPropertyWithDefinedSetter(
1184 receiver, Handle<JSReceiver>::cast(setter), value, should_throw);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001185 }
1186
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001187 RETURN_FAILURE(isolate, should_throw,
1188 NewTypeError(MessageTemplate::kNoSetterInCallback,
1189 it->GetName(), it->GetHolder<JSObject>()));
Steve Blocka7e24c12009-10-30 11:49:00 +00001190}
1191
1192
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001193MaybeHandle<Object> Object::GetPropertyWithDefinedGetter(
1194 Handle<Object> receiver,
1195 Handle<JSReceiver> getter) {
1196 Isolate* isolate = getter->GetIsolate();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001197
1198 // Platforms with simulators like arm/arm64 expose a funny issue. If the
1199 // simulator has a separate JS stack pointer from the C++ stack pointer, it
1200 // can miss C++ stack overflows in the stack guard at the start of JavaScript
1201 // functions. It would be very expensive to check the C++ stack pointer at
1202 // that location. The best solution seems to be to break the impasse by
1203 // adding checks at possible recursion points. What's more, we don't put
1204 // this stack check behind the USE_SIMULATOR define in order to keep
1205 // behavior the same between hardware and simulators.
1206 StackLimitCheck check(isolate);
1207 if (check.JsHasOverflowed()) {
1208 isolate->StackOverflow();
1209 return MaybeHandle<Object>();
Steve Blocka7e24c12009-10-30 11:49:00 +00001210 }
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001211
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001212 return Execution::Call(isolate, getter, receiver, 0, NULL);
Steve Blocka7e24c12009-10-30 11:49:00 +00001213}
1214
1215
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001216Maybe<bool> Object::SetPropertyWithDefinedSetter(Handle<Object> receiver,
1217 Handle<JSReceiver> setter,
1218 Handle<Object> value,
1219 ShouldThrow should_throw) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001220 Isolate* isolate = setter->GetIsolate();
1221
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001222 Handle<Object> argv[] = { value };
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001223 RETURN_ON_EXCEPTION_VALUE(isolate, Execution::Call(isolate, setter, receiver,
1224 arraysize(argv), argv),
1225 Nothing<bool>());
1226 return Just(true);
Steve Blocka7e24c12009-10-30 11:49:00 +00001227}
1228
1229
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001230// static
1231bool Object::IsErrorObject(Isolate* isolate, Handle<Object> object) {
1232 if (!object->IsJSObject()) return false;
1233 // Use stack_trace_symbol as proxy for [[ErrorData]].
1234 Handle<Name> symbol = isolate->factory()->stack_trace_symbol();
1235 Maybe<bool> has_stack_trace =
1236 JSReceiver::HasOwnProperty(Handle<JSReceiver>::cast(object), symbol);
1237 DCHECK(!has_stack_trace.IsNothing());
1238 return has_stack_trace.FromJust();
1239}
1240
1241
1242// static
1243bool JSObject::AllCanRead(LookupIterator* it) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001244 // Skip current iteration, it's in state ACCESS_CHECK or INTERCEPTOR, both of
1245 // which have already been checked.
1246 DCHECK(it->state() == LookupIterator::ACCESS_CHECK ||
1247 it->state() == LookupIterator::INTERCEPTOR);
1248 for (it->Next(); it->IsFound(); it->Next()) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001249 if (it->state() == LookupIterator::ACCESSOR) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001250 auto accessors = it->GetAccessors();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001251 if (accessors->IsAccessorInfo()) {
1252 if (AccessorInfo::cast(*accessors)->all_can_read()) return true;
1253 }
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001254 } else if (it->state() == LookupIterator::INTERCEPTOR) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001255 if (it->GetInterceptor()->all_can_read()) return true;
1256 } else if (it->state() == LookupIterator::JSPROXY) {
1257 // Stop lookupiterating. And no, AllCanNotRead.
1258 return false;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001259 }
1260 }
1261 return false;
1262}
1263
1264
1265MaybeHandle<Object> JSObject::GetPropertyWithFailedAccessCheck(
1266 LookupIterator* it) {
1267 Handle<JSObject> checked = it->GetHolder<JSObject>();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001268 while (AllCanRead(it)) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001269 if (it->state() == LookupIterator::ACCESSOR) {
Ben Murdoch097c5b22016-05-18 11:27:45 +01001270 return GetPropertyWithAccessor(it);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001271 }
1272 DCHECK_EQ(LookupIterator::INTERCEPTOR, it->state());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001273 bool done;
1274 Handle<Object> result;
1275 ASSIGN_RETURN_ON_EXCEPTION(it->isolate(), result,
1276 GetPropertyWithInterceptor(it, &done), Object);
1277 if (done) return result;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001278 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001279
1280 // Cross-Origin [[Get]] of Well-Known Symbols does not throw, and returns
1281 // undefined.
1282 Handle<Name> name = it->GetName();
1283 if (name->IsSymbol() && Symbol::cast(*name)->is_well_known_symbol()) {
1284 return it->factory()->undefined_value();
1285 }
1286
1287 it->isolate()->ReportFailedAccessCheck(checked);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001288 RETURN_EXCEPTION_IF_SCHEDULED_EXCEPTION(it->isolate(), Object);
1289 return it->factory()->undefined_value();
1290}
1291
1292
1293Maybe<PropertyAttributes> JSObject::GetPropertyAttributesWithFailedAccessCheck(
1294 LookupIterator* it) {
1295 Handle<JSObject> checked = it->GetHolder<JSObject>();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001296 while (AllCanRead(it)) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001297 if (it->state() == LookupIterator::ACCESSOR) {
Ben Murdoch097c5b22016-05-18 11:27:45 +01001298 return Just(it->property_attributes());
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001299 }
1300 DCHECK_EQ(LookupIterator::INTERCEPTOR, it->state());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001301 auto result = GetPropertyAttributesWithInterceptor(it);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001302 if (it->isolate()->has_scheduled_exception()) break;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001303 if (result.IsJust() && result.FromJust() != ABSENT) return result;
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001304 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001305 it->isolate()->ReportFailedAccessCheck(checked);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001306 RETURN_VALUE_IF_SCHEDULED_EXCEPTION(it->isolate(),
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001307 Nothing<PropertyAttributes>());
1308 return Just(ABSENT);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001309}
1310
1311
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001312// static
1313bool JSObject::AllCanWrite(LookupIterator* it) {
1314 for (; it->IsFound() && it->state() != LookupIterator::JSPROXY; it->Next()) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001315 if (it->state() == LookupIterator::ACCESSOR) {
1316 Handle<Object> accessors = it->GetAccessors();
1317 if (accessors->IsAccessorInfo()) {
1318 if (AccessorInfo::cast(*accessors)->all_can_write()) return true;
1319 }
1320 }
1321 }
1322 return false;
1323}
1324
1325
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001326Maybe<bool> JSObject::SetPropertyWithFailedAccessCheck(
1327 LookupIterator* it, Handle<Object> value, ShouldThrow should_throw) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001328 Handle<JSObject> checked = it->GetHolder<JSObject>();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001329 if (AllCanWrite(it)) {
1330 return SetPropertyWithAccessor(it, value, should_throw);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001331 }
1332
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001333 it->isolate()->ReportFailedAccessCheck(checked);
1334 RETURN_VALUE_IF_SCHEDULED_EXCEPTION(it->isolate(), Nothing<bool>());
1335 return Just(true);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001336}
1337
1338
1339void JSObject::SetNormalizedProperty(Handle<JSObject> object,
1340 Handle<Name> name,
1341 Handle<Object> value,
1342 PropertyDetails details) {
1343 DCHECK(!object->HasFastProperties());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001344 if (!name->IsUniqueName()) {
1345 name = object->GetIsolate()->factory()->InternalizeString(
1346 Handle<String>::cast(name));
1347 }
1348
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001349 if (object->IsJSGlobalObject()) {
1350 Handle<GlobalDictionary> property_dictionary(object->global_dictionary());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001351
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001352 int entry = property_dictionary->FindEntry(name);
1353 if (entry == GlobalDictionary::kNotFound) {
1354 auto cell = object->GetIsolate()->factory()->NewPropertyCell();
1355 cell->set_value(*value);
1356 auto cell_type = value->IsUndefined() ? PropertyCellType::kUndefined
1357 : PropertyCellType::kConstant;
1358 details = details.set_cell_type(cell_type);
1359 value = cell;
1360 property_dictionary =
1361 GlobalDictionary::Add(property_dictionary, name, value, details);
1362 object->set_properties(*property_dictionary);
Steve Blocka7e24c12009-10-30 11:49:00 +00001363 } else {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001364 PropertyCell::UpdateCell(property_dictionary, entry, value, details);
1365 }
1366 } else {
1367 Handle<NameDictionary> property_dictionary(object->property_dictionary());
1368
1369 int entry = property_dictionary->FindEntry(name);
1370 if (entry == NameDictionary::kNotFound) {
1371 property_dictionary =
1372 NameDictionary::Add(property_dictionary, name, value, details);
1373 object->set_properties(*property_dictionary);
1374 } else {
1375 PropertyDetails original_details = property_dictionary->DetailsAt(entry);
1376 int enumeration_index = original_details.dictionary_index();
1377 DCHECK(enumeration_index > 0);
1378 details = details.set_index(enumeration_index);
1379 property_dictionary->SetEntry(entry, name, value, details);
Steve Blocka7e24c12009-10-30 11:49:00 +00001380 }
1381 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001382}
1383
Ben Murdoch097c5b22016-05-18 11:27:45 +01001384Maybe<bool> JSReceiver::HasInPrototypeChain(Isolate* isolate,
1385 Handle<JSReceiver> object,
1386 Handle<Object> proto) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001387 PrototypeIterator iter(isolate, object, PrototypeIterator::START_AT_RECEIVER);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001388 while (true) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001389 if (!iter.AdvanceFollowingProxies()) return Nothing<bool>();
1390 if (iter.IsAtEnd()) return Just(false);
Ben Murdoch097c5b22016-05-18 11:27:45 +01001391 if (PrototypeIterator::GetCurrent(iter).is_identical_to(proto)) {
1392 return Just(true);
1393 }
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001394 }
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001395}
1396
1397
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001398Map* Object::GetRootMap(Isolate* isolate) {
1399 DisallowHeapAllocation no_alloc;
Ben Murdoch8b112d22011-06-08 16:22:53 +01001400 if (IsSmi()) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001401 Context* native_context = isolate->context()->native_context();
1402 return native_context->number_function()->initial_map();
Ben Murdoch8b112d22011-06-08 16:22:53 +01001403 }
1404
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001405 // The object is either a number, a string, a symbol, a boolean, a SIMD value,
Ben Murdoch257744e2011-11-30 15:57:28 +00001406 // a real JS object, or a Harmony proxy.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001407 HeapObject* heap_object = HeapObject::cast(this);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001408 if (heap_object->IsJSReceiver()) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001409 return heap_object->map();
Ben Murdoch8b112d22011-06-08 16:22:53 +01001410 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001411 int constructor_function_index =
1412 heap_object->map()->GetConstructorFunctionIndex();
1413 if (constructor_function_index != Map::kNoConstructorFunctionIndex) {
1414 Context* native_context = isolate->context()->native_context();
1415 JSFunction* constructor_function =
1416 JSFunction::cast(native_context->get(constructor_function_index));
1417 return constructor_function->initial_map();
Steve Blocka7e24c12009-10-30 11:49:00 +00001418 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001419 return isolate->heap()->null_value()->map();
Steve Blocka7e24c12009-10-30 11:49:00 +00001420}
1421
1422
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001423Object* Object::GetHash() {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001424 Object* hash = GetSimpleHash();
1425 if (hash->IsSmi()) return hash;
1426
1427 DCHECK(IsJSReceiver());
1428 return JSReceiver::cast(this)->GetIdentityHash();
1429}
1430
1431
1432Object* Object::GetSimpleHash() {
1433 // The object is either a Smi, a HeapNumber, a name, an odd-ball,
1434 // a SIMD value type, a real JS object, or a Harmony proxy.
1435 if (IsSmi()) {
1436 uint32_t hash = ComputeIntegerHash(Smi::cast(this)->value(), kZeroHashSeed);
1437 return Smi::FromInt(hash & Smi::kMaxValue);
1438 }
1439 if (IsHeapNumber()) {
1440 double num = HeapNumber::cast(this)->value();
1441 if (std::isnan(num)) return Smi::FromInt(Smi::kMaxValue);
1442 if (i::IsMinusZero(num)) num = 0;
1443 if (IsSmiDouble(num)) {
1444 return Smi::FromInt(FastD2I(num))->GetHash();
1445 }
1446 uint32_t hash = ComputeLongHash(double_to_uint64(num));
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001447 return Smi::FromInt(hash & Smi::kMaxValue);
1448 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001449 if (IsName()) {
1450 uint32_t hash = Name::cast(this)->Hash();
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001451 return Smi::FromInt(hash);
1452 }
1453 if (IsOddball()) {
1454 uint32_t hash = Oddball::cast(this)->to_string()->Hash();
1455 return Smi::FromInt(hash);
1456 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001457 if (IsSimd128Value()) {
1458 uint32_t hash = Simd128Value::cast(this)->Hash();
1459 return Smi::FromInt(hash & Smi::kMaxValue);
1460 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001461 DCHECK(IsJSReceiver());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001462 JSReceiver* receiver = JSReceiver::cast(this);
1463 return receiver->GetHeap()->undefined_value();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001464}
1465
1466
1467Handle<Smi> Object::GetOrCreateHash(Isolate* isolate, Handle<Object> object) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001468 Handle<Object> hash(object->GetSimpleHash(), isolate);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001469 if (hash->IsSmi()) return Handle<Smi>::cast(hash);
1470
1471 DCHECK(object->IsJSReceiver());
1472 return JSReceiver::GetOrCreateIdentityHash(Handle<JSReceiver>::cast(object));
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001473}
1474
1475
1476bool Object::SameValue(Object* other) {
1477 if (other == this) return true;
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001478
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001479 // The object is either a number, a name, an odd-ball,
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001480 // a real JS object, or a Harmony proxy.
1481 if (IsNumber() && other->IsNumber()) {
1482 double this_value = Number();
1483 double other_value = other->Number();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001484 // SameValue(NaN, NaN) is true.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001485 if (this_value != other_value) {
1486 return std::isnan(this_value) && std::isnan(other_value);
1487 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001488 // SameValue(0.0, -0.0) is false.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001489 return (std::signbit(this_value) == std::signbit(other_value));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001490 }
1491 if (IsString() && other->IsString()) {
1492 return String::cast(this)->Equals(String::cast(other));
1493 }
Ben Murdoch097c5b22016-05-18 11:27:45 +01001494 if (IsFloat32x4() && other->IsFloat32x4()) {
1495 Float32x4* a = Float32x4::cast(this);
1496 Float32x4* b = Float32x4::cast(other);
1497 for (int i = 0; i < 4; i++) {
1498 float x = a->get_lane(i);
1499 float y = b->get_lane(i);
1500 // Implements the ES5 SameValue operation for floating point types.
1501 // http://www.ecma-international.org/ecma-262/6.0/#sec-samevalue
1502 if (x != y && !(std::isnan(x) && std::isnan(y))) return false;
1503 if (std::signbit(x) != std::signbit(y)) return false;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001504 }
Ben Murdoch097c5b22016-05-18 11:27:45 +01001505 return true;
1506 } else if (IsSimd128Value() && other->IsSimd128Value()) {
1507 Simd128Value* a = Simd128Value::cast(this);
1508 Simd128Value* b = Simd128Value::cast(other);
1509 return a->map() == b->map() && a->BitwiseEquals(b);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001510 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001511 return false;
1512}
1513
1514
1515bool Object::SameValueZero(Object* other) {
1516 if (other == this) return true;
1517
1518 // The object is either a number, a name, an odd-ball,
1519 // a real JS object, or a Harmony proxy.
1520 if (IsNumber() && other->IsNumber()) {
1521 double this_value = Number();
1522 double other_value = other->Number();
1523 // +0 == -0 is true
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001524 return this_value == other_value ||
1525 (std::isnan(this_value) && std::isnan(other_value));
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001526 }
1527 if (IsString() && other->IsString()) {
1528 return String::cast(this)->Equals(String::cast(other));
1529 }
Ben Murdoch097c5b22016-05-18 11:27:45 +01001530 if (IsFloat32x4() && other->IsFloat32x4()) {
1531 Float32x4* a = Float32x4::cast(this);
1532 Float32x4* b = Float32x4::cast(other);
1533 for (int i = 0; i < 4; i++) {
1534 float x = a->get_lane(i);
1535 float y = b->get_lane(i);
1536 // Implements the ES6 SameValueZero operation for floating point types.
1537 // http://www.ecma-international.org/ecma-262/6.0/#sec-samevaluezero
1538 if (x != y && !(std::isnan(x) && std::isnan(y))) return false;
1539 // SameValueZero doesn't distinguish between 0 and -0.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001540 }
Ben Murdoch097c5b22016-05-18 11:27:45 +01001541 return true;
1542 } else if (IsSimd128Value() && other->IsSimd128Value()) {
1543 Simd128Value* a = Simd128Value::cast(this);
1544 Simd128Value* b = Simd128Value::cast(other);
1545 return a->map() == b->map() && a->BitwiseEquals(b);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001546 }
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001547 return false;
1548}
1549
1550
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001551MaybeHandle<Object> Object::ArraySpeciesConstructor(
1552 Isolate* isolate, Handle<Object> original_array) {
1553 Handle<Context> native_context = isolate->native_context();
Ben Murdoch097c5b22016-05-18 11:27:45 +01001554 Handle<Object> default_species = isolate->array_function();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001555 if (!FLAG_harmony_species) {
Ben Murdoch097c5b22016-05-18 11:27:45 +01001556 return default_species;
1557 }
1558 if (original_array->IsJSArray() &&
1559 Handle<JSReceiver>::cast(original_array)->map()->new_target_is_base() &&
1560 isolate->IsArraySpeciesLookupChainIntact()) {
1561 return default_species;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001562 }
1563 Handle<Object> constructor = isolate->factory()->undefined_value();
1564 Maybe<bool> is_array = Object::IsArray(original_array);
1565 MAYBE_RETURN_NULL(is_array);
1566 if (is_array.FromJust()) {
1567 ASSIGN_RETURN_ON_EXCEPTION(
1568 isolate, constructor,
1569 Object::GetProperty(original_array,
1570 isolate->factory()->constructor_string()),
1571 Object);
1572 if (constructor->IsConstructor()) {
1573 Handle<Context> constructor_context;
1574 ASSIGN_RETURN_ON_EXCEPTION(
1575 isolate, constructor_context,
1576 JSReceiver::GetFunctionRealm(Handle<JSReceiver>::cast(constructor)),
1577 Object);
1578 if (*constructor_context != *native_context &&
1579 *constructor == constructor_context->array_function()) {
1580 constructor = isolate->factory()->undefined_value();
1581 }
1582 }
1583 if (constructor->IsJSReceiver()) {
1584 ASSIGN_RETURN_ON_EXCEPTION(
1585 isolate, constructor,
1586 Object::GetProperty(constructor,
1587 isolate->factory()->species_symbol()),
1588 Object);
1589 if (constructor->IsNull()) {
1590 constructor = isolate->factory()->undefined_value();
1591 }
1592 }
1593 }
1594 if (constructor->IsUndefined()) {
Ben Murdoch097c5b22016-05-18 11:27:45 +01001595 return default_species;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001596 } else {
1597 if (!constructor->IsConstructor()) {
1598 THROW_NEW_ERROR(isolate,
1599 NewTypeError(MessageTemplate::kSpeciesNotConstructor),
1600 Object);
1601 }
1602 return constructor;
1603 }
1604}
1605
1606
Ben Murdochb0fe1622011-05-05 13:52:32 +01001607void Object::ShortPrint(FILE* out) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001608 OFStream os(out);
1609 os << Brief(this);
Steve Blocka7e24c12009-10-30 11:49:00 +00001610}
1611
1612
1613void Object::ShortPrint(StringStream* accumulator) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001614 std::ostringstream os;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001615 os << Brief(this);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001616 accumulator->Add(os.str().c_str());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001617}
1618
1619
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001620void Object::ShortPrint(std::ostream& os) { os << Brief(this); }
1621
1622
1623std::ostream& operator<<(std::ostream& os, const Brief& v) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001624 if (v.value->IsSmi()) {
1625 Smi::cast(v.value)->SmiPrint(os);
Steve Blocka7e24c12009-10-30 11:49:00 +00001626 } else {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001627 // TODO(svenpanne) Const-correct HeapObjectShortPrint!
1628 HeapObject* obj = const_cast<HeapObject*>(HeapObject::cast(v.value));
1629 obj->HeapObjectShortPrint(os);
Steve Blocka7e24c12009-10-30 11:49:00 +00001630 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001631 return os;
Steve Blocka7e24c12009-10-30 11:49:00 +00001632}
1633
1634
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001635void Smi::SmiPrint(std::ostream& os) const { // NOLINT
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001636 os << value();
Steve Blocka7e24c12009-10-30 11:49:00 +00001637}
1638
1639
Steve Blocka7e24c12009-10-30 11:49:00 +00001640// Should a word be prefixed by 'a' or 'an' in order to read naturally in
1641// English? Returns false for non-ASCII or words that don't start with
1642// a capital letter. The a/an rule follows pronunciation in English.
1643// We don't use the BBC's overcorrect "an historic occasion" though if
1644// you speak a dialect you may well say "an 'istoric occasion".
1645static bool AnWord(String* str) {
1646 if (str->length() == 0) return false; // A nothing.
1647 int c0 = str->Get(0);
1648 int c1 = str->length() > 1 ? str->Get(1) : 0;
1649 if (c0 == 'U') {
1650 if (c1 > 'Z') {
1651 return true; // An Umpire, but a UTF8String, a U.
1652 }
1653 } else if (c0 == 'A' || c0 == 'E' || c0 == 'I' || c0 == 'O') {
1654 return true; // An Ape, an ABCBook.
1655 } else if ((c1 == 0 || (c1 >= 'A' && c1 <= 'Z')) &&
1656 (c0 == 'F' || c0 == 'H' || c0 == 'M' || c0 == 'N' || c0 == 'R' ||
1657 c0 == 'S' || c0 == 'X')) {
1658 return true; // An MP3File, an M.
1659 }
1660 return false;
1661}
1662
1663
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001664Handle<String> String::SlowFlatten(Handle<ConsString> cons,
1665 PretenureFlag pretenure) {
1666 DCHECK(AllowHeapAllocation::IsAllowed());
1667 DCHECK(cons->second()->length() != 0);
1668 Isolate* isolate = cons->GetIsolate();
1669 int length = cons->length();
1670 PretenureFlag tenure = isolate->heap()->InNewSpace(*cons) ? pretenure
1671 : TENURED;
1672 Handle<SeqString> result;
1673 if (cons->IsOneByteRepresentation()) {
1674 Handle<SeqOneByteString> flat = isolate->factory()->NewRawOneByteString(
1675 length, tenure).ToHandleChecked();
1676 DisallowHeapAllocation no_gc;
1677 WriteToFlat(*cons, flat->GetChars(), 0, length);
1678 result = flat;
1679 } else {
1680 Handle<SeqTwoByteString> flat = isolate->factory()->NewRawTwoByteString(
1681 length, tenure).ToHandleChecked();
1682 DisallowHeapAllocation no_gc;
1683 WriteToFlat(*cons, flat->GetChars(), 0, length);
1684 result = flat;
Steve Blocka7e24c12009-10-30 11:49:00 +00001685 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001686 cons->set_first(*result);
1687 cons->set_second(isolate->heap()->empty_string());
1688 DCHECK(result->IsFlat());
1689 return result;
Steve Blocka7e24c12009-10-30 11:49:00 +00001690}
1691
1692
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001693
Steve Blocka7e24c12009-10-30 11:49:00 +00001694bool String::MakeExternal(v8::String::ExternalStringResource* resource) {
Steve Block8defd9f2010-07-08 12:39:36 +01001695 // Externalizing twice leaks the external resource, so it's
Kristian Monsen9dcf7e22010-06-28 14:14:28 +01001696 // prohibited by the API.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001697 DCHECK(!this->IsExternalString());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001698 DCHECK(!resource->IsCompressible());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001699#ifdef ENABLE_SLOW_DCHECKS
Steve Block3ce2e202009-11-05 08:53:23 +00001700 if (FLAG_enable_slow_asserts) {
Steve Blocka7e24c12009-10-30 11:49:00 +00001701 // Assert that the resource and the string are equivalent.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001702 DCHECK(static_cast<size_t>(this->length()) == resource->length());
Kristian Monsen25f61362010-05-21 11:50:48 +01001703 ScopedVector<uc16> smart_chars(this->length());
1704 String::WriteToFlat(this, smart_chars.start(), 0, this->length());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001705 DCHECK(memcmp(smart_chars.start(),
Steve Blocka7e24c12009-10-30 11:49:00 +00001706 resource->data(),
Kristian Monsen25f61362010-05-21 11:50:48 +01001707 resource->length() * sizeof(smart_chars[0])) == 0);
Steve Blocka7e24c12009-10-30 11:49:00 +00001708 }
1709#endif // DEBUG
Steve Blocka7e24c12009-10-30 11:49:00 +00001710 int size = this->Size(); // Byte size of the original string.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001711 // Abort if size does not allow in-place conversion.
1712 if (size < ExternalString::kShortSize) return false;
1713 Heap* heap = GetHeap();
1714 bool is_one_byte = this->IsOneByteRepresentation();
1715 bool is_internalized = this->IsInternalizedString();
Steve Blocka7e24c12009-10-30 11:49:00 +00001716
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001717 // Morph the string to an external string by replacing the map and
1718 // reinitializing the fields. This won't work if the space the existing
1719 // string occupies is too small for a regular external string.
1720 // Instead, we resort to a short external string instead, omitting
1721 // the field caching the address of the backing store. When we encounter
1722 // short external strings in generated code, we need to bailout to runtime.
1723 Map* new_map;
1724 if (size < ExternalString::kSize) {
1725 new_map = is_internalized
1726 ? (is_one_byte
1727 ? heap->short_external_internalized_string_with_one_byte_data_map()
1728 : heap->short_external_internalized_string_map())
1729 : (is_one_byte ? heap->short_external_string_with_one_byte_data_map()
1730 : heap->short_external_string_map());
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001731 } else {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001732 new_map = is_internalized
1733 ? (is_one_byte
1734 ? heap->external_internalized_string_with_one_byte_data_map()
1735 : heap->external_internalized_string_map())
1736 : (is_one_byte ? heap->external_string_with_one_byte_data_map()
1737 : heap->external_string_map());
Ben Murdoch85b71792012-04-11 18:30:58 +01001738 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001739
1740 // Byte size of the external String object.
1741 int new_size = this->SizeFromMap(new_map);
1742 heap->CreateFillerObjectAt(this->address() + new_size, size - new_size);
1743
1744 // We are storing the new map using release store after creating a filler for
1745 // the left-over space to avoid races with the sweeper thread.
1746 this->synchronized_set_map(new_map);
1747
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001748 ExternalTwoByteString* self = ExternalTwoByteString::cast(this);
1749 self->set_resource(resource);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001750 if (is_internalized) self->Hash(); // Force regeneration of the hash value.
Steve Blocka7e24c12009-10-30 11:49:00 +00001751
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001752 heap->AdjustLiveBytes(this, new_size - size, Heap::CONCURRENT_TO_SWEEPER);
Steve Blocka7e24c12009-10-30 11:49:00 +00001753 return true;
1754}
1755
1756
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001757bool String::MakeExternal(v8::String::ExternalOneByteStringResource* resource) {
1758 // Externalizing twice leaks the external resource, so it's
1759 // prohibited by the API.
1760 DCHECK(!this->IsExternalString());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001761 DCHECK(!resource->IsCompressible());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001762#ifdef ENABLE_SLOW_DCHECKS
Steve Block3ce2e202009-11-05 08:53:23 +00001763 if (FLAG_enable_slow_asserts) {
Steve Blocka7e24c12009-10-30 11:49:00 +00001764 // Assert that the resource and the string are equivalent.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001765 DCHECK(static_cast<size_t>(this->length()) == resource->length());
1766 if (this->IsTwoByteRepresentation()) {
1767 ScopedVector<uint16_t> smart_chars(this->length());
1768 String::WriteToFlat(this, smart_chars.start(), 0, this->length());
1769 DCHECK(String::IsOneByte(smart_chars.start(), this->length()));
1770 }
Kristian Monsen25f61362010-05-21 11:50:48 +01001771 ScopedVector<char> smart_chars(this->length());
1772 String::WriteToFlat(this, smart_chars.start(), 0, this->length());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001773 DCHECK(memcmp(smart_chars.start(),
Steve Blocka7e24c12009-10-30 11:49:00 +00001774 resource->data(),
Kristian Monsen25f61362010-05-21 11:50:48 +01001775 resource->length() * sizeof(smart_chars[0])) == 0);
Steve Blocka7e24c12009-10-30 11:49:00 +00001776 }
1777#endif // DEBUG
Steve Blocka7e24c12009-10-30 11:49:00 +00001778 int size = this->Size(); // Byte size of the original string.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001779 // Abort if size does not allow in-place conversion.
1780 if (size < ExternalString::kShortSize) return false;
1781 Heap* heap = GetHeap();
1782 bool is_internalized = this->IsInternalizedString();
Steve Blocka7e24c12009-10-30 11:49:00 +00001783
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001784 // Morph the string to an external string by replacing the map and
1785 // reinitializing the fields. This won't work if the space the existing
1786 // string occupies is too small for a regular external string.
1787 // Instead, we resort to a short external string instead, omitting
1788 // the field caching the address of the backing store. When we encounter
1789 // short external strings in generated code, we need to bailout to runtime.
1790 Map* new_map;
1791 if (size < ExternalString::kSize) {
1792 new_map = is_internalized
1793 ? heap->short_external_one_byte_internalized_string_map()
1794 : heap->short_external_one_byte_string_map();
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001795 } else {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001796 new_map = is_internalized
1797 ? heap->external_one_byte_internalized_string_map()
1798 : heap->external_one_byte_string_map();
Ben Murdoch85b71792012-04-11 18:30:58 +01001799 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001800
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001801 // Byte size of the external String object.
1802 int new_size = this->SizeFromMap(new_map);
Steve Block44f0eee2011-05-26 01:26:41 +01001803 heap->CreateFillerObjectAt(this->address() + new_size, size - new_size);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001804
1805 // We are storing the new map using release store after creating a filler for
1806 // the left-over space to avoid races with the sweeper thread.
1807 this->synchronized_set_map(new_map);
1808
1809 ExternalOneByteString* self = ExternalOneByteString::cast(this);
1810 self->set_resource(resource);
1811 if (is_internalized) self->Hash(); // Force regeneration of the hash value.
1812
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001813 heap->AdjustLiveBytes(this, new_size - size, Heap::CONCURRENT_TO_SWEEPER);
Steve Blocka7e24c12009-10-30 11:49:00 +00001814 return true;
1815}
1816
1817
1818void String::StringShortPrint(StringStream* accumulator) {
1819 int len = length();
Steve Blockd0582a62009-12-15 09:54:21 +00001820 if (len > kMaxShortPrintLength) {
Steve Blocka7e24c12009-10-30 11:49:00 +00001821 accumulator->Add("<Very long string[%u]>", len);
1822 return;
1823 }
1824
1825 if (!LooksValid()) {
1826 accumulator->Add("<Invalid String>");
1827 return;
1828 }
1829
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001830 StringCharacterStream stream(this);
Steve Blocka7e24c12009-10-30 11:49:00 +00001831
1832 bool truncated = false;
1833 if (len > kMaxShortPrintLength) {
1834 len = kMaxShortPrintLength;
1835 truncated = true;
1836 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001837 bool one_byte = true;
Steve Blocka7e24c12009-10-30 11:49:00 +00001838 for (int i = 0; i < len; i++) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001839 uint16_t c = stream.GetNext();
Steve Blocka7e24c12009-10-30 11:49:00 +00001840
1841 if (c < 32 || c >= 127) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001842 one_byte = false;
Steve Blocka7e24c12009-10-30 11:49:00 +00001843 }
1844 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001845 stream.Reset(this);
1846 if (one_byte) {
Steve Blocka7e24c12009-10-30 11:49:00 +00001847 accumulator->Add("<String[%u]: ", length());
1848 for (int i = 0; i < len; i++) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001849 accumulator->Put(static_cast<char>(stream.GetNext()));
Steve Blocka7e24c12009-10-30 11:49:00 +00001850 }
1851 accumulator->Put('>');
1852 } else {
1853 // Backslash indicates that the string contains control
1854 // characters and that backslashes are therefore escaped.
1855 accumulator->Add("<String[%u]\\: ", length());
1856 for (int i = 0; i < len; i++) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001857 uint16_t c = stream.GetNext();
Steve Blocka7e24c12009-10-30 11:49:00 +00001858 if (c == '\n') {
1859 accumulator->Add("\\n");
1860 } else if (c == '\r') {
1861 accumulator->Add("\\r");
1862 } else if (c == '\\') {
1863 accumulator->Add("\\\\");
1864 } else if (c < 32 || c > 126) {
1865 accumulator->Add("\\x%02x", c);
1866 } else {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001867 accumulator->Put(static_cast<char>(c));
Steve Blocka7e24c12009-10-30 11:49:00 +00001868 }
1869 }
1870 if (truncated) {
1871 accumulator->Put('.');
1872 accumulator->Put('.');
1873 accumulator->Put('.');
1874 }
1875 accumulator->Put('>');
1876 }
1877 return;
1878}
1879
1880
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001881void String::PrintUC16(std::ostream& os, int start, int end) { // NOLINT
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001882 if (end < 0) end = length();
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001883 StringCharacterStream stream(this, start);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001884 for (int i = start; i < end && stream.HasMore(); i++) {
1885 os << AsUC16(stream.GetNext());
1886 }
1887}
1888
1889
Steve Blocka7e24c12009-10-30 11:49:00 +00001890void JSObject::JSObjectShortPrint(StringStream* accumulator) {
1891 switch (map()->instance_type()) {
1892 case JS_ARRAY_TYPE: {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001893 double length = JSArray::cast(this)->length()->IsUndefined()
1894 ? 0
1895 : JSArray::cast(this)->length()->Number();
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001896 accumulator->Add("<JS Array[%u]>", static_cast<uint32_t>(length));
Steve Blocka7e24c12009-10-30 11:49:00 +00001897 break;
1898 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001899 case JS_BOUND_FUNCTION_TYPE: {
1900 JSBoundFunction* bound_function = JSBoundFunction::cast(this);
1901 Object* name = bound_function->name();
1902 accumulator->Add("<JS BoundFunction");
1903 if (name->IsString()) {
1904 String* str = String::cast(name);
1905 if (str->length() > 0) {
1906 accumulator->Add(" ");
1907 accumulator->Put(str);
1908 }
1909 }
1910 accumulator->Add(
1911 " (BoundTargetFunction %p)>",
1912 reinterpret_cast<void*>(bound_function->bound_target_function()));
1913 break;
1914 }
Ben Murdoch69a99ed2011-11-30 16:03:39 +00001915 case JS_WEAK_MAP_TYPE: {
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001916 accumulator->Add("<JS WeakMap>");
Ben Murdoch69a99ed2011-11-30 16:03:39 +00001917 break;
1918 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001919 case JS_WEAK_SET_TYPE: {
1920 accumulator->Add("<JS WeakSet>");
1921 break;
1922 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001923 case JS_REGEXP_TYPE: {
1924 accumulator->Add("<JS RegExp>");
1925 break;
1926 }
1927 case JS_FUNCTION_TYPE: {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001928 JSFunction* function = JSFunction::cast(this);
1929 Object* fun_name = function->shared()->DebugName();
Steve Blocka7e24c12009-10-30 11:49:00 +00001930 bool printed = false;
1931 if (fun_name->IsString()) {
1932 String* str = String::cast(fun_name);
1933 if (str->length() > 0) {
1934 accumulator->Add("<JS Function ");
1935 accumulator->Put(str);
Steve Blocka7e24c12009-10-30 11:49:00 +00001936 printed = true;
1937 }
1938 }
1939 if (!printed) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001940 accumulator->Add("<JS Function");
Steve Blocka7e24c12009-10-30 11:49:00 +00001941 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001942 accumulator->Add(" (SharedFunctionInfo %p)",
1943 reinterpret_cast<void*>(function->shared()));
1944 accumulator->Put('>');
1945 break;
1946 }
1947 case JS_GENERATOR_OBJECT_TYPE: {
1948 accumulator->Add("<JS Generator>");
1949 break;
1950 }
1951 case JS_MODULE_TYPE: {
1952 accumulator->Add("<JS Module>");
Steve Blocka7e24c12009-10-30 11:49:00 +00001953 break;
1954 }
1955 // All other JSObjects are rather similar to each other (JSObject,
1956 // JSGlobalProxy, JSGlobalObject, JSUndetectableObject, JSValue).
1957 default: {
Ben Murdoch8b112d22011-06-08 16:22:53 +01001958 Map* map_of_this = map();
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001959 Heap* heap = GetHeap();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001960 Object* constructor = map_of_this->GetConstructor();
Steve Blocka7e24c12009-10-30 11:49:00 +00001961 bool printed = false;
1962 if (constructor->IsHeapObject() &&
Steve Block44f0eee2011-05-26 01:26:41 +01001963 !heap->Contains(HeapObject::cast(constructor))) {
Steve Blocka7e24c12009-10-30 11:49:00 +00001964 accumulator->Add("!!!INVALID CONSTRUCTOR!!!");
1965 } else {
1966 bool global_object = IsJSGlobalProxy();
1967 if (constructor->IsJSFunction()) {
Steve Block44f0eee2011-05-26 01:26:41 +01001968 if (!heap->Contains(JSFunction::cast(constructor)->shared())) {
Steve Blocka7e24c12009-10-30 11:49:00 +00001969 accumulator->Add("!!!INVALID SHARED ON CONSTRUCTOR!!!");
1970 } else {
1971 Object* constructor_name =
1972 JSFunction::cast(constructor)->shared()->name();
1973 if (constructor_name->IsString()) {
1974 String* str = String::cast(constructor_name);
1975 if (str->length() > 0) {
1976 bool vowel = AnWord(str);
1977 accumulator->Add("<%sa%s ",
1978 global_object ? "Global Object: " : "",
1979 vowel ? "n" : "");
1980 accumulator->Put(str);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001981 accumulator->Add(" with %smap %p",
1982 map_of_this->is_deprecated() ? "deprecated " : "",
1983 map_of_this);
Steve Blocka7e24c12009-10-30 11:49:00 +00001984 printed = true;
1985 }
1986 }
1987 }
1988 }
1989 if (!printed) {
1990 accumulator->Add("<JS %sObject", global_object ? "Global " : "");
1991 }
1992 }
1993 if (IsJSValue()) {
1994 accumulator->Add(" value = ");
1995 JSValue::cast(this)->value()->ShortPrint(accumulator);
1996 }
1997 accumulator->Put('>');
1998 break;
1999 }
2000 }
2001}
2002
2003
Ben Murdoch3ef787d2012-04-12 10:51:47 +01002004void JSObject::PrintElementsTransition(
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002005 FILE* file, Handle<JSObject> object,
2006 ElementsKind from_kind, Handle<FixedArrayBase> from_elements,
2007 ElementsKind to_kind, Handle<FixedArrayBase> to_elements) {
Ben Murdoch3ef787d2012-04-12 10:51:47 +01002008 if (from_kind != to_kind) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002009 OFStream os(file);
2010 os << "elements transition [" << ElementsKindToString(from_kind) << " -> "
2011 << ElementsKindToString(to_kind) << "] in ";
2012 JavaScriptFrame::PrintTop(object->GetIsolate(), file, false, true);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01002013 PrintF(file, " for ");
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002014 object->ShortPrint(file);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01002015 PrintF(file, " from ");
2016 from_elements->ShortPrint(file);
2017 PrintF(file, " to ");
2018 to_elements->ShortPrint(file);
2019 PrintF(file, "\n");
2020 }
2021}
2022
2023
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002024// static
2025MaybeHandle<JSFunction> Map::GetConstructorFunction(
2026 Handle<Map> map, Handle<Context> native_context) {
2027 if (map->IsPrimitiveMap()) {
2028 int const constructor_function_index = map->GetConstructorFunctionIndex();
2029 if (constructor_function_index != kNoConstructorFunctionIndex) {
2030 return handle(
2031 JSFunction::cast(native_context->get(constructor_function_index)));
2032 }
2033 }
2034 return MaybeHandle<JSFunction>();
2035}
2036
2037
2038void Map::PrintReconfiguration(FILE* file, int modify_index, PropertyKind kind,
2039 PropertyAttributes attributes) {
2040 OFStream os(file);
2041 os << "[reconfiguring]";
2042 Name* name = instance_descriptors()->GetKey(modify_index);
2043 if (name->IsString()) {
2044 String::cast(name)->PrintOn(file);
2045 } else {
2046 os << "{symbol " << static_cast<void*>(name) << "}";
2047 }
2048 os << ": " << (kind == kData ? "kData" : "ACCESSORS") << ", attrs: ";
2049 os << attributes << " [";
2050 JavaScriptFrame::PrintTop(GetIsolate(), file, false, true);
2051 os << "]\n";
2052}
2053
Ben Murdoch097c5b22016-05-18 11:27:45 +01002054void Map::PrintGeneralization(
2055 FILE* file, const char* reason, int modify_index, int split,
2056 int descriptors, bool constant_to_field, Representation old_representation,
2057 Representation new_representation, MaybeHandle<FieldType> old_field_type,
2058 MaybeHandle<Object> old_value, MaybeHandle<FieldType> new_field_type,
2059 MaybeHandle<Object> new_value) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002060 OFStream os(file);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002061 os << "[generalizing]";
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002062 Name* name = instance_descriptors()->GetKey(modify_index);
2063 if (name->IsString()) {
2064 String::cast(name)->PrintOn(file);
2065 } else {
2066 os << "{symbol " << static_cast<void*>(name) << "}";
2067 }
2068 os << ":";
2069 if (constant_to_field) {
2070 os << "c";
2071 } else {
2072 os << old_representation.Mnemonic() << "{";
Ben Murdoch097c5b22016-05-18 11:27:45 +01002073 if (old_field_type.is_null()) {
2074 os << Brief(*(old_value.ToHandleChecked()));
2075 } else {
2076 old_field_type.ToHandleChecked()->PrintTo(os);
2077 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002078 os << "}";
2079 }
2080 os << "->" << new_representation.Mnemonic() << "{";
Ben Murdoch097c5b22016-05-18 11:27:45 +01002081 if (new_field_type.is_null()) {
2082 os << Brief(*(new_value.ToHandleChecked()));
2083 } else {
2084 new_field_type.ToHandleChecked()->PrintTo(os);
2085 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002086 os << "} (";
2087 if (strlen(reason) > 0) {
2088 os << reason;
2089 } else {
2090 os << "+" << (descriptors - split) << " maps";
2091 }
2092 os << ") [";
2093 JavaScriptFrame::PrintTop(GetIsolate(), file, false, true);
2094 os << "]\n";
2095}
2096
2097
2098void JSObject::PrintInstanceMigration(FILE* file,
2099 Map* original_map,
2100 Map* new_map) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002101 PrintF(file, "[migrating]");
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002102 DescriptorArray* o = original_map->instance_descriptors();
2103 DescriptorArray* n = new_map->instance_descriptors();
2104 for (int i = 0; i < original_map->NumberOfOwnDescriptors(); i++) {
2105 Representation o_r = o->GetDetails(i).representation();
2106 Representation n_r = n->GetDetails(i).representation();
2107 if (!o_r.Equals(n_r)) {
2108 String::cast(o->GetKey(i))->PrintOn(file);
2109 PrintF(file, ":%s->%s ", o_r.Mnemonic(), n_r.Mnemonic());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002110 } else if (o->GetDetails(i).type() == DATA_CONSTANT &&
2111 n->GetDetails(i).type() == DATA) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002112 Name* name = o->GetKey(i);
2113 if (name->IsString()) {
2114 String::cast(name)->PrintOn(file);
2115 } else {
2116 PrintF(file, "{symbol %p}", static_cast<void*>(name));
2117 }
2118 PrintF(file, " ");
2119 }
2120 }
2121 PrintF(file, "\n");
2122}
2123
2124
Emily Bernierd0a1eb72015-03-24 16:35:39 -04002125void HeapObject::HeapObjectShortPrint(std::ostream& os) { // NOLINT
Steve Block44f0eee2011-05-26 01:26:41 +01002126 Heap* heap = GetHeap();
2127 if (!heap->Contains(this)) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002128 os << "!!!INVALID POINTER!!!";
Steve Blocka7e24c12009-10-30 11:49:00 +00002129 return;
2130 }
Steve Block44f0eee2011-05-26 01:26:41 +01002131 if (!heap->Contains(map())) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002132 os << "!!!INVALID MAP!!!";
Steve Blocka7e24c12009-10-30 11:49:00 +00002133 return;
2134 }
2135
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002136 os << this << " ";
Steve Blocka7e24c12009-10-30 11:49:00 +00002137
2138 if (IsString()) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002139 HeapStringAllocator allocator;
2140 StringStream accumulator(&allocator);
2141 String::cast(this)->StringShortPrint(&accumulator);
2142 os << accumulator.ToCString().get();
Steve Blocka7e24c12009-10-30 11:49:00 +00002143 return;
2144 }
2145 if (IsJSObject()) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002146 HeapStringAllocator allocator;
2147 StringStream accumulator(&allocator);
2148 JSObject::cast(this)->JSObjectShortPrint(&accumulator);
2149 os << accumulator.ToCString().get();
Steve Blocka7e24c12009-10-30 11:49:00 +00002150 return;
2151 }
2152 switch (map()->instance_type()) {
2153 case MAP_TYPE:
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002154 os << "<Map(" << ElementsKindToString(Map::cast(this)->elements_kind())
2155 << ")>";
Steve Blocka7e24c12009-10-30 11:49:00 +00002156 break;
2157 case FIXED_ARRAY_TYPE:
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002158 os << "<FixedArray[" << FixedArray::cast(this)->length() << "]>";
Steve Blocka7e24c12009-10-30 11:49:00 +00002159 break;
Ben Murdoch3ef787d2012-04-12 10:51:47 +01002160 case FIXED_DOUBLE_ARRAY_TYPE:
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002161 os << "<FixedDoubleArray[" << FixedDoubleArray::cast(this)->length()
2162 << "]>";
Ben Murdoch3ef787d2012-04-12 10:51:47 +01002163 break;
Steve Blocka7e24c12009-10-30 11:49:00 +00002164 case BYTE_ARRAY_TYPE:
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002165 os << "<ByteArray[" << ByteArray::cast(this)->length() << "]>";
Steve Blocka7e24c12009-10-30 11:49:00 +00002166 break;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002167 case BYTECODE_ARRAY_TYPE:
2168 os << "<BytecodeArray[" << BytecodeArray::cast(this)->length() << "]>";
2169 break;
2170 case TRANSITION_ARRAY_TYPE:
2171 os << "<TransitionArray[" << TransitionArray::cast(this)->length()
2172 << "]>";
2173 break;
Ben Murdoch3ef787d2012-04-12 10:51:47 +01002174 case FREE_SPACE_TYPE:
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002175 os << "<FreeSpace[" << FreeSpace::cast(this)->size() << "]>";
Ben Murdoch3ef787d2012-04-12 10:51:47 +01002176 break;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002177#define TYPED_ARRAY_SHORT_PRINT(Type, type, TYPE, ctype, size) \
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002178 case FIXED_##TYPE##_ARRAY_TYPE: \
2179 os << "<Fixed" #Type "Array[" << Fixed##Type##Array::cast(this)->length() \
2180 << "]>"; \
2181 break;
2182
2183 TYPED_ARRAYS(TYPED_ARRAY_SHORT_PRINT)
2184#undef TYPED_ARRAY_SHORT_PRINT
2185
2186 case SHARED_FUNCTION_INFO_TYPE: {
2187 SharedFunctionInfo* shared = SharedFunctionInfo::cast(this);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002188 base::SmartArrayPointer<char> debug_name =
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002189 shared->DebugName()->ToCString();
2190 if (debug_name[0] != 0) {
2191 os << "<SharedFunctionInfo " << debug_name.get() << ">";
2192 } else {
2193 os << "<SharedFunctionInfo>";
2194 }
Steve Blocka7e24c12009-10-30 11:49:00 +00002195 break;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002196 }
Steve Block1e0659c2011-05-24 12:43:12 +01002197 case JS_MESSAGE_OBJECT_TYPE:
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002198 os << "<JSMessageObject>";
Steve Block1e0659c2011-05-24 12:43:12 +01002199 break;
Steve Blocka7e24c12009-10-30 11:49:00 +00002200#define MAKE_STRUCT_CASE(NAME, Name, name) \
2201 case NAME##_TYPE: \
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002202 os << "<" #Name ">"; \
Steve Blocka7e24c12009-10-30 11:49:00 +00002203 break;
2204 STRUCT_LIST(MAKE_STRUCT_CASE)
2205#undef MAKE_STRUCT_CASE
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002206 case CODE_TYPE: {
2207 Code* code = Code::cast(this);
2208 os << "<Code: " << Code::Kind2String(code->kind()) << ">";
Steve Blocka7e24c12009-10-30 11:49:00 +00002209 break;
2210 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002211 case ODDBALL_TYPE: {
2212 if (IsUndefined()) {
2213 os << "<undefined>";
2214 } else if (IsTheHole()) {
2215 os << "<the hole>";
2216 } else if (IsNull()) {
2217 os << "<null>";
2218 } else if (IsTrue()) {
2219 os << "<true>";
2220 } else if (IsFalse()) {
2221 os << "<false>";
2222 } else {
2223 os << "<Odd Oddball>";
2224 }
Steve Blocka7e24c12009-10-30 11:49:00 +00002225 break;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002226 }
2227 case SYMBOL_TYPE: {
2228 Symbol* symbol = Symbol::cast(this);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04002229 symbol->SymbolShortPrint(os);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002230 break;
2231 }
2232 case HEAP_NUMBER_TYPE: {
2233 os << "<Number: ";
2234 HeapNumber::cast(this)->HeapNumberPrint(os);
2235 os << ">";
2236 break;
2237 }
2238 case MUTABLE_HEAP_NUMBER_TYPE: {
2239 os << "<MutableNumber: ";
2240 HeapNumber::cast(this)->HeapNumberPrint(os);
2241 os << '>';
2242 break;
2243 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002244 case SIMD128_VALUE_TYPE: {
2245#define SIMD128_TYPE(TYPE, Type, type, lane_count, lane_type) \
2246 if (Is##Type()) { \
2247 os << "<" #Type ">"; \
2248 break; \
2249 }
2250 SIMD128_TYPES(SIMD128_TYPE)
2251#undef SIMD128_TYPE
2252 UNREACHABLE();
2253 break;
2254 }
Ben Murdoch589d6972011-11-30 16:04:58 +00002255 case JS_PROXY_TYPE:
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002256 os << "<JSProxy>";
Ben Murdoch589d6972011-11-30 16:04:58 +00002257 break;
Ben Murdoch257744e2011-11-30 15:57:28 +00002258 case FOREIGN_TYPE:
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002259 os << "<Foreign>";
Steve Blocka7e24c12009-10-30 11:49:00 +00002260 break;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002261 case CELL_TYPE: {
2262 os << "Cell for ";
2263 HeapStringAllocator allocator;
2264 StringStream accumulator(&allocator);
2265 Cell::cast(this)->value()->ShortPrint(&accumulator);
2266 os << accumulator.ToCString().get();
Steve Blocka7e24c12009-10-30 11:49:00 +00002267 break;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002268 }
2269 case PROPERTY_CELL_TYPE: {
2270 os << "PropertyCell for ";
2271 HeapStringAllocator allocator;
2272 StringStream accumulator(&allocator);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002273 PropertyCell* cell = PropertyCell::cast(this);
2274 cell->value()->ShortPrint(&accumulator);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002275 os << accumulator.ToCString().get();
2276 break;
2277 }
Emily Bernierd0a1eb72015-03-24 16:35:39 -04002278 case WEAK_CELL_TYPE: {
2279 os << "WeakCell for ";
2280 HeapStringAllocator allocator;
2281 StringStream accumulator(&allocator);
2282 WeakCell::cast(this)->value()->ShortPrint(&accumulator);
2283 os << accumulator.ToCString().get();
2284 break;
2285 }
Steve Blocka7e24c12009-10-30 11:49:00 +00002286 default:
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002287 os << "<Other heap object (" << map()->instance_type() << ")>";
Steve Blocka7e24c12009-10-30 11:49:00 +00002288 break;
2289 }
2290}
2291
2292
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002293void HeapObject::Iterate(ObjectVisitor* v) { IterateFast<ObjectVisitor>(v); }
2294
2295
2296void HeapObject::IterateBody(ObjectVisitor* v) {
Steve Blocka7e24c12009-10-30 11:49:00 +00002297 Map* m = map();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002298 IterateBodyFast<ObjectVisitor>(m->instance_type(), SizeFromMap(m), v);
Steve Blocka7e24c12009-10-30 11:49:00 +00002299}
2300
2301
2302void HeapObject::IterateBody(InstanceType type, int object_size,
2303 ObjectVisitor* v) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002304 IterateBodyFast<ObjectVisitor>(type, object_size, v);
2305}
2306
2307
2308struct CallIsValidSlot {
2309 template <typename BodyDescriptor>
2310 static bool apply(HeapObject* obj, int offset, int) {
2311 return BodyDescriptor::IsValidSlot(obj, offset);
Steve Blocka7e24c12009-10-30 11:49:00 +00002312 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002313};
Steve Blocka7e24c12009-10-30 11:49:00 +00002314
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002315
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002316bool HeapObject::IsValidSlot(int offset) {
2317 DCHECK_NE(0, offset);
2318 return BodyDescriptorApply<CallIsValidSlot, bool>(map()->instance_type(),
2319 this, offset, 0);
Steve Blocka7e24c12009-10-30 11:49:00 +00002320}
2321
2322
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002323bool HeapNumber::HeapNumberBooleanValue() {
2324 return DoubleToBoolean(value());
Steve Blocka7e24c12009-10-30 11:49:00 +00002325}
2326
2327
Emily Bernierd0a1eb72015-03-24 16:35:39 -04002328void HeapNumber::HeapNumberPrint(std::ostream& os) { // NOLINT
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002329 os << value();
Steve Blocka7e24c12009-10-30 11:49:00 +00002330}
2331
2332
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002333#define FIELD_ADDR_CONST(p, offset) \
2334 (reinterpret_cast<const byte*>(p) + offset - kHeapObjectTag)
2335
2336#define READ_INT32_FIELD(p, offset) \
2337 (*reinterpret_cast<const int32_t*>(FIELD_ADDR_CONST(p, offset)))
2338
2339#define READ_INT64_FIELD(p, offset) \
2340 (*reinterpret_cast<const int64_t*>(FIELD_ADDR_CONST(p, offset)))
2341
2342#define READ_BYTE_FIELD(p, offset) \
2343 (*reinterpret_cast<const byte*>(FIELD_ADDR_CONST(p, offset)))
2344
2345
2346// static
2347Handle<String> Simd128Value::ToString(Handle<Simd128Value> input) {
2348#define SIMD128_TYPE(TYPE, Type, type, lane_count, lane_type) \
2349 if (input->Is##Type()) return Type::ToString(Handle<Type>::cast(input));
2350 SIMD128_TYPES(SIMD128_TYPE)
2351#undef SIMD128_TYPE
2352 UNREACHABLE();
2353 return Handle<String>::null();
2354}
2355
2356
2357// static
2358Handle<String> Float32x4::ToString(Handle<Float32x4> input) {
2359 Isolate* const isolate = input->GetIsolate();
2360 char arr[100];
2361 Vector<char> buffer(arr, arraysize(arr));
2362 std::ostringstream os;
2363 os << "SIMD.Float32x4("
2364 << std::string(DoubleToCString(input->get_lane(0), buffer)) << ", "
2365 << std::string(DoubleToCString(input->get_lane(1), buffer)) << ", "
2366 << std::string(DoubleToCString(input->get_lane(2), buffer)) << ", "
2367 << std::string(DoubleToCString(input->get_lane(3), buffer)) << ")";
2368 return isolate->factory()->NewStringFromAsciiChecked(os.str().c_str());
2369}
2370
2371
2372#define SIMD128_BOOL_TO_STRING(Type, lane_count) \
2373 Handle<String> Type::ToString(Handle<Type> input) { \
2374 Isolate* const isolate = input->GetIsolate(); \
2375 std::ostringstream os; \
2376 os << "SIMD." #Type "("; \
2377 os << (input->get_lane(0) ? "true" : "false"); \
2378 for (int i = 1; i < lane_count; i++) { \
2379 os << ", " << (input->get_lane(i) ? "true" : "false"); \
2380 } \
2381 os << ")"; \
2382 return isolate->factory()->NewStringFromAsciiChecked(os.str().c_str()); \
2383 }
2384SIMD128_BOOL_TO_STRING(Bool32x4, 4)
2385SIMD128_BOOL_TO_STRING(Bool16x8, 8)
2386SIMD128_BOOL_TO_STRING(Bool8x16, 16)
2387#undef SIMD128_BOOL_TO_STRING
2388
2389
2390#define SIMD128_INT_TO_STRING(Type, lane_count) \
2391 Handle<String> Type::ToString(Handle<Type> input) { \
2392 Isolate* const isolate = input->GetIsolate(); \
2393 char arr[100]; \
2394 Vector<char> buffer(arr, arraysize(arr)); \
2395 std::ostringstream os; \
2396 os << "SIMD." #Type "("; \
2397 os << IntToCString(input->get_lane(0), buffer); \
2398 for (int i = 1; i < lane_count; i++) { \
2399 os << ", " << IntToCString(input->get_lane(i), buffer); \
2400 } \
2401 os << ")"; \
2402 return isolate->factory()->NewStringFromAsciiChecked(os.str().c_str()); \
2403 }
2404SIMD128_INT_TO_STRING(Int32x4, 4)
2405SIMD128_INT_TO_STRING(Uint32x4, 4)
2406SIMD128_INT_TO_STRING(Int16x8, 8)
2407SIMD128_INT_TO_STRING(Uint16x8, 8)
2408SIMD128_INT_TO_STRING(Int8x16, 16)
2409SIMD128_INT_TO_STRING(Uint8x16, 16)
2410#undef SIMD128_INT_TO_STRING
2411
2412
2413bool Simd128Value::BitwiseEquals(const Simd128Value* other) const {
2414 return READ_INT64_FIELD(this, kValueOffset) ==
2415 READ_INT64_FIELD(other, kValueOffset) &&
2416 READ_INT64_FIELD(this, kValueOffset + kInt64Size) ==
2417 READ_INT64_FIELD(other, kValueOffset + kInt64Size);
2418}
2419
2420
2421uint32_t Simd128Value::Hash() const {
2422 uint32_t seed = v8::internal::kZeroHashSeed;
2423 uint32_t hash;
2424 hash = ComputeIntegerHash(READ_INT32_FIELD(this, kValueOffset), seed);
2425 hash = ComputeIntegerHash(
2426 READ_INT32_FIELD(this, kValueOffset + 1 * kInt32Size), hash * 31);
2427 hash = ComputeIntegerHash(
2428 READ_INT32_FIELD(this, kValueOffset + 2 * kInt32Size), hash * 31);
2429 hash = ComputeIntegerHash(
2430 READ_INT32_FIELD(this, kValueOffset + 3 * kInt32Size), hash * 31);
2431 return hash;
2432}
2433
2434
2435void Simd128Value::CopyBits(void* destination) const {
2436 memcpy(destination, &READ_BYTE_FIELD(this, kValueOffset), kSimd128Size);
2437}
2438
2439
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00002440String* JSReceiver::class_name() {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002441 if (IsFunction()) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002442 return GetHeap()->Function_string();
Steve Blocka7e24c12009-10-30 11:49:00 +00002443 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002444 Object* maybe_constructor = map()->GetConstructor();
2445 if (maybe_constructor->IsJSFunction()) {
2446 JSFunction* constructor = JSFunction::cast(maybe_constructor);
Steve Blocka7e24c12009-10-30 11:49:00 +00002447 return String::cast(constructor->shared()->instance_class_name());
2448 }
2449 // If the constructor is not present, return "Object".
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002450 return GetHeap()->Object_string();
Steve Blocka7e24c12009-10-30 11:49:00 +00002451}
2452
2453
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002454MaybeHandle<String> JSReceiver::BuiltinStringTag(Handle<JSReceiver> object) {
2455 Maybe<bool> is_array = Object::IsArray(object);
2456 MAYBE_RETURN(is_array, MaybeHandle<String>());
2457 Isolate* const isolate = object->GetIsolate();
2458 if (is_array.FromJust()) {
2459 return isolate->factory()->Array_string();
Steve Blocka7e24c12009-10-30 11:49:00 +00002460 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002461 // TODO(adamk): According to ES2015, we should return "Function" when
2462 // object has a [[Call]] internal method (corresponds to IsCallable).
2463 // But this is well cemented in layout tests and might cause webbreakage.
2464 // if (object->IsCallable()) {
2465 // return isolate->factory()->Function_string();
2466 // }
2467 // TODO(adamk): class_name() is expensive, replace with instance type
2468 // checks where possible.
2469 return handle(object->class_name(), isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00002470}
2471
2472
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002473// static
2474Handle<String> JSReceiver::GetConstructorName(Handle<JSReceiver> receiver) {
2475 Isolate* isolate = receiver->GetIsolate();
2476
2477 // If the object was instantiated simply with base == new.target, the
2478 // constructor on the map provides the most accurate name.
2479 // Don't provide the info for prototypes, since their constructors are
2480 // reclaimed and replaced by Object in OptimizeAsPrototype.
2481 if (!receiver->IsJSProxy() && receiver->map()->new_target_is_base() &&
2482 !receiver->map()->is_prototype_map()) {
2483 Object* maybe_constructor = receiver->map()->GetConstructor();
2484 if (maybe_constructor->IsJSFunction()) {
2485 JSFunction* constructor = JSFunction::cast(maybe_constructor);
2486 String* name = String::cast(constructor->shared()->name());
2487 if (name->length() == 0) name = constructor->shared()->inferred_name();
2488 if (name->length() != 0 &&
2489 !name->Equals(isolate->heap()->Object_string())) {
2490 return handle(name, isolate);
2491 }
2492 }
2493 }
2494
2495 if (FLAG_harmony_tostring) {
2496 Handle<Object> maybe_tag = JSReceiver::GetDataProperty(
2497 receiver, isolate->factory()->to_string_tag_symbol());
2498 if (maybe_tag->IsString()) return Handle<String>::cast(maybe_tag);
2499 }
2500
2501 PrototypeIterator iter(isolate, receiver);
2502 if (iter.IsAtEnd()) return handle(receiver->class_name());
2503 Handle<JSReceiver> start = PrototypeIterator::GetCurrent<JSReceiver>(iter);
2504 LookupIterator it(receiver, isolate->factory()->constructor_string(), start,
2505 LookupIterator::PROTOTYPE_CHAIN_SKIP_INTERCEPTOR);
2506 Handle<Object> maybe_constructor = JSReceiver::GetDataProperty(&it);
2507 Handle<String> result = isolate->factory()->Object_string();
2508 if (maybe_constructor->IsJSFunction()) {
2509 JSFunction* constructor = JSFunction::cast(*maybe_constructor);
2510 String* name = String::cast(constructor->shared()->name());
2511 if (name->length() == 0) name = constructor->shared()->inferred_name();
2512 if (name->length() > 0) result = handle(name, isolate);
2513 }
2514
2515 return result.is_identical_to(isolate->factory()->Object_string())
2516 ? handle(receiver->class_name())
2517 : result;
2518}
2519
2520
2521Context* JSReceiver::GetCreationContext() {
Ben Murdoch097c5b22016-05-18 11:27:45 +01002522 JSReceiver* receiver = this;
2523 while (receiver->IsJSBoundFunction()) {
2524 receiver = JSBoundFunction::cast(receiver)->bound_target_function();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002525 }
Ben Murdoch097c5b22016-05-18 11:27:45 +01002526 Object* constructor = receiver->map()->GetConstructor();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002527 JSFunction* function;
2528 if (constructor->IsJSFunction()) {
2529 function = JSFunction::cast(constructor);
2530 } else {
2531 // Functions have null as a constructor,
2532 // but any JSFunction knows its context immediately.
Ben Murdoch097c5b22016-05-18 11:27:45 +01002533 CHECK(receiver->IsJSFunction());
2534 function = JSFunction::cast(receiver);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002535 }
2536
2537 return function->context()->native_context();
2538}
2539
Ben Murdoch097c5b22016-05-18 11:27:45 +01002540static Handle<Object> WrapType(Handle<FieldType> type) {
2541 if (type->IsClass()) return Map::WeakCellForMap(type->AsClass());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002542 return type;
Steve Blocka7e24c12009-10-30 11:49:00 +00002543}
2544
Ben Murdoch097c5b22016-05-18 11:27:45 +01002545MaybeHandle<Map> Map::CopyWithField(Handle<Map> map, Handle<Name> name,
2546 Handle<FieldType> type,
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002547 PropertyAttributes attributes,
2548 Representation representation,
2549 TransitionFlag flag) {
2550 DCHECK(DescriptorArray::kNotFound ==
2551 map->instance_descriptors()->Search(
2552 *name, map->NumberOfOwnDescriptors()));
Ben Murdoch8b112d22011-06-08 16:22:53 +01002553
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002554 // Ensure the descriptor array does not get too big.
2555 if (map->NumberOfOwnDescriptors() >= kMaxNumberOfDescriptors) {
2556 return MaybeHandle<Map>();
Steve Blocka7e24c12009-10-30 11:49:00 +00002557 }
2558
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002559 Isolate* isolate = map->GetIsolate();
2560
Steve Blocka7e24c12009-10-30 11:49:00 +00002561 // Compute the new index for new field.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002562 int index = map->NextFreePropertyIndex();
Steve Blocka7e24c12009-10-30 11:49:00 +00002563
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002564 if (map->instance_type() == JS_CONTEXT_EXTENSION_OBJECT_TYPE) {
2565 representation = Representation::Tagged();
Ben Murdoch097c5b22016-05-18 11:27:45 +01002566 type = FieldType::Any(isolate);
John Reck59135872010-11-02 12:39:01 -07002567 }
Steve Blocka7e24c12009-10-30 11:49:00 +00002568
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002569 Handle<Object> wrapped_type(WrapType(type));
2570
2571 DataDescriptor new_field_desc(name, index, wrapped_type, attributes,
2572 representation);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002573 Handle<Map> new_map = Map::CopyAddDescriptor(map, &new_field_desc, flag);
2574 int unused_property_fields = new_map->unused_property_fields() - 1;
2575 if (unused_property_fields < 0) {
2576 unused_property_fields += JSObject::kFieldsAdded;
John Reck59135872010-11-02 12:39:01 -07002577 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002578 new_map->set_unused_property_fields(unused_property_fields);
2579 return new_map;
Steve Blocka7e24c12009-10-30 11:49:00 +00002580}
2581
2582
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002583MaybeHandle<Map> Map::CopyWithConstant(Handle<Map> map,
2584 Handle<Name> name,
2585 Handle<Object> constant,
2586 PropertyAttributes attributes,
2587 TransitionFlag flag) {
2588 // Ensure the descriptor array does not get too big.
2589 if (map->NumberOfOwnDescriptors() >= kMaxNumberOfDescriptors) {
2590 return MaybeHandle<Map>();
John Reck59135872010-11-02 12:39:01 -07002591 }
Steve Blocka7e24c12009-10-30 11:49:00 +00002592
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002593 // Allocate new instance descriptors with (name, constant) added.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002594 DataConstantDescriptor new_constant_desc(name, constant, attributes);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002595 return Map::CopyAddDescriptor(map, &new_constant_desc, flag);
Steve Blocka7e24c12009-10-30 11:49:00 +00002596}
2597
2598
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002599void JSObject::AddSlowProperty(Handle<JSObject> object,
2600 Handle<Name> name,
2601 Handle<Object> value,
2602 PropertyAttributes attributes) {
2603 DCHECK(!object->HasFastProperties());
2604 Isolate* isolate = object->GetIsolate();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002605 if (object->IsJSGlobalObject()) {
2606 Handle<GlobalDictionary> dict(object->global_dictionary());
2607 PropertyDetails details(attributes, DATA, 0, PropertyCellType::kNoCell);
Steve Blocka7e24c12009-10-30 11:49:00 +00002608 int entry = dict->FindEntry(name);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002609 // If there's a cell there, just invalidate and set the property.
2610 if (entry != GlobalDictionary::kNotFound) {
2611 PropertyCell::UpdateCell(dict, entry, value, details);
2612 // TODO(ishell): move this to UpdateCell.
2613 // Need to adjust the details.
Steve Blocka7e24c12009-10-30 11:49:00 +00002614 int index = dict->NextEnumerationIndex();
Steve Blocka7e24c12009-10-30 11:49:00 +00002615 dict->SetNextEnumerationIndex(index + 1);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002616 PropertyCell* cell = PropertyCell::cast(dict->ValueAt(entry));
2617 details = cell->property_details().set_index(index);
2618 cell->set_property_details(details);
2619
2620 } else {
2621 auto cell = isolate->factory()->NewPropertyCell();
2622 cell->set_value(*value);
2623 auto cell_type = value->IsUndefined() ? PropertyCellType::kUndefined
2624 : PropertyCellType::kConstant;
2625 details = details.set_cell_type(cell_type);
2626 value = cell;
2627
2628 Handle<GlobalDictionary> result =
2629 GlobalDictionary::Add(dict, name, value, details);
2630 if (*dict != *result) object->set_properties(*result);
Steve Blocka7e24c12009-10-30 11:49:00 +00002631 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002632 } else {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002633 Handle<NameDictionary> dict(object->property_dictionary());
2634 PropertyDetails details(attributes, DATA, 0, PropertyCellType::kNoCell);
2635 Handle<NameDictionary> result =
2636 NameDictionary::Add(dict, name, value, details);
2637 if (*dict != *result) object->set_properties(*result);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002638 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002639}
2640
2641
Emily Bernierd0a1eb72015-03-24 16:35:39 -04002642MaybeHandle<Object> JSObject::EnqueueChangeRecord(Handle<JSObject> object,
2643 const char* type_str,
2644 Handle<Name> name,
2645 Handle<Object> old_value) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002646 DCHECK(!object->IsJSGlobalProxy());
2647 DCHECK(!object->IsJSGlobalObject());
2648 Isolate* isolate = object->GetIsolate();
2649 HandleScope scope(isolate);
2650 Handle<String> type = isolate->factory()->InternalizeUtf8String(type_str);
2651 Handle<Object> args[] = { type, object, name, old_value };
2652 int argc = name.is_null() ? 2 : old_value->IsTheHole() ? 3 : 4;
2653
Emily Bernierd0a1eb72015-03-24 16:35:39 -04002654 return Execution::Call(isolate,
2655 Handle<JSFunction>(isolate->observers_notify_change()),
2656 isolate->factory()->undefined_value(), argc, args);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002657}
2658
2659
2660const char* Representation::Mnemonic() const {
2661 switch (kind_) {
2662 case kNone: return "v";
2663 case kTagged: return "t";
2664 case kSmi: return "s";
2665 case kDouble: return "d";
2666 case kInteger32: return "i";
2667 case kHeapObject: return "h";
2668 case kExternal: return "x";
2669 default:
2670 UNREACHABLE();
2671 return NULL;
2672 }
2673}
2674
2675
2676bool Map::InstancesNeedRewriting(Map* target, int target_number_of_fields,
2677 int target_inobject, int target_unused,
2678 int* old_number_of_fields) {
2679 // If fields were added (or removed), rewrite the instance.
2680 *old_number_of_fields = NumberOfFields();
2681 DCHECK(target_number_of_fields >= *old_number_of_fields);
2682 if (target_number_of_fields != *old_number_of_fields) return true;
2683
2684 // If smi descriptors were replaced by double descriptors, rewrite.
2685 DescriptorArray* old_desc = instance_descriptors();
2686 DescriptorArray* new_desc = target->instance_descriptors();
2687 int limit = NumberOfOwnDescriptors();
2688 for (int i = 0; i < limit; i++) {
2689 if (new_desc->GetDetails(i).representation().IsDouble() !=
2690 old_desc->GetDetails(i).representation().IsDouble()) {
2691 return true;
Steve Block44f0eee2011-05-26 01:26:41 +01002692 }
Steve Block8defd9f2010-07-08 12:39:36 +01002693 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002694
2695 // If no fields were added, and no inobject properties were removed, setting
2696 // the map is sufficient.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002697 if (target_inobject == GetInObjectProperties()) return false;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002698 // In-object slack tracking may have reduced the object size of the new map.
2699 // In that case, succeed if all existing fields were inobject, and they still
2700 // fit within the new inobject size.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002701 DCHECK(target_inobject < GetInObjectProperties());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002702 if (target_number_of_fields <= target_inobject) {
2703 DCHECK(target_number_of_fields + target_unused == target_inobject);
2704 return false;
2705 }
2706 // Otherwise, properties will need to be moved to the backing store.
2707 return true;
2708}
2709
2710
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002711// static
2712void JSObject::UpdatePrototypeUserRegistration(Handle<Map> old_map,
2713 Handle<Map> new_map,
2714 Isolate* isolate) {
2715 if (!FLAG_track_prototype_users) return;
2716 if (!old_map->is_prototype_map()) return;
2717 DCHECK(new_map->is_prototype_map());
2718 bool was_registered = JSObject::UnregisterPrototypeUser(old_map, isolate);
2719 new_map->set_prototype_info(old_map->prototype_info());
2720 old_map->set_prototype_info(Smi::FromInt(0));
2721 if (FLAG_trace_prototype_users) {
2722 PrintF("Moving prototype_info %p from map %p to map %p.\n",
2723 reinterpret_cast<void*>(new_map->prototype_info()),
2724 reinterpret_cast<void*>(*old_map),
2725 reinterpret_cast<void*>(*new_map));
2726 }
2727 if (was_registered) {
2728 if (new_map->prototype_info()->IsPrototypeInfo()) {
2729 // The new map isn't registered with its prototype yet; reflect this fact
2730 // in the PrototypeInfo it just inherited from the old map.
2731 PrototypeInfo::cast(new_map->prototype_info())
2732 ->set_registry_slot(PrototypeInfo::UNREGISTERED);
2733 }
2734 JSObject::LazyRegisterPrototypeUser(new_map, isolate);
2735 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002736}
2737
Ben Murdoch097c5b22016-05-18 11:27:45 +01002738namespace {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002739// To migrate a fast instance to a fast map:
2740// - First check whether the instance needs to be rewritten. If not, simply
2741// change the map.
2742// - Otherwise, allocate a fixed array large enough to hold all fields, in
2743// addition to unused space.
2744// - Copy all existing properties in, in the following order: backing store
2745// properties, unused fields, inobject properties.
2746// - If all allocation succeeded, commit the state atomically:
2747// * Copy inobject properties from the backing store back into the object.
2748// * Trim the difference in instance size of the object. This also cleanly
2749// frees inobject properties that moved to the backing store.
2750// * If there are properties left in the backing store, trim of the space used
2751// to temporarily store the inobject properties.
2752// * If there are properties left in the backing store, install the backing
2753// store.
Ben Murdoch097c5b22016-05-18 11:27:45 +01002754void MigrateFastToFast(Handle<JSObject> object, Handle<Map> new_map) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002755 Isolate* isolate = object->GetIsolate();
2756 Handle<Map> old_map(object->map());
Ben Murdoch097c5b22016-05-18 11:27:45 +01002757 // In case of a regular transition.
2758 if (new_map->GetBackPointer() == *old_map) {
2759 // If the map does not add named properties, simply set the map.
2760 if (old_map->NumberOfOwnDescriptors() ==
2761 new_map->NumberOfOwnDescriptors()) {
2762 object->synchronized_set_map(*new_map);
2763 return;
2764 }
2765
2766 PropertyDetails details = new_map->GetLastDescriptorDetails();
2767 // Either new_map adds an kDescriptor property, or a kField property for
2768 // which there is still space, and which does not require a mutable double
2769 // box (an out-of-object double).
2770 if (details.location() == kDescriptor ||
2771 (old_map->unused_property_fields() > 0 &&
2772 ((FLAG_unbox_double_fields && object->properties()->length() == 0) ||
2773 !details.representation().IsDouble()))) {
2774 object->synchronized_set_map(*new_map);
2775 return;
2776 }
2777
2778 // If there is still space in the object, we need to allocate a mutable
2779 // double box.
2780 if (old_map->unused_property_fields() > 0) {
2781 FieldIndex index =
2782 FieldIndex::ForDescriptor(*new_map, new_map->LastAdded());
2783 DCHECK(details.representation().IsDouble());
2784 DCHECK(!new_map->IsUnboxedDoubleField(index));
2785 Handle<Object> value = isolate->factory()->NewHeapNumber(0, MUTABLE);
2786 object->RawFastPropertyAtPut(index, *value);
2787 object->synchronized_set_map(*new_map);
2788 return;
2789 }
2790
2791 // This migration is a transition from a map that has run out of property
2792 // space. Extend the backing store.
2793 int grow_by = new_map->unused_property_fields() + 1;
2794 Handle<FixedArray> old_storage = handle(object->properties(), isolate);
2795 Handle<FixedArray> new_storage =
2796 isolate->factory()->CopyFixedArrayAndGrow(old_storage, grow_by);
2797
2798 // Properly initialize newly added property.
2799 Handle<Object> value;
2800 if (details.representation().IsDouble()) {
2801 value = isolate->factory()->NewHeapNumber(0, MUTABLE);
2802 } else {
2803 value = isolate->factory()->uninitialized_value();
2804 }
2805 DCHECK_EQ(DATA, details.type());
2806 int target_index = details.field_index() - new_map->GetInObjectProperties();
2807 DCHECK(target_index >= 0); // Must be a backing store index.
2808 new_storage->set(target_index, *value);
2809
2810 // From here on we cannot fail and we shouldn't GC anymore.
2811 DisallowHeapAllocation no_allocation;
2812
2813 // Set the new property value and do the map transition.
2814 object->set_properties(*new_storage);
2815 object->synchronized_set_map(*new_map);
2816 return;
2817 }
2818
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002819 int old_number_of_fields;
2820 int number_of_fields = new_map->NumberOfFields();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002821 int inobject = new_map->GetInObjectProperties();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002822 int unused = new_map->unused_property_fields();
2823
2824 // Nothing to do if no functions were converted to fields and no smis were
2825 // converted to doubles.
2826 if (!old_map->InstancesNeedRewriting(*new_map, number_of_fields, inobject,
2827 unused, &old_number_of_fields)) {
2828 object->synchronized_set_map(*new_map);
2829 return;
2830 }
2831
2832 int total_size = number_of_fields + unused;
2833 int external = total_size - inobject;
2834
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002835 Handle<FixedArray> array = isolate->factory()->NewFixedArray(total_size);
2836
2837 Handle<DescriptorArray> old_descriptors(old_map->instance_descriptors());
2838 Handle<DescriptorArray> new_descriptors(new_map->instance_descriptors());
2839 int old_nof = old_map->NumberOfOwnDescriptors();
2840 int new_nof = new_map->NumberOfOwnDescriptors();
2841
2842 // This method only supports generalizing instances to at least the same
2843 // number of properties.
2844 DCHECK(old_nof <= new_nof);
2845
2846 for (int i = 0; i < old_nof; i++) {
2847 PropertyDetails details = new_descriptors->GetDetails(i);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002848 if (details.type() != DATA) continue;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002849 PropertyDetails old_details = old_descriptors->GetDetails(i);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04002850 Representation old_representation = old_details.representation();
2851 Representation representation = details.representation();
Emily Bernierd0a1eb72015-03-24 16:35:39 -04002852 Handle<Object> value;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002853 if (old_details.type() == ACCESSOR_CONSTANT) {
2854 // In case of kAccessor -> kData property reconfiguration, the property
2855 // must already be prepared for data or certain type.
2856 DCHECK(!details.representation().IsNone());
2857 if (details.representation().IsDouble()) {
2858 value = isolate->factory()->NewHeapNumber(0, MUTABLE);
2859 } else {
2860 value = isolate->factory()->uninitialized_value();
2861 }
2862 } else if (old_details.type() == DATA_CONSTANT) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -04002863 value = handle(old_descriptors->GetValue(i), isolate);
2864 DCHECK(!old_representation.IsDouble() && !representation.IsDouble());
2865 } else {
2866 FieldIndex index = FieldIndex::ForDescriptor(*old_map, i);
2867 if (object->IsUnboxedDoubleField(index)) {
2868 double old = object->RawFastDoublePropertyAt(index);
2869 value = isolate->factory()->NewHeapNumber(
2870 old, representation.IsDouble() ? MUTABLE : IMMUTABLE);
2871
2872 } else {
2873 value = handle(object->RawFastPropertyAt(index), isolate);
2874 if (!old_representation.IsDouble() && representation.IsDouble()) {
2875 if (old_representation.IsNone()) {
2876 value = handle(Smi::FromInt(0), isolate);
2877 }
2878 value = Object::NewStorageFor(isolate, value, representation);
2879 } else if (old_representation.IsDouble() &&
2880 !representation.IsDouble()) {
2881 value = Object::WrapForRead(isolate, value, old_representation);
2882 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002883 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002884 }
Emily Bernierd0a1eb72015-03-24 16:35:39 -04002885 DCHECK(!(representation.IsDouble() && value->IsSmi()));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002886 int target_index = new_descriptors->GetFieldIndex(i) - inobject;
2887 if (target_index < 0) target_index += total_size;
2888 array->set(target_index, *value);
2889 }
2890
2891 for (int i = old_nof; i < new_nof; i++) {
2892 PropertyDetails details = new_descriptors->GetDetails(i);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002893 if (details.type() != DATA) continue;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002894 Handle<Object> value;
2895 if (details.representation().IsDouble()) {
2896 value = isolate->factory()->NewHeapNumber(0, MUTABLE);
2897 } else {
2898 value = isolate->factory()->uninitialized_value();
2899 }
2900 int target_index = new_descriptors->GetFieldIndex(i) - inobject;
2901 if (target_index < 0) target_index += total_size;
2902 array->set(target_index, *value);
2903 }
2904
2905 // From here on we cannot fail and we shouldn't GC anymore.
2906 DisallowHeapAllocation no_allocation;
2907
Ben Murdoch097c5b22016-05-18 11:27:45 +01002908 Heap* heap = isolate->heap();
2909
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002910 // Copy (real) inobject properties. If necessary, stop at number_of_fields to
2911 // avoid overwriting |one_pointer_filler_map|.
2912 int limit = Min(inobject, number_of_fields);
2913 for (int i = 0; i < limit; i++) {
2914 FieldIndex index = FieldIndex::ForPropertyIndex(*new_map, i);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04002915 Object* value = array->get(external + i);
2916 // Can't use JSObject::FastPropertyAtPut() because proper map was not set
2917 // yet.
2918 if (new_map->IsUnboxedDoubleField(index)) {
2919 DCHECK(value->IsMutableHeapNumber());
2920 object->RawFastDoublePropertyAtPut(index,
2921 HeapNumber::cast(value)->value());
Ben Murdoch097c5b22016-05-18 11:27:45 +01002922 if (i < old_number_of_fields && !old_map->IsUnboxedDoubleField(index)) {
2923 // Transition from tagged to untagged slot.
2924 heap->ClearRecordedSlot(*object,
2925 HeapObject::RawField(*object, index.offset()));
2926 }
Emily Bernierd0a1eb72015-03-24 16:35:39 -04002927 } else {
2928 object->RawFastPropertyAtPut(index, value);
2929 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002930 }
2931
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002932
2933 // If there are properties in the new backing store, trim it to the correct
2934 // size and install the backing store into the object.
2935 if (external > 0) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002936 heap->RightTrimFixedArray<Heap::CONCURRENT_TO_SWEEPER>(*array, inobject);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002937 object->set_properties(*array);
2938 }
2939
2940 // Create filler object past the new instance size.
2941 int new_instance_size = new_map->instance_size();
2942 int instance_size_delta = old_map->instance_size() - new_instance_size;
2943 DCHECK(instance_size_delta >= 0);
2944
2945 if (instance_size_delta > 0) {
2946 Address address = object->address();
2947 heap->CreateFillerObjectAt(
2948 address + new_instance_size, instance_size_delta);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002949 heap->AdjustLiveBytes(*object, -instance_size_delta,
2950 Heap::CONCURRENT_TO_SWEEPER);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002951 }
2952
2953 // We are storing the new map using release store after creating a filler for
2954 // the left-over space to avoid races with the sweeper thread.
2955 object->synchronized_set_map(*new_map);
2956}
2957
Ben Murdoch097c5b22016-05-18 11:27:45 +01002958void MigrateFastToSlow(Handle<JSObject> object, Handle<Map> new_map,
2959 int expected_additional_properties) {
2960 // The global object is always normalized.
2961 DCHECK(!object->IsJSGlobalObject());
2962 // JSGlobalProxy must never be normalized
2963 DCHECK(!object->IsJSGlobalProxy());
2964
2965 Isolate* isolate = object->GetIsolate();
2966 HandleScope scope(isolate);
2967 Handle<Map> map(object->map());
2968
2969 // Allocate new content.
2970 int real_size = map->NumberOfOwnDescriptors();
2971 int property_count = real_size;
2972 if (expected_additional_properties > 0) {
2973 property_count += expected_additional_properties;
2974 } else {
2975 property_count += 2; // Make space for two more properties.
2976 }
2977 Handle<NameDictionary> dictionary =
2978 NameDictionary::New(isolate, property_count);
2979
2980 Handle<DescriptorArray> descs(map->instance_descriptors());
2981 for (int i = 0; i < real_size; i++) {
2982 PropertyDetails details = descs->GetDetails(i);
2983 Handle<Name> key(descs->GetKey(i));
2984 switch (details.type()) {
2985 case DATA_CONSTANT: {
2986 Handle<Object> value(descs->GetConstant(i), isolate);
2987 PropertyDetails d(details.attributes(), DATA, i + 1,
2988 PropertyCellType::kNoCell);
2989 dictionary = NameDictionary::Add(dictionary, key, value, d);
2990 break;
2991 }
2992 case DATA: {
2993 FieldIndex index = FieldIndex::ForDescriptor(*map, i);
2994 Handle<Object> value;
2995 if (object->IsUnboxedDoubleField(index)) {
2996 double old_value = object->RawFastDoublePropertyAt(index);
2997 value = isolate->factory()->NewHeapNumber(old_value);
2998 } else {
2999 value = handle(object->RawFastPropertyAt(index), isolate);
3000 if (details.representation().IsDouble()) {
3001 DCHECK(value->IsMutableHeapNumber());
3002 Handle<HeapNumber> old = Handle<HeapNumber>::cast(value);
3003 value = isolate->factory()->NewHeapNumber(old->value());
3004 }
3005 }
3006 PropertyDetails d(details.attributes(), DATA, i + 1,
3007 PropertyCellType::kNoCell);
3008 dictionary = NameDictionary::Add(dictionary, key, value, d);
3009 break;
3010 }
3011 case ACCESSOR: {
3012 FieldIndex index = FieldIndex::ForDescriptor(*map, i);
3013 Handle<Object> value(object->RawFastPropertyAt(index), isolate);
3014 PropertyDetails d(details.attributes(), ACCESSOR_CONSTANT, i + 1,
3015 PropertyCellType::kNoCell);
3016 dictionary = NameDictionary::Add(dictionary, key, value, d);
3017 break;
3018 }
3019 case ACCESSOR_CONSTANT: {
3020 Handle<Object> value(descs->GetCallbacksObject(i), isolate);
3021 PropertyDetails d(details.attributes(), ACCESSOR_CONSTANT, i + 1,
3022 PropertyCellType::kNoCell);
3023 dictionary = NameDictionary::Add(dictionary, key, value, d);
3024 break;
3025 }
3026 }
3027 }
3028
3029 // Copy the next enumeration index from instance descriptor.
3030 dictionary->SetNextEnumerationIndex(real_size + 1);
3031
3032 // From here on we cannot fail and we shouldn't GC anymore.
3033 DisallowHeapAllocation no_allocation;
3034
3035 // Resize the object in the heap if necessary.
3036 int new_instance_size = new_map->instance_size();
3037 int instance_size_delta = map->instance_size() - new_instance_size;
3038 DCHECK(instance_size_delta >= 0);
3039
3040 if (instance_size_delta > 0) {
3041 Heap* heap = isolate->heap();
3042 heap->CreateFillerObjectAt(object->address() + new_instance_size,
3043 instance_size_delta);
3044 heap->AdjustLiveBytes(*object, -instance_size_delta,
3045 Heap::CONCURRENT_TO_SWEEPER);
3046 }
3047
3048 // We are storing the new map using release store after creating a filler for
3049 // the left-over space to avoid races with the sweeper thread.
3050 object->synchronized_set_map(*new_map);
3051
3052 object->set_properties(*dictionary);
3053
3054 // Ensure that in-object space of slow-mode object does not contain random
3055 // garbage.
3056 int inobject_properties = new_map->GetInObjectProperties();
3057 for (int i = 0; i < inobject_properties; i++) {
3058 FieldIndex index = FieldIndex::ForPropertyIndex(*new_map, i);
3059 object->RawFastPropertyAtPut(index, Smi::FromInt(0));
3060 }
3061
3062 isolate->counters()->props_to_dictionary()->Increment();
3063
3064#ifdef DEBUG
3065 if (FLAG_trace_normalization) {
3066 OFStream os(stdout);
3067 os << "Object properties have been normalized:\n";
3068 object->Print(os);
3069 }
3070#endif
3071}
3072
3073} // namespace
3074
3075void JSObject::MigrateToMap(Handle<JSObject> object, Handle<Map> new_map,
3076 int expected_additional_properties) {
3077 if (object->map() == *new_map) return;
3078 Handle<Map> old_map(object->map());
3079 if (old_map->is_prototype_map()) {
3080 // If this object is a prototype (the callee will check), invalidate any
3081 // prototype chains involving it.
3082 InvalidatePrototypeChains(object->map());
3083
3084 // If the map was registered with its prototype before, ensure that it
3085 // registers with its new prototype now. This preserves the invariant that
3086 // when a map on a prototype chain is registered with its prototype, then
3087 // all prototypes further up the chain are also registered with their
3088 // respective prototypes.
3089 UpdatePrototypeUserRegistration(old_map, new_map, new_map->GetIsolate());
3090 }
3091
3092 if (old_map->is_dictionary_map()) {
3093 // For slow-to-fast migrations JSObject::MigrateSlowToFast()
3094 // must be used instead.
3095 CHECK(new_map->is_dictionary_map());
3096
3097 // Slow-to-slow migration is trivial.
3098 object->set_map(*new_map);
3099 } else if (!new_map->is_dictionary_map()) {
3100 MigrateFastToFast(object, new_map);
3101 if (old_map->is_prototype_map()) {
3102 DCHECK(!old_map->is_stable());
3103 DCHECK(new_map->is_stable());
3104 // Clear out the old descriptor array to avoid problems to sharing
3105 // the descriptor array without using an explicit.
3106 old_map->InitializeDescriptors(
3107 old_map->GetHeap()->empty_descriptor_array(),
3108 LayoutDescriptor::FastPointerLayout());
3109 // Ensure that no transition was inserted for prototype migrations.
3110 DCHECK_EQ(
3111 0, TransitionArray::NumberOfTransitions(old_map->raw_transitions()));
3112 DCHECK(new_map->GetBackPointer()->IsUndefined());
3113 }
3114 } else {
3115 MigrateFastToSlow(object, new_map, expected_additional_properties);
3116 }
3117
3118 // Careful: Don't allocate here!
3119 // For some callers of this method, |object| might be in an inconsistent
3120 // state now: the new map might have a new elements_kind, but the object's
3121 // elements pointer hasn't been updated yet. Callers will fix this, but in
3122 // the meantime, (indirectly) calling JSObjectVerify() must be avoided.
3123 // When adding code here, add a DisallowHeapAllocation too.
3124}
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003125
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003126int Map::NumberOfFields() {
3127 DescriptorArray* descriptors = instance_descriptors();
3128 int result = 0;
3129 for (int i = 0; i < NumberOfOwnDescriptors(); i++) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003130 if (descriptors->GetDetails(i).location() == kField) result++;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003131 }
Steve Blocka7e24c12009-10-30 11:49:00 +00003132 return result;
3133}
3134
3135
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003136Handle<Map> Map::CopyGeneralizeAllRepresentations(
3137 Handle<Map> map, int modify_index, StoreMode store_mode, PropertyKind kind,
3138 PropertyAttributes attributes, const char* reason) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003139 Isolate* isolate = map->GetIsolate();
Emily Bernierd0a1eb72015-03-24 16:35:39 -04003140 Handle<DescriptorArray> old_descriptors(map->instance_descriptors(), isolate);
3141 int number_of_own_descriptors = map->NumberOfOwnDescriptors();
3142 Handle<DescriptorArray> descriptors =
3143 DescriptorArray::CopyUpTo(old_descriptors, number_of_own_descriptors);
Steve Blocka7e24c12009-10-30 11:49:00 +00003144
Emily Bernierd0a1eb72015-03-24 16:35:39 -04003145 for (int i = 0; i < number_of_own_descriptors; i++) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003146 descriptors->SetRepresentation(i, Representation::Tagged());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003147 if (descriptors->GetDetails(i).type() == DATA) {
Ben Murdoch097c5b22016-05-18 11:27:45 +01003148 descriptors->SetValue(i, FieldType::Any());
John Reck59135872010-11-02 12:39:01 -07003149 }
3150 }
Steve Blocka7e24c12009-10-30 11:49:00 +00003151
Emily Bernierd0a1eb72015-03-24 16:35:39 -04003152 Handle<LayoutDescriptor> new_layout_descriptor(
3153 LayoutDescriptor::FastPointerLayout(), isolate);
3154 Handle<Map> new_map = CopyReplaceDescriptors(
3155 map, descriptors, new_layout_descriptor, OMIT_TRANSITION,
3156 MaybeHandle<Name>(), reason, SPECIAL_TRANSITION);
3157
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003158 // Unless the instance is being migrated, ensure that modify_index is a field.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003159 if (modify_index >= 0) {
3160 PropertyDetails details = descriptors->GetDetails(modify_index);
3161 if (store_mode == FORCE_FIELD &&
3162 (details.type() != DATA || details.attributes() != attributes)) {
3163 int field_index = details.type() == DATA ? details.field_index()
3164 : new_map->NumberOfFields();
3165 DataDescriptor d(handle(descriptors->GetKey(modify_index), isolate),
3166 field_index, attributes, Representation::Tagged());
3167 descriptors->Replace(modify_index, &d);
3168 if (details.type() != DATA) {
3169 int unused_property_fields = new_map->unused_property_fields() - 1;
3170 if (unused_property_fields < 0) {
3171 unused_property_fields += JSObject::kFieldsAdded;
3172 }
3173 new_map->set_unused_property_fields(unused_property_fields);
John Reck59135872010-11-02 12:39:01 -07003174 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003175 } else {
3176 DCHECK(details.attributes() == attributes);
John Reck59135872010-11-02 12:39:01 -07003177 }
Steve Blocka7e24c12009-10-30 11:49:00 +00003178
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003179 if (FLAG_trace_generalization) {
Ben Murdoch097c5b22016-05-18 11:27:45 +01003180 MaybeHandle<FieldType> field_type = FieldType::None(isolate);
3181 if (details.type() == DATA) {
3182 field_type = handle(
3183 map->instance_descriptors()->GetFieldType(modify_index), isolate);
3184 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003185 map->PrintGeneralization(
3186 stdout, reason, modify_index, new_map->NumberOfOwnDescriptors(),
3187 new_map->NumberOfOwnDescriptors(),
3188 details.type() == DATA_CONSTANT && store_mode == FORCE_FIELD,
3189 details.representation(), Representation::Tagged(), field_type,
Ben Murdoch097c5b22016-05-18 11:27:45 +01003190 MaybeHandle<Object>(), FieldType::Any(isolate),
3191 MaybeHandle<Object>());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003192 }
Steve Blocka7e24c12009-10-30 11:49:00 +00003193 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003194 return new_map;
Steve Blocka7e24c12009-10-30 11:49:00 +00003195}
3196
3197
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003198void Map::DeprecateTransitionTree() {
3199 if (is_deprecated()) return;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003200 Object* transitions = raw_transitions();
3201 int num_transitions = TransitionArray::NumberOfTransitions(transitions);
3202 for (int i = 0; i < num_transitions; ++i) {
3203 TransitionArray::GetTarget(transitions, i)->DeprecateTransitionTree();
Steve Blocka7e24c12009-10-30 11:49:00 +00003204 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003205 deprecate();
3206 dependent_code()->DeoptimizeDependentCodeGroup(
3207 GetIsolate(), DependentCode::kTransitionGroup);
3208 NotifyLeafMapLayoutChange();
Steve Blocka7e24c12009-10-30 11:49:00 +00003209}
3210
3211
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003212static inline bool EqualImmutableValues(Object* obj1, Object* obj2) {
3213 if (obj1 == obj2) return true; // Valid for both kData and kAccessor kinds.
3214 // TODO(ishell): compare AccessorPairs.
3215 return false;
3216}
Steve Blocka7e24c12009-10-30 11:49:00 +00003217
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003218
3219// Installs |new_descriptors| over the current instance_descriptors to ensure
3220// proper sharing of descriptor arrays.
3221void Map::ReplaceDescriptors(DescriptorArray* new_descriptors,
3222 LayoutDescriptor* new_layout_descriptor) {
3223 // Don't overwrite the empty descriptor array or initial map's descriptors.
3224 if (NumberOfOwnDescriptors() == 0 || GetBackPointer()->IsUndefined()) {
3225 return;
3226 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003227
3228 DescriptorArray* to_replace = instance_descriptors();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003229 GetHeap()->incremental_marking()->RecordWrites(to_replace);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003230 Map* current = this;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003231 while (current->instance_descriptors() == to_replace) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003232 Object* next = current->GetBackPointer();
3233 if (next->IsUndefined()) break; // Stop overwriting at initial map.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003234 current->SetEnumLength(kInvalidEnumCacheSentinel);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04003235 current->UpdateDescriptors(new_descriptors, new_layout_descriptor);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003236 current = Map::cast(next);
3237 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003238 set_owns_descriptors(false);
3239}
3240
3241
3242Map* Map::FindRootMap() {
3243 Map* result = this;
3244 while (true) {
3245 Object* back = result->GetBackPointer();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003246 if (back->IsUndefined()) {
3247 // Initial map always owns descriptors and doesn't have unused entries
3248 // in the descriptor array.
3249 DCHECK(result->owns_descriptors());
3250 DCHECK_EQ(result->NumberOfOwnDescriptors(),
3251 result->instance_descriptors()->number_of_descriptors());
3252 return result;
3253 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003254 result = Map::cast(back);
3255 }
3256}
3257
3258
3259Map* Map::FindLastMatchMap(int verbatim,
3260 int length,
3261 DescriptorArray* descriptors) {
3262 DisallowHeapAllocation no_allocation;
3263
3264 // This can only be called on roots of transition trees.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003265 DCHECK_EQ(verbatim, NumberOfOwnDescriptors());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003266
3267 Map* current = this;
3268
3269 for (int i = verbatim; i < length; i++) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003270 Name* name = descriptors->GetKey(i);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04003271 PropertyDetails details = descriptors->GetDetails(i);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003272 Map* next = TransitionArray::SearchTransition(current, details.kind(), name,
3273 details.attributes());
3274 if (next == NULL) break;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003275 DescriptorArray* next_descriptors = next->instance_descriptors();
3276
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003277 PropertyDetails next_details = next_descriptors->GetDetails(i);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003278 DCHECK_EQ(details.kind(), next_details.kind());
3279 DCHECK_EQ(details.attributes(), next_details.attributes());
3280 if (details.location() != next_details.location()) break;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003281 if (!details.representation().Equals(next_details.representation())) break;
Steve Blocka7e24c12009-10-30 11:49:00 +00003282
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003283 if (next_details.location() == kField) {
Ben Murdoch097c5b22016-05-18 11:27:45 +01003284 FieldType* next_field_type = next_descriptors->GetFieldType(i);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003285 if (!descriptors->GetFieldType(i)->NowIs(next_field_type)) {
3286 break;
3287 }
3288 } else {
3289 if (!EqualImmutableValues(descriptors->GetValue(i),
3290 next_descriptors->GetValue(i))) {
3291 break;
3292 }
3293 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003294 current = next;
3295 }
3296 return current;
Steve Blocka7e24c12009-10-30 11:49:00 +00003297}
3298
3299
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003300Map* Map::FindFieldOwner(int descriptor) {
3301 DisallowHeapAllocation no_allocation;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003302 DCHECK_EQ(DATA, instance_descriptors()->GetDetails(descriptor).type());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003303 Map* result = this;
3304 while (true) {
3305 Object* back = result->GetBackPointer();
3306 if (back->IsUndefined()) break;
3307 Map* parent = Map::cast(back);
3308 if (parent->NumberOfOwnDescriptors() <= descriptor) break;
3309 result = parent;
Steve Blocka7e24c12009-10-30 11:49:00 +00003310 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003311 return result;
Steve Blocka7e24c12009-10-30 11:49:00 +00003312}
3313
3314
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003315void Map::UpdateFieldType(int descriptor, Handle<Name> name,
Emily Bernierd0a1eb72015-03-24 16:35:39 -04003316 Representation new_representation,
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003317 Handle<Object> new_wrapped_type) {
3318 DCHECK(new_wrapped_type->IsSmi() || new_wrapped_type->IsWeakCell());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003319 DisallowHeapAllocation no_allocation;
3320 PropertyDetails details = instance_descriptors()->GetDetails(descriptor);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003321 if (details.type() != DATA) return;
3322 Object* transitions = raw_transitions();
3323 int num_transitions = TransitionArray::NumberOfTransitions(transitions);
3324 for (int i = 0; i < num_transitions; ++i) {
3325 Map* target = TransitionArray::GetTarget(transitions, i);
3326 target->UpdateFieldType(descriptor, name, new_representation,
3327 new_wrapped_type);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003328 }
Emily Bernierd0a1eb72015-03-24 16:35:39 -04003329 // It is allowed to change representation here only from None to something.
3330 DCHECK(details.representation().Equals(new_representation) ||
3331 details.representation().IsNone());
3332
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003333 // Skip if already updated the shared descriptor.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003334 if (instance_descriptors()->GetValue(descriptor) == *new_wrapped_type) return;
3335 DataDescriptor d(name, instance_descriptors()->GetFieldIndex(descriptor),
3336 new_wrapped_type, details.attributes(), new_representation);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003337 instance_descriptors()->Replace(descriptor, &d);
3338}
3339
Ben Murdoch097c5b22016-05-18 11:27:45 +01003340bool FieldTypeIsCleared(Representation rep, FieldType* type) {
3341 return type->IsNone() && rep.IsHeapObject();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003342}
3343
3344
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003345// static
Ben Murdoch097c5b22016-05-18 11:27:45 +01003346Handle<FieldType> Map::GeneralizeFieldType(Representation rep1,
3347 Handle<FieldType> type1,
3348 Representation rep2,
3349 Handle<FieldType> type2,
3350 Isolate* isolate) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003351 // Cleared field types need special treatment. They represent lost knowledge,
3352 // so we must be conservative, so their generalization with any other type
3353 // is "Any".
3354 if (FieldTypeIsCleared(rep1, *type1) || FieldTypeIsCleared(rep2, *type2)) {
Ben Murdoch097c5b22016-05-18 11:27:45 +01003355 return FieldType::Any(isolate);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003356 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003357 if (type1->NowIs(type2)) return type2;
3358 if (type2->NowIs(type1)) return type1;
Ben Murdoch097c5b22016-05-18 11:27:45 +01003359 return FieldType::Any(isolate);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003360}
3361
3362
3363// static
Emily Bernierd0a1eb72015-03-24 16:35:39 -04003364void Map::GeneralizeFieldType(Handle<Map> map, int modify_index,
3365 Representation new_representation,
Ben Murdoch097c5b22016-05-18 11:27:45 +01003366 Handle<FieldType> new_field_type) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003367 Isolate* isolate = map->GetIsolate();
3368
3369 // Check if we actually need to generalize the field type at all.
Emily Bernierd0a1eb72015-03-24 16:35:39 -04003370 Handle<DescriptorArray> old_descriptors(map->instance_descriptors(), isolate);
3371 Representation old_representation =
3372 old_descriptors->GetDetails(modify_index).representation();
Ben Murdoch097c5b22016-05-18 11:27:45 +01003373 Handle<FieldType> old_field_type(old_descriptors->GetFieldType(modify_index),
3374 isolate);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04003375
3376 if (old_representation.Equals(new_representation) &&
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003377 !FieldTypeIsCleared(new_representation, *new_field_type) &&
3378 // Checking old_field_type for being cleared is not necessary because
3379 // the NowIs check below would fail anyway in that case.
Emily Bernierd0a1eb72015-03-24 16:35:39 -04003380 new_field_type->NowIs(old_field_type)) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003381 DCHECK(Map::GeneralizeFieldType(old_representation, old_field_type,
3382 new_representation, new_field_type, isolate)
3383 ->NowIs(old_field_type));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003384 return;
3385 }
3386
3387 // Determine the field owner.
3388 Handle<Map> field_owner(map->FindFieldOwner(modify_index), isolate);
3389 Handle<DescriptorArray> descriptors(
3390 field_owner->instance_descriptors(), isolate);
3391 DCHECK_EQ(*old_field_type, descriptors->GetFieldType(modify_index));
3392
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003393 new_field_type =
3394 Map::GeneralizeFieldType(old_representation, old_field_type,
3395 new_representation, new_field_type, isolate);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003396
3397 PropertyDetails details = descriptors->GetDetails(modify_index);
3398 Handle<Name> name(descriptors->GetKey(modify_index));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003399
3400 Handle<Object> wrapped_type(WrapType(new_field_type));
Emily Bernierd0a1eb72015-03-24 16:35:39 -04003401 field_owner->UpdateFieldType(modify_index, name, new_representation,
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003402 wrapped_type);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003403 field_owner->dependent_code()->DeoptimizeDependentCodeGroup(
3404 isolate, DependentCode::kFieldTypeGroup);
3405
3406 if (FLAG_trace_generalization) {
3407 map->PrintGeneralization(
Ben Murdoch097c5b22016-05-18 11:27:45 +01003408 stdout, "field type generalization", modify_index,
3409 map->NumberOfOwnDescriptors(), map->NumberOfOwnDescriptors(), false,
3410 details.representation(), details.representation(), old_field_type,
3411 MaybeHandle<Object>(), new_field_type, MaybeHandle<Object>());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003412 }
3413}
3414
Ben Murdoch097c5b22016-05-18 11:27:45 +01003415static inline Handle<FieldType> GetFieldType(
3416 Isolate* isolate, Handle<DescriptorArray> descriptors, int descriptor,
3417 PropertyLocation location, Representation representation) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003418#ifdef DEBUG
3419 PropertyDetails details = descriptors->GetDetails(descriptor);
3420 DCHECK_EQ(kData, details.kind());
3421 DCHECK_EQ(details.location(), location);
3422#endif
3423 if (location == kField) {
3424 return handle(descriptors->GetFieldType(descriptor), isolate);
3425 } else {
3426 return descriptors->GetValue(descriptor)
3427 ->OptimalType(isolate, representation);
3428 }
3429}
3430
3431
3432// Reconfigures property at |modify_index| with |new_kind|, |new_attributes|,
3433// |store_mode| and/or |new_representation|/|new_field_type|.
3434// If |modify_index| is negative then no properties are reconfigured but the
3435// map is migrated to the up-to-date non-deprecated state.
3436//
3437// This method rewrites or completes the transition tree to reflect the new
3438// change. To avoid high degrees over polymorphism, and to stabilize quickly,
3439// on every rewrite the new type is deduced by merging the current type with
3440// any potential new (partial) version of the type in the transition tree.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003441// To do this, on each rewrite:
3442// - Search the root of the transition tree using FindRootMap.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003443// - Find |target_map|, the newest matching version of this map using the
3444// virtually "enhanced" |old_map|'s descriptor array (i.e. whose entry at
3445// |modify_index| is considered to be of |new_kind| and having
3446// |new_attributes|) to walk the transition tree.
3447// - Merge/generalize the "enhanced" descriptor array of the |old_map| and
3448// descriptor array of the |target_map|.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003449// - Generalize the |modify_index| descriptor using |new_representation| and
3450// |new_field_type|.
3451// - Walk the tree again starting from the root towards |target_map|. Stop at
3452// |split_map|, the first map who's descriptor array does not match the merged
3453// descriptor array.
3454// - If |target_map| == |split_map|, |target_map| is in the expected state.
3455// Return it.
3456// - Otherwise, invalidate the outdated transition target from |target_map|, and
3457// replace its transition tree with a new branch for the updated descriptors.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003458Handle<Map> Map::ReconfigureProperty(Handle<Map> old_map, int modify_index,
3459 PropertyKind new_kind,
3460 PropertyAttributes new_attributes,
3461 Representation new_representation,
Ben Murdoch097c5b22016-05-18 11:27:45 +01003462 Handle<FieldType> new_field_type,
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003463 StoreMode store_mode) {
3464 DCHECK_NE(kAccessor, new_kind); // TODO(ishell): not supported yet.
3465 DCHECK(store_mode != FORCE_FIELD || modify_index >= 0);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003466 Isolate* isolate = old_map->GetIsolate();
3467
3468 Handle<DescriptorArray> old_descriptors(
3469 old_map->instance_descriptors(), isolate);
3470 int old_nof = old_map->NumberOfOwnDescriptors();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003471
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003472 // If it's just a representation generalization case (i.e. property kind and
3473 // attributes stays unchanged) it's fine to transition from None to anything
3474 // but double without any modification to the object, because the default
3475 // uninitialized value for representation None can be overwritten by both
3476 // smi and tagged values. Doubles, however, would require a box allocation.
3477 if (modify_index >= 0 && !new_representation.IsNone() &&
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003478 !new_representation.IsDouble()) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003479 PropertyDetails old_details = old_descriptors->GetDetails(modify_index);
3480 Representation old_representation = old_details.representation();
Emily Bernierd0a1eb72015-03-24 16:35:39 -04003481
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003482 if (old_representation.IsNone()) {
3483 DCHECK_EQ(new_kind, old_details.kind());
3484 DCHECK_EQ(new_attributes, old_details.attributes());
3485 DCHECK_EQ(DATA, old_details.type());
3486 if (FLAG_trace_generalization) {
3487 old_map->PrintGeneralization(
3488 stdout, "uninitialized field", modify_index,
3489 old_map->NumberOfOwnDescriptors(),
3490 old_map->NumberOfOwnDescriptors(), false, old_representation,
Ben Murdoch097c5b22016-05-18 11:27:45 +01003491 new_representation,
3492 handle(old_descriptors->GetFieldType(modify_index), isolate),
3493 MaybeHandle<Object>(), new_field_type, MaybeHandle<Object>());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003494 }
3495 Handle<Map> field_owner(old_map->FindFieldOwner(modify_index), isolate);
3496
3497 GeneralizeFieldType(field_owner, modify_index, new_representation,
3498 new_field_type);
3499 DCHECK(old_descriptors->GetDetails(modify_index)
3500 .representation()
3501 .Equals(new_representation));
3502 DCHECK(
3503 old_descriptors->GetFieldType(modify_index)->NowIs(new_field_type));
3504 return old_map;
3505 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003506 }
3507
3508 // Check the state of the root map.
3509 Handle<Map> root_map(old_map->FindRootMap(), isolate);
3510 if (!old_map->EquivalentToForTransition(*root_map)) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -04003511 return CopyGeneralizeAllRepresentations(old_map, modify_index, store_mode,
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003512 new_kind, new_attributes,
Emily Bernierd0a1eb72015-03-24 16:35:39 -04003513 "GenAll_NotEquivalent");
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003514 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003515
3516 ElementsKind from_kind = root_map->elements_kind();
3517 ElementsKind to_kind = old_map->elements_kind();
3518 // TODO(ishell): Add a test for SLOW_SLOPPY_ARGUMENTS_ELEMENTS.
3519 if (from_kind != to_kind && to_kind != DICTIONARY_ELEMENTS &&
3520 to_kind != SLOW_SLOPPY_ARGUMENTS_ELEMENTS &&
3521 !(IsTransitionableFastElementsKind(from_kind) &&
3522 IsMoreGeneralElementsKindTransition(from_kind, to_kind))) {
3523 return CopyGeneralizeAllRepresentations(old_map, modify_index, store_mode,
3524 new_kind, new_attributes,
3525 "GenAll_InvalidElementsTransition");
3526 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003527 int root_nof = root_map->NumberOfOwnDescriptors();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003528 if (modify_index >= 0 && modify_index < root_nof) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003529 PropertyDetails old_details = old_descriptors->GetDetails(modify_index);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003530 if (old_details.kind() != new_kind ||
3531 old_details.attributes() != new_attributes) {
3532 return CopyGeneralizeAllRepresentations(old_map, modify_index, store_mode,
3533 new_kind, new_attributes,
3534 "GenAll_RootModification1");
3535 }
3536 if ((old_details.type() != DATA && store_mode == FORCE_FIELD) ||
3537 (old_details.type() == DATA &&
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003538 (!new_field_type->NowIs(old_descriptors->GetFieldType(modify_index)) ||
3539 !new_representation.fits_into(old_details.representation())))) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -04003540 return CopyGeneralizeAllRepresentations(old_map, modify_index, store_mode,
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003541 new_kind, new_attributes,
3542 "GenAll_RootModification2");
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003543 }
3544 }
3545
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003546 // From here on, use the map with correct elements kind as root map.
3547 if (from_kind != to_kind) {
3548 root_map = Map::AsElementsKind(root_map, to_kind);
3549 }
3550
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003551 Handle<Map> target_map = root_map;
3552 for (int i = root_nof; i < old_nof; ++i) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -04003553 PropertyDetails old_details = old_descriptors->GetDetails(i);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003554 PropertyKind next_kind;
3555 PropertyLocation next_location;
3556 PropertyAttributes next_attributes;
3557 Representation next_representation;
3558 bool property_kind_reconfiguration = false;
3559
3560 if (modify_index == i) {
3561 DCHECK_EQ(FORCE_FIELD, store_mode);
3562 property_kind_reconfiguration = old_details.kind() != new_kind;
3563
3564 next_kind = new_kind;
3565 next_location = kField;
3566 next_attributes = new_attributes;
3567 // If property kind is not reconfigured merge the result with
3568 // representation/field type from the old descriptor.
3569 next_representation = new_representation;
3570 if (!property_kind_reconfiguration) {
3571 next_representation =
3572 next_representation.generalize(old_details.representation());
3573 }
3574
3575 } else {
3576 next_kind = old_details.kind();
3577 next_location = old_details.location();
3578 next_attributes = old_details.attributes();
3579 next_representation = old_details.representation();
3580 }
3581 Map* transition = TransitionArray::SearchTransition(
3582 *target_map, next_kind, old_descriptors->GetKey(i), next_attributes);
3583 if (transition == NULL) break;
3584 Handle<Map> tmp_map(transition, isolate);
3585
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003586 Handle<DescriptorArray> tmp_descriptors = handle(
3587 tmp_map->instance_descriptors(), isolate);
3588
3589 // Check if target map is incompatible.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003590 PropertyDetails tmp_details = tmp_descriptors->GetDetails(i);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003591 DCHECK_EQ(next_kind, tmp_details.kind());
3592 DCHECK_EQ(next_attributes, tmp_details.attributes());
3593 if (next_kind == kAccessor &&
3594 !EqualImmutableValues(old_descriptors->GetValue(i),
3595 tmp_descriptors->GetValue(i))) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -04003596 return CopyGeneralizeAllRepresentations(old_map, modify_index, store_mode,
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003597 new_kind, new_attributes,
Emily Bernierd0a1eb72015-03-24 16:35:39 -04003598 "GenAll_Incompatible");
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003599 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003600 if (next_location == kField && tmp_details.location() == kDescriptor) break;
3601
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003602 Representation tmp_representation = tmp_details.representation();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003603 if (!next_representation.fits_into(tmp_representation)) break;
3604
3605 PropertyLocation old_location = old_details.location();
3606 PropertyLocation tmp_location = tmp_details.location();
3607 if (tmp_location == kField) {
3608 if (next_kind == kData) {
Ben Murdoch097c5b22016-05-18 11:27:45 +01003609 Handle<FieldType> next_field_type;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003610 if (modify_index == i) {
3611 next_field_type = new_field_type;
3612 if (!property_kind_reconfiguration) {
Ben Murdoch097c5b22016-05-18 11:27:45 +01003613 Handle<FieldType> old_field_type =
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003614 GetFieldType(isolate, old_descriptors, i,
3615 old_details.location(), tmp_representation);
3616 Representation old_representation = old_details.representation();
3617 next_field_type = GeneralizeFieldType(
3618 old_representation, old_field_type, new_representation,
3619 next_field_type, isolate);
3620 }
3621 } else {
Ben Murdoch097c5b22016-05-18 11:27:45 +01003622 Handle<FieldType> old_field_type =
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003623 GetFieldType(isolate, old_descriptors, i, old_details.location(),
3624 tmp_representation);
3625 next_field_type = old_field_type;
3626 }
3627 GeneralizeFieldType(tmp_map, i, tmp_representation, next_field_type);
3628 }
3629 } else if (old_location == kField ||
3630 !EqualImmutableValues(old_descriptors->GetValue(i),
3631 tmp_descriptors->GetValue(i))) {
Ben Murdoch7d3e7fc2011-07-12 16:37:06 +01003632 break;
Steve Blocka7e24c12009-10-30 11:49:00 +00003633 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003634 DCHECK(!tmp_map->is_deprecated());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003635 target_map = tmp_map;
Steve Blocka7e24c12009-10-30 11:49:00 +00003636 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003637
3638 // Directly change the map if the target map is more general.
3639 Handle<DescriptorArray> target_descriptors(
3640 target_map->instance_descriptors(), isolate);
3641 int target_nof = target_map->NumberOfOwnDescriptors();
3642 if (target_nof == old_nof &&
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003643 (store_mode != FORCE_FIELD ||
3644 (modify_index >= 0 &&
3645 target_descriptors->GetDetails(modify_index).location() == kField))) {
3646#ifdef DEBUG
3647 if (modify_index >= 0) {
3648 PropertyDetails details = target_descriptors->GetDetails(modify_index);
3649 DCHECK_EQ(new_kind, details.kind());
3650 DCHECK_EQ(new_attributes, details.attributes());
3651 DCHECK(new_representation.fits_into(details.representation()));
3652 DCHECK(details.location() != kField ||
3653 new_field_type->NowIs(
3654 target_descriptors->GetFieldType(modify_index)));
3655 }
3656#endif
3657 if (*target_map != *old_map) {
3658 old_map->NotifyLeafMapLayoutChange();
3659 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003660 return target_map;
3661 }
3662
3663 // Find the last compatible target map in the transition tree.
3664 for (int i = target_nof; i < old_nof; ++i) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -04003665 PropertyDetails old_details = old_descriptors->GetDetails(i);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003666 PropertyKind next_kind;
3667 PropertyAttributes next_attributes;
3668 if (modify_index == i) {
3669 next_kind = new_kind;
3670 next_attributes = new_attributes;
3671 } else {
3672 next_kind = old_details.kind();
3673 next_attributes = old_details.attributes();
3674 }
3675 Map* transition = TransitionArray::SearchTransition(
3676 *target_map, next_kind, old_descriptors->GetKey(i), next_attributes);
3677 if (transition == NULL) break;
3678 Handle<Map> tmp_map(transition, isolate);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003679 Handle<DescriptorArray> tmp_descriptors(
3680 tmp_map->instance_descriptors(), isolate);
3681
3682 // Check if target map is compatible.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003683#ifdef DEBUG
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003684 PropertyDetails tmp_details = tmp_descriptors->GetDetails(i);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003685 DCHECK_EQ(next_kind, tmp_details.kind());
3686 DCHECK_EQ(next_attributes, tmp_details.attributes());
3687#endif
3688 if (next_kind == kAccessor &&
3689 !EqualImmutableValues(old_descriptors->GetValue(i),
3690 tmp_descriptors->GetValue(i))) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -04003691 return CopyGeneralizeAllRepresentations(old_map, modify_index, store_mode,
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003692 new_kind, new_attributes,
Emily Bernierd0a1eb72015-03-24 16:35:39 -04003693 "GenAll_Incompatible");
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003694 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003695 DCHECK(!tmp_map->is_deprecated());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003696 target_map = tmp_map;
3697 }
3698 target_nof = target_map->NumberOfOwnDescriptors();
3699 target_descriptors = handle(target_map->instance_descriptors(), isolate);
3700
3701 // Allocate a new descriptor array large enough to hold the required
3702 // descriptors, with minimally the exact same size as the old descriptor
3703 // array.
3704 int new_slack = Max(
3705 old_nof, old_descriptors->number_of_descriptors()) - old_nof;
3706 Handle<DescriptorArray> new_descriptors = DescriptorArray::Allocate(
3707 isolate, old_nof, new_slack);
3708 DCHECK(new_descriptors->length() > target_descriptors->length() ||
3709 new_descriptors->NumberOfSlackDescriptors() > 0 ||
3710 new_descriptors->number_of_descriptors() ==
3711 old_descriptors->number_of_descriptors());
3712 DCHECK(new_descriptors->number_of_descriptors() == old_nof);
3713
3714 // 0 -> |root_nof|
3715 int current_offset = 0;
3716 for (int i = 0; i < root_nof; ++i) {
3717 PropertyDetails old_details = old_descriptors->GetDetails(i);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003718 if (old_details.location() == kField) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -04003719 current_offset += old_details.field_width_in_words();
3720 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003721 Descriptor d(handle(old_descriptors->GetKey(i), isolate),
3722 handle(old_descriptors->GetValue(i), isolate),
3723 old_details);
3724 new_descriptors->Set(i, &d);
3725 }
3726
3727 // |root_nof| -> |target_nof|
3728 for (int i = root_nof; i < target_nof; ++i) {
3729 Handle<Name> target_key(target_descriptors->GetKey(i), isolate);
3730 PropertyDetails old_details = old_descriptors->GetDetails(i);
3731 PropertyDetails target_details = target_descriptors->GetDetails(i);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003732
3733 PropertyKind next_kind;
3734 PropertyAttributes next_attributes;
3735 PropertyLocation next_location;
3736 Representation next_representation;
3737 bool property_kind_reconfiguration = false;
3738
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003739 if (modify_index == i) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003740 DCHECK_EQ(FORCE_FIELD, store_mode);
3741 property_kind_reconfiguration = old_details.kind() != new_kind;
3742
3743 next_kind = new_kind;
3744 next_attributes = new_attributes;
3745 next_location = kField;
3746
3747 // Merge new representation/field type with ones from the target
3748 // descriptor. If property kind is not reconfigured merge the result with
3749 // representation/field type from the old descriptor.
3750 next_representation =
3751 new_representation.generalize(target_details.representation());
3752 if (!property_kind_reconfiguration) {
3753 next_representation =
3754 next_representation.generalize(old_details.representation());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003755 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003756 } else {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003757 // Merge old_descriptor and target_descriptor entries.
3758 DCHECK_EQ(target_details.kind(), old_details.kind());
3759 next_kind = target_details.kind();
3760 next_attributes = target_details.attributes();
3761 next_location =
3762 old_details.location() == kField ||
3763 target_details.location() == kField ||
3764 !EqualImmutableValues(target_descriptors->GetValue(i),
3765 old_descriptors->GetValue(i))
3766 ? kField
3767 : kDescriptor;
3768
3769 next_representation = old_details.representation().generalize(
3770 target_details.representation());
3771 }
3772 DCHECK_EQ(next_kind, target_details.kind());
3773 DCHECK_EQ(next_attributes, target_details.attributes());
3774
3775 if (next_location == kField) {
3776 if (next_kind == kData) {
Ben Murdoch097c5b22016-05-18 11:27:45 +01003777 Handle<FieldType> target_field_type =
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003778 GetFieldType(isolate, target_descriptors, i,
3779 target_details.location(), next_representation);
3780
Ben Murdoch097c5b22016-05-18 11:27:45 +01003781 Handle<FieldType> next_field_type;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003782 if (modify_index == i) {
3783 next_field_type = GeneralizeFieldType(
3784 target_details.representation(), target_field_type,
3785 new_representation, new_field_type, isolate);
3786 if (!property_kind_reconfiguration) {
Ben Murdoch097c5b22016-05-18 11:27:45 +01003787 Handle<FieldType> old_field_type =
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003788 GetFieldType(isolate, old_descriptors, i,
3789 old_details.location(), next_representation);
3790 next_field_type = GeneralizeFieldType(
3791 old_details.representation(), old_field_type,
3792 next_representation, next_field_type, isolate);
3793 }
3794 } else {
Ben Murdoch097c5b22016-05-18 11:27:45 +01003795 Handle<FieldType> old_field_type =
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003796 GetFieldType(isolate, old_descriptors, i, old_details.location(),
3797 next_representation);
3798 next_field_type = GeneralizeFieldType(
3799 old_details.representation(), old_field_type, next_representation,
3800 target_field_type, isolate);
3801 }
3802 Handle<Object> wrapped_type(WrapType(next_field_type));
3803 DataDescriptor d(target_key, current_offset, wrapped_type,
3804 next_attributes, next_representation);
3805 current_offset += d.GetDetails().field_width_in_words();
3806 new_descriptors->Set(i, &d);
3807 } else {
3808 UNIMPLEMENTED(); // TODO(ishell): implement.
3809 }
3810 } else {
3811 PropertyDetails details(next_attributes, next_kind, next_location,
3812 next_representation);
3813 Descriptor d(target_key, handle(target_descriptors->GetValue(i), isolate),
3814 details);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003815 new_descriptors->Set(i, &d);
3816 }
3817 }
3818
3819 // |target_nof| -> |old_nof|
3820 for (int i = target_nof; i < old_nof; ++i) {
3821 PropertyDetails old_details = old_descriptors->GetDetails(i);
3822 Handle<Name> old_key(old_descriptors->GetKey(i), isolate);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003823
3824 // Merge old_descriptor entry and modified details together.
3825 PropertyKind next_kind;
3826 PropertyAttributes next_attributes;
3827 PropertyLocation next_location;
3828 Representation next_representation;
3829 bool property_kind_reconfiguration = false;
3830
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003831 if (modify_index == i) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003832 DCHECK_EQ(FORCE_FIELD, store_mode);
3833 // In case of property kind reconfiguration it is not necessary to
3834 // take into account representation/field type of the old descriptor.
3835 property_kind_reconfiguration = old_details.kind() != new_kind;
3836
3837 next_kind = new_kind;
3838 next_attributes = new_attributes;
3839 next_location = kField;
3840 next_representation = new_representation;
3841 if (!property_kind_reconfiguration) {
3842 next_representation =
3843 next_representation.generalize(old_details.representation());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003844 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003845 } else {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003846 next_kind = old_details.kind();
3847 next_attributes = old_details.attributes();
3848 next_location = old_details.location();
3849 next_representation = old_details.representation();
3850 }
3851
3852 if (next_location == kField) {
3853 if (next_kind == kData) {
Ben Murdoch097c5b22016-05-18 11:27:45 +01003854 Handle<FieldType> next_field_type;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003855 if (modify_index == i) {
3856 next_field_type = new_field_type;
3857 if (!property_kind_reconfiguration) {
Ben Murdoch097c5b22016-05-18 11:27:45 +01003858 Handle<FieldType> old_field_type =
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003859 GetFieldType(isolate, old_descriptors, i,
3860 old_details.location(), next_representation);
3861 next_field_type = GeneralizeFieldType(
3862 old_details.representation(), old_field_type,
3863 next_representation, next_field_type, isolate);
3864 }
3865 } else {
Ben Murdoch097c5b22016-05-18 11:27:45 +01003866 Handle<FieldType> old_field_type =
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003867 GetFieldType(isolate, old_descriptors, i, old_details.location(),
3868 next_representation);
3869 next_field_type = old_field_type;
3870 }
3871
3872 Handle<Object> wrapped_type(WrapType(next_field_type));
3873
3874 DataDescriptor d(old_key, current_offset, wrapped_type, next_attributes,
3875 next_representation);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04003876 current_offset += d.GetDetails().field_width_in_words();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003877 new_descriptors->Set(i, &d);
3878 } else {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003879 UNIMPLEMENTED(); // TODO(ishell): implement.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003880 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003881 } else {
3882 PropertyDetails details(next_attributes, next_kind, next_location,
3883 next_representation);
3884 Descriptor d(old_key, handle(old_descriptors->GetValue(i), isolate),
3885 details);
3886 new_descriptors->Set(i, &d);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003887 }
3888 }
3889
3890 new_descriptors->Sort();
3891
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003892 DCHECK(store_mode != FORCE_FIELD ||
3893 new_descriptors->GetDetails(modify_index).location() == kField);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003894
3895 Handle<Map> split_map(root_map->FindLastMatchMap(
3896 root_nof, old_nof, *new_descriptors), isolate);
3897 int split_nof = split_map->NumberOfOwnDescriptors();
3898 DCHECK_NE(old_nof, split_nof);
3899
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003900 PropertyKind split_kind;
3901 PropertyAttributes split_attributes;
3902 if (modify_index == split_nof) {
3903 split_kind = new_kind;
3904 split_attributes = new_attributes;
3905 } else {
3906 PropertyDetails split_prop_details = old_descriptors->GetDetails(split_nof);
3907 split_kind = split_prop_details.kind();
3908 split_attributes = split_prop_details.attributes();
3909 }
Emily Bernierd0a1eb72015-03-24 16:35:39 -04003910
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003911 // Invalidate a transition target at |key|.
3912 Map* maybe_transition = TransitionArray::SearchTransition(
3913 *split_map, split_kind, old_descriptors->GetKey(split_nof),
3914 split_attributes);
3915 if (maybe_transition != NULL) {
3916 maybe_transition->DeprecateTransitionTree();
3917 }
3918
3919 // If |maybe_transition| is not NULL then the transition array already
3920 // contains entry for given descriptor. This means that the transition
Emily Bernierd0a1eb72015-03-24 16:35:39 -04003921 // could be inserted regardless of whether transitions array is full or not.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003922 if (maybe_transition == NULL &&
3923 !TransitionArray::CanHaveMoreTransitions(split_map)) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -04003924 return CopyGeneralizeAllRepresentations(old_map, modify_index, store_mode,
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003925 new_kind, new_attributes,
Emily Bernierd0a1eb72015-03-24 16:35:39 -04003926 "GenAll_CantHaveMoreTransitions");
3927 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003928
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003929 old_map->NotifyLeafMapLayoutChange();
3930
3931 if (FLAG_trace_generalization && modify_index >= 0) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003932 PropertyDetails old_details = old_descriptors->GetDetails(modify_index);
3933 PropertyDetails new_details = new_descriptors->GetDetails(modify_index);
Ben Murdoch097c5b22016-05-18 11:27:45 +01003934 MaybeHandle<FieldType> old_field_type;
3935 MaybeHandle<FieldType> new_field_type;
3936 MaybeHandle<Object> old_value;
3937 MaybeHandle<Object> new_value;
3938 if (old_details.type() == DATA) {
3939 old_field_type =
3940 handle(old_descriptors->GetFieldType(modify_index), isolate);
3941 } else {
3942 old_value = handle(old_descriptors->GetValue(modify_index), isolate);
3943 }
3944 if (new_details.type() == DATA) {
3945 new_field_type =
3946 handle(new_descriptors->GetFieldType(modify_index), isolate);
3947 } else {
3948 new_value = handle(new_descriptors->GetValue(modify_index), isolate);
3949 }
3950
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003951 old_map->PrintGeneralization(
3952 stdout, "", modify_index, split_nof, old_nof,
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003953 old_details.location() == kDescriptor && store_mode == FORCE_FIELD,
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003954 old_details.representation(), new_details.representation(),
Ben Murdoch097c5b22016-05-18 11:27:45 +01003955 old_field_type, old_value, new_field_type, new_value);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003956 }
3957
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003958 Handle<LayoutDescriptor> new_layout_descriptor =
3959 LayoutDescriptor::New(split_map, new_descriptors, old_nof);
3960
3961 Handle<Map> new_map =
3962 AddMissingTransitions(split_map, new_descriptors, new_layout_descriptor);
3963
3964 // Deprecated part of the transition tree is no longer reachable, so replace
3965 // current instance descriptors in the "survived" part of the tree with
3966 // the new descriptors to maintain descriptors sharing invariant.
3967 split_map->ReplaceDescriptors(*new_descriptors, *new_layout_descriptor);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003968 return new_map;
Steve Blocka7e24c12009-10-30 11:49:00 +00003969}
3970
3971
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003972// Generalize the representation of all DATA descriptors.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003973Handle<Map> Map::GeneralizeAllFieldRepresentations(
3974 Handle<Map> map) {
3975 Handle<DescriptorArray> descriptors(map->instance_descriptors());
3976 for (int i = 0; i < map->NumberOfOwnDescriptors(); ++i) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003977 PropertyDetails details = descriptors->GetDetails(i);
3978 if (details.type() == DATA) {
3979 map = ReconfigureProperty(map, i, kData, details.attributes(),
3980 Representation::Tagged(),
Ben Murdoch097c5b22016-05-18 11:27:45 +01003981 FieldType::Any(map->GetIsolate()), FORCE_FIELD);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01003982 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003983 }
3984 return map;
3985}
3986
3987
3988// static
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003989MaybeHandle<Map> Map::TryUpdate(Handle<Map> old_map) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003990 DisallowHeapAllocation no_allocation;
3991 DisallowDeoptimization no_deoptimization(old_map->GetIsolate());
3992
3993 if (!old_map->is_deprecated()) return old_map;
3994
3995 // Check the state of the root map.
3996 Map* root_map = old_map->FindRootMap();
3997 if (!old_map->EquivalentToForTransition(root_map)) return MaybeHandle<Map>();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003998
3999 ElementsKind from_kind = root_map->elements_kind();
4000 ElementsKind to_kind = old_map->elements_kind();
4001 if (from_kind != to_kind) {
4002 // Try to follow existing elements kind transitions.
4003 root_map = root_map->LookupElementsTransitionMap(to_kind);
4004 if (root_map == NULL) return MaybeHandle<Map>();
4005 // From here on, use the map with correct elements kind as root map.
4006 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004007 int root_nof = root_map->NumberOfOwnDescriptors();
4008
4009 int old_nof = old_map->NumberOfOwnDescriptors();
4010 DescriptorArray* old_descriptors = old_map->instance_descriptors();
4011
4012 Map* new_map = root_map;
4013 for (int i = root_nof; i < old_nof; ++i) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -04004014 PropertyDetails old_details = old_descriptors->GetDetails(i);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004015 Map* transition = TransitionArray::SearchTransition(
4016 new_map, old_details.kind(), old_descriptors->GetKey(i),
4017 old_details.attributes());
4018 if (transition == NULL) return MaybeHandle<Map>();
4019 new_map = transition;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004020 DescriptorArray* new_descriptors = new_map->instance_descriptors();
4021
4022 PropertyDetails new_details = new_descriptors->GetDetails(i);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04004023 DCHECK_EQ(old_details.kind(), new_details.kind());
4024 DCHECK_EQ(old_details.attributes(), new_details.attributes());
4025 if (!old_details.representation().fits_into(new_details.representation())) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004026 return MaybeHandle<Map>();
4027 }
Emily Bernierd0a1eb72015-03-24 16:35:39 -04004028 switch (new_details.type()) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004029 case DATA: {
Ben Murdoch097c5b22016-05-18 11:27:45 +01004030 FieldType* new_type = new_descriptors->GetFieldType(i);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004031 // Cleared field types need special treatment. They represent lost
4032 // knowledge, so we must first generalize the new_type to "Any".
4033 if (FieldTypeIsCleared(new_details.representation(), new_type)) {
4034 return MaybeHandle<Map>();
4035 }
4036 PropertyType old_property_type = old_details.type();
4037 if (old_property_type == DATA) {
Ben Murdoch097c5b22016-05-18 11:27:45 +01004038 FieldType* old_type = old_descriptors->GetFieldType(i);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004039 if (FieldTypeIsCleared(old_details.representation(), old_type) ||
4040 !old_type->NowIs(new_type)) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -04004041 return MaybeHandle<Map>();
4042 }
4043 } else {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004044 DCHECK(old_property_type == DATA_CONSTANT);
4045 Object* old_value = old_descriptors->GetValue(i);
4046 if (!new_type->NowContains(old_value)) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -04004047 return MaybeHandle<Map>();
4048 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004049 }
4050 break;
Emily Bernierd0a1eb72015-03-24 16:35:39 -04004051 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004052 case ACCESSOR: {
4053#ifdef DEBUG
Ben Murdoch097c5b22016-05-18 11:27:45 +01004054 FieldType* new_type = new_descriptors->GetFieldType(i);
4055 DCHECK(new_type->IsAny());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004056#endif
Emily Bernierd0a1eb72015-03-24 16:35:39 -04004057 break;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004058 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004059
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004060 case DATA_CONSTANT:
4061 case ACCESSOR_CONSTANT: {
4062 Object* old_value = old_descriptors->GetValue(i);
4063 Object* new_value = new_descriptors->GetValue(i);
4064 if (old_details.location() == kField || old_value != new_value) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004065 return MaybeHandle<Map>();
4066 }
4067 break;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004068 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004069 }
4070 }
4071 if (new_map->NumberOfOwnDescriptors() != old_nof) return MaybeHandle<Map>();
4072 return handle(new_map);
4073}
4074
4075
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004076// static
4077Handle<Map> Map::Update(Handle<Map> map) {
4078 if (!map->is_deprecated()) return map;
4079 return ReconfigureProperty(map, -1, kData, NONE, Representation::None(),
Ben Murdoch097c5b22016-05-18 11:27:45 +01004080 FieldType::None(map->GetIsolate()),
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004081 ALLOW_IN_DESCRIPTOR);
4082}
4083
4084
4085Maybe<bool> JSObject::SetPropertyWithInterceptor(LookupIterator* it,
Ben Murdoch097c5b22016-05-18 11:27:45 +01004086 ShouldThrow should_throw,
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004087 Handle<Object> value) {
4088 Isolate* isolate = it->isolate();
4089 // Make sure that the top context does not change when doing callbacks or
4090 // interceptor calls.
4091 AssertNoContextChange ncc(isolate);
4092
4093 DCHECK_EQ(LookupIterator::INTERCEPTOR, it->state());
4094 Handle<InterceptorInfo> interceptor(it->GetInterceptor());
4095 if (interceptor->setter()->IsUndefined()) return Just(false);
4096
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004097 Handle<JSObject> holder = it->GetHolder<JSObject>();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004098 v8::Local<v8::Value> result;
4099 PropertyCallbackArguments args(isolate, interceptor->data(),
Ben Murdoch097c5b22016-05-18 11:27:45 +01004100 *it->GetReceiver(), *holder, should_throw);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004101
4102 if (it->IsElement()) {
4103 uint32_t index = it->index();
4104 v8::IndexedPropertySetterCallback setter =
4105 v8::ToCData<v8::IndexedPropertySetterCallback>(interceptor->setter());
4106 LOG(isolate,
4107 ApiIndexedPropertyAccess("interceptor-indexed-set", *holder, index));
4108 result = args.Call(setter, index, v8::Utils::ToLocal(value));
4109 } else {
4110 Handle<Name> name = it->name();
4111 DCHECK(!name->IsPrivate());
4112
4113 if (name->IsSymbol() && !interceptor->can_intercept_symbols()) {
4114 return Just(false);
4115 }
4116
4117 v8::GenericNamedPropertySetterCallback setter =
4118 v8::ToCData<v8::GenericNamedPropertySetterCallback>(
4119 interceptor->setter());
4120 LOG(it->isolate(),
4121 ApiNamedPropertyAccess("interceptor-named-set", *holder, *name));
4122 result =
4123 args.Call(setter, v8::Utils::ToLocal(name), v8::Utils::ToLocal(value));
Emily Bernierd0a1eb72015-03-24 16:35:39 -04004124 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004125
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004126 RETURN_VALUE_IF_SCHEDULED_EXCEPTION(it->isolate(), Nothing<bool>());
4127 if (result.IsEmpty()) return Just(false);
4128#ifdef DEBUG
4129 Handle<Object> result_internal = v8::Utils::OpenHandle(*result);
4130 result_internal->VerifyApiCallResultType();
4131#endif
4132 return Just(true);
4133 // TODO(neis): In the future, we may want to actually return the interceptor's
4134 // result, which then should be a boolean.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004135}
4136
4137
4138MaybeHandle<Object> Object::SetProperty(Handle<Object> object,
4139 Handle<Name> name, Handle<Object> value,
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004140 LanguageMode language_mode,
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004141 StoreFromKeyed store_mode) {
4142 LookupIterator it(object, name);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004143 MAYBE_RETURN_NULL(SetProperty(&it, value, language_mode, store_mode));
4144 return value;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004145}
4146
4147
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004148Maybe<bool> Object::SetPropertyInternal(LookupIterator* it,
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004149 Handle<Object> value,
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004150 LanguageMode language_mode,
Emily Bernierd0a1eb72015-03-24 16:35:39 -04004151 StoreFromKeyed store_mode,
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004152 bool* found) {
Ben Murdoch097c5b22016-05-18 11:27:45 +01004153 it->UpdateProtector();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004154 ShouldThrow should_throw =
4155 is_sloppy(language_mode) ? DONT_THROW : THROW_ON_ERROR;
4156
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004157 // Make sure that the top context does not change when doing callbacks or
4158 // interceptor calls.
4159 AssertNoContextChange ncc(it->isolate());
4160
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004161 *found = true;
4162
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004163 bool done = false;
4164 for (; it->IsFound(); it->Next()) {
4165 switch (it->state()) {
4166 case LookupIterator::NOT_FOUND:
4167 UNREACHABLE();
4168
4169 case LookupIterator::ACCESS_CHECK:
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004170 if (it->HasAccess()) break;
4171 // Check whether it makes sense to reuse the lookup iterator. Here it
4172 // might still call into setters up the prototype chain.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004173 return JSObject::SetPropertyWithFailedAccessCheck(it, value,
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004174 should_throw);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004175
4176 case LookupIterator::JSPROXY:
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004177 return JSProxy::SetProperty(it->GetHolder<JSProxy>(), it->GetName(),
4178 value, it->GetReceiver(), language_mode);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004179
4180 case LookupIterator::INTERCEPTOR:
4181 if (it->HolderIsReceiverOrHiddenPrototype()) {
Ben Murdoch097c5b22016-05-18 11:27:45 +01004182 Maybe<bool> result =
4183 JSObject::SetPropertyWithInterceptor(it, should_throw, value);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004184 if (result.IsNothing() || result.FromJust()) return result;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004185 } else {
4186 Maybe<PropertyAttributes> maybe_attributes =
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004187 JSObject::GetPropertyAttributesWithInterceptor(it);
4188 if (!maybe_attributes.IsJust()) return Nothing<bool>();
4189 done = maybe_attributes.FromJust() != ABSENT;
4190 if (done && (maybe_attributes.FromJust() & READ_ONLY) != 0) {
4191 return WriteToReadOnlyProperty(it, value, should_throw);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004192 }
4193 }
4194 break;
4195
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004196 case LookupIterator::ACCESSOR: {
4197 if (it->IsReadOnly()) {
4198 return WriteToReadOnlyProperty(it, value, should_throw);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004199 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004200 Handle<Object> accessors = it->GetAccessors();
4201 if (accessors->IsAccessorInfo() &&
4202 !it->HolderIsReceiverOrHiddenPrototype() &&
4203 AccessorInfo::cast(*accessors)->is_special_data_property()) {
4204 done = true;
4205 break;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004206 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004207 return SetPropertyWithAccessor(it, value, should_throw);
4208 }
4209 case LookupIterator::INTEGER_INDEXED_EXOTIC:
4210 // TODO(verwaest): We should throw an exception.
4211 return Just(true);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004212
4213 case LookupIterator::DATA:
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004214 if (it->IsReadOnly()) {
4215 return WriteToReadOnlyProperty(it, value, should_throw);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004216 }
4217 if (it->HolderIsReceiverOrHiddenPrototype()) {
4218 return SetDataProperty(it, value);
4219 }
4220 done = true;
4221 break;
4222
4223 case LookupIterator::TRANSITION:
4224 done = true;
4225 break;
4226 }
4227
4228 if (done) break;
4229 }
4230
4231 // If the receiver is the JSGlobalObject, the store was contextual. In case
4232 // the property did not exist yet on the global object itself, we have to
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004233 // throw a reference error in strict mode. In sloppy mode, we continue.
4234 if (it->GetReceiver()->IsJSGlobalObject() && is_strict(language_mode)) {
4235 it->isolate()->Throw(*it->isolate()->factory()->NewReferenceError(
4236 MessageTemplate::kNotDefined, it->name()));
4237 return Nothing<bool>();
4238 }
4239
4240 *found = false;
4241 return Nothing<bool>();
4242}
4243
4244
4245Maybe<bool> Object::SetProperty(LookupIterator* it, Handle<Object> value,
4246 LanguageMode language_mode,
4247 StoreFromKeyed store_mode) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004248 bool found = false;
4249 Maybe<bool> result =
4250 SetPropertyInternal(it, value, language_mode, store_mode, &found);
4251 if (found) return result;
Ben Murdoch097c5b22016-05-18 11:27:45 +01004252 ShouldThrow should_throw =
4253 is_sloppy(language_mode) ? DONT_THROW : THROW_ON_ERROR;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004254 return AddDataProperty(it, value, NONE, should_throw, store_mode);
4255}
4256
4257
4258Maybe<bool> Object::SetSuperProperty(LookupIterator* it, Handle<Object> value,
4259 LanguageMode language_mode,
4260 StoreFromKeyed store_mode) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004261 Isolate* isolate = it->isolate();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004262
4263 bool found = false;
4264 Maybe<bool> result =
4265 SetPropertyInternal(it, value, language_mode, store_mode, &found);
4266 if (found) return result;
4267
4268 // The property either doesn't exist on the holder or exists there as a data
4269 // property.
4270
Ben Murdoch097c5b22016-05-18 11:27:45 +01004271 ShouldThrow should_throw =
4272 is_sloppy(language_mode) ? DONT_THROW : THROW_ON_ERROR;
4273
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004274 if (!it->GetReceiver()->IsJSReceiver()) {
4275 return WriteToReadOnlyProperty(it, value, should_throw);
4276 }
4277 Handle<JSReceiver> receiver = Handle<JSReceiver>::cast(it->GetReceiver());
4278
4279 LookupIterator::Configuration c = LookupIterator::OWN;
4280 LookupIterator own_lookup =
4281 it->IsElement() ? LookupIterator(isolate, receiver, it->index(), c)
4282 : LookupIterator(receiver, it->name(), c);
4283
4284 for (; own_lookup.IsFound(); own_lookup.Next()) {
4285 switch (own_lookup.state()) {
4286 case LookupIterator::ACCESS_CHECK:
4287 if (!own_lookup.HasAccess()) {
4288 return JSObject::SetPropertyWithFailedAccessCheck(&own_lookup, value,
4289 should_throw);
4290 }
4291 break;
4292
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004293 case LookupIterator::ACCESSOR:
Ben Murdoch097c5b22016-05-18 11:27:45 +01004294 if (own_lookup.GetAccessors()->IsAccessorInfo()) {
4295 if (own_lookup.IsReadOnly()) {
4296 return WriteToReadOnlyProperty(&own_lookup, value, should_throw);
4297 }
4298 return JSObject::SetPropertyWithAccessor(&own_lookup, value,
4299 should_throw);
4300 }
4301 // Fall through.
4302 case LookupIterator::INTEGER_INDEXED_EXOTIC:
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004303 return RedefineIncompatibleProperty(isolate, it->GetName(), value,
4304 should_throw);
4305
4306 case LookupIterator::DATA: {
Ben Murdoch097c5b22016-05-18 11:27:45 +01004307 if (own_lookup.IsReadOnly()) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004308 return WriteToReadOnlyProperty(&own_lookup, value, should_throw);
4309 }
4310 return SetDataProperty(&own_lookup, value);
4311 }
4312
4313 case LookupIterator::INTERCEPTOR:
4314 case LookupIterator::JSPROXY: {
4315 PropertyDescriptor desc;
4316 Maybe<bool> owned =
4317 JSReceiver::GetOwnPropertyDescriptor(&own_lookup, &desc);
4318 MAYBE_RETURN(owned, Nothing<bool>());
4319 if (!owned.FromJust()) {
4320 return JSReceiver::CreateDataProperty(&own_lookup, value,
4321 should_throw);
4322 }
4323 if (PropertyDescriptor::IsAccessorDescriptor(&desc) ||
4324 !desc.writable()) {
4325 return RedefineIncompatibleProperty(isolate, it->GetName(), value,
4326 should_throw);
4327 }
4328
4329 PropertyDescriptor value_desc;
4330 value_desc.set_value(value);
4331 return JSReceiver::DefineOwnProperty(isolate, receiver, it->GetName(),
4332 &value_desc, should_throw);
4333 }
4334
4335 case LookupIterator::NOT_FOUND:
4336 case LookupIterator::TRANSITION:
4337 UNREACHABLE();
4338 }
4339 }
4340
4341 return JSObject::AddDataProperty(&own_lookup, value, NONE, should_throw,
4342 store_mode);
4343}
4344
Ben Murdoch097c5b22016-05-18 11:27:45 +01004345MaybeHandle<Object> Object::ReadAbsentProperty(LookupIterator* it) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004346 return it->isolate()->factory()->undefined_value();
4347}
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004348
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004349MaybeHandle<Object> Object::ReadAbsentProperty(Isolate* isolate,
4350 Handle<Object> receiver,
Ben Murdoch097c5b22016-05-18 11:27:45 +01004351 Handle<Object> name) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004352 return isolate->factory()->undefined_value();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004353}
4354
4355
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004356Maybe<bool> Object::CannotCreateProperty(Isolate* isolate,
4357 Handle<Object> receiver,
4358 Handle<Object> name,
4359 Handle<Object> value,
4360 ShouldThrow should_throw) {
4361 RETURN_FAILURE(
4362 isolate, should_throw,
4363 NewTypeError(MessageTemplate::kStrictCannotCreateProperty, name,
4364 Object::TypeOf(isolate, receiver), receiver));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004365}
4366
4367
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004368Maybe<bool> Object::WriteToReadOnlyProperty(LookupIterator* it,
4369 Handle<Object> value,
4370 ShouldThrow should_throw) {
4371 return WriteToReadOnlyProperty(it->isolate(), it->GetReceiver(),
4372 it->GetName(), value, should_throw);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04004373}
4374
4375
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004376Maybe<bool> Object::WriteToReadOnlyProperty(Isolate* isolate,
4377 Handle<Object> receiver,
4378 Handle<Object> name,
4379 Handle<Object> value,
4380 ShouldThrow should_throw) {
4381 RETURN_FAILURE(isolate, should_throw,
4382 NewTypeError(MessageTemplate::kStrictReadOnlyProperty, name,
4383 Object::TypeOf(isolate, receiver), receiver));
4384}
4385
4386
4387Maybe<bool> Object::RedefineIncompatibleProperty(Isolate* isolate,
4388 Handle<Object> name,
4389 Handle<Object> value,
4390 ShouldThrow should_throw) {
4391 RETURN_FAILURE(isolate, should_throw,
4392 NewTypeError(MessageTemplate::kRedefineDisallowed, name));
4393}
4394
4395
4396Maybe<bool> Object::SetDataProperty(LookupIterator* it, Handle<Object> value) {
4397 // Proxies are handled elsewhere. Other non-JSObjects cannot have own
4398 // properties.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004399 Handle<JSObject> receiver = Handle<JSObject>::cast(it->GetReceiver());
4400
4401 // Store on the holder which may be hidden behind the receiver.
4402 DCHECK(it->HolderIsReceiverOrHiddenPrototype());
4403
4404 // Old value for the observation change record.
4405 // Fetch before transforming the object since the encoding may become
4406 // incompatible with what's cached in |it|.
Emily Bernierd0a1eb72015-03-24 16:35:39 -04004407 bool is_observed = receiver->map()->is_observed() &&
Ben Murdoch097c5b22016-05-18 11:27:45 +01004408 (it->IsElement() || !it->name()->IsPrivate());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004409 MaybeHandle<Object> maybe_old;
4410 if (is_observed) maybe_old = it->GetDataValue();
4411
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004412 Handle<Object> to_assign = value;
4413 // Convert the incoming value to a number for storing into typed arrays.
4414 if (it->IsElement() && receiver->HasFixedTypedArrayElements()) {
4415 if (!value->IsNumber() && !value->IsUndefined()) {
4416 ASSIGN_RETURN_ON_EXCEPTION_VALUE(
4417 it->isolate(), to_assign, Object::ToNumber(value), Nothing<bool>());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004418 // We have to recheck the length. However, it can only change if the
4419 // underlying buffer was neutered, so just check that.
4420 if (Handle<JSArrayBufferView>::cast(receiver)->WasNeutered()) {
4421 return Just(true);
4422 // TODO(neis): According to the spec, this should throw a TypeError.
4423 }
4424 }
4425 }
4426
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004427 // Possibly migrate to the most up-to-date map that will be able to store
4428 // |value| under it->name().
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004429 it->PrepareForDataProperty(to_assign);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004430
4431 // Write the property value.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004432 it->WriteDataValue(to_assign);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004433
4434 // Send the change record if there are observers.
4435 if (is_observed && !value->SameValue(*maybe_old.ToHandleChecked())) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004436 RETURN_ON_EXCEPTION_VALUE(
4437 it->isolate(),
4438 JSObject::EnqueueChangeRecord(receiver, "update", it->GetName(),
4439 maybe_old.ToHandleChecked()),
4440 Nothing<bool>());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004441 }
4442
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004443#if VERIFY_HEAP
4444 if (FLAG_verify_heap) {
4445 receiver->JSObjectVerify();
4446 }
4447#endif
4448 return Just(true);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004449}
4450
4451
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004452MUST_USE_RESULT static MaybeHandle<Object> BeginPerformSplice(
4453 Handle<JSArray> object) {
4454 Isolate* isolate = object->GetIsolate();
4455 HandleScope scope(isolate);
4456 Handle<Object> args[] = {object};
4457
4458 return Execution::Call(
4459 isolate, Handle<JSFunction>(isolate->observers_begin_perform_splice()),
4460 isolate->factory()->undefined_value(), arraysize(args), args);
4461}
4462
4463
4464MUST_USE_RESULT static MaybeHandle<Object> EndPerformSplice(
4465 Handle<JSArray> object) {
4466 Isolate* isolate = object->GetIsolate();
4467 HandleScope scope(isolate);
4468 Handle<Object> args[] = {object};
4469
4470 return Execution::Call(
4471 isolate, Handle<JSFunction>(isolate->observers_end_perform_splice()),
4472 isolate->factory()->undefined_value(), arraysize(args), args);
4473}
4474
4475
4476MUST_USE_RESULT static MaybeHandle<Object> EnqueueSpliceRecord(
4477 Handle<JSArray> object, uint32_t index, Handle<JSArray> deleted,
4478 uint32_t add_count) {
4479 Isolate* isolate = object->GetIsolate();
4480 HandleScope scope(isolate);
4481 Handle<Object> index_object = isolate->factory()->NewNumberFromUint(index);
4482 Handle<Object> add_count_object =
4483 isolate->factory()->NewNumberFromUint(add_count);
4484
4485 Handle<Object> args[] = {object, index_object, deleted, add_count_object};
4486
4487 return Execution::Call(
4488 isolate, Handle<JSFunction>(isolate->observers_enqueue_splice()),
4489 isolate->factory()->undefined_value(), arraysize(args), args);
4490}
4491
4492
4493Maybe<bool> Object::AddDataProperty(LookupIterator* it, Handle<Object> value,
4494 PropertyAttributes attributes,
4495 ShouldThrow should_throw,
4496 StoreFromKeyed store_mode) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004497 if (!it->GetReceiver()->IsJSObject()) {
Ben Murdoch097c5b22016-05-18 11:27:45 +01004498 if (it->GetReceiver()->IsJSProxy() && it->GetName()->IsPrivate()) {
4499 RETURN_FAILURE(it->isolate(), should_throw,
4500 NewTypeError(MessageTemplate::kProxyPrivate));
4501 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004502 return CannotCreateProperty(it->isolate(), it->GetReceiver(), it->GetName(),
4503 value, should_throw);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004504 }
4505
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004506 DCHECK_NE(LookupIterator::INTEGER_INDEXED_EXOTIC, it->state());
4507
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004508 Handle<JSObject> receiver = it->GetStoreTarget();
4509
4510 // If the receiver is a JSGlobalProxy, store on the prototype (JSGlobalObject)
4511 // instead. If the prototype is Null, the proxy is detached.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004512 if (receiver->IsJSGlobalProxy()) return Just(true);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004513
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004514 Isolate* isolate = it->isolate();
Emily Bernierd0a1eb72015-03-24 16:35:39 -04004515
Ben Murdoch097c5b22016-05-18 11:27:45 +01004516 if (it->ExtendingNonExtensible(receiver)) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004517 RETURN_FAILURE(
4518 isolate, should_throw,
4519 NewTypeError(MessageTemplate::kObjectNotExtensible, it->GetName()));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004520 }
4521
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004522 if (it->IsElement()) {
4523 if (receiver->IsJSArray()) {
4524 Handle<JSArray> array = Handle<JSArray>::cast(receiver);
4525 if (JSArray::WouldChangeReadOnlyLength(array, it->index())) {
4526 RETURN_FAILURE(array->GetIsolate(), should_throw,
4527 NewTypeError(MessageTemplate::kStrictReadOnlyProperty,
4528 isolate->factory()->length_string(),
4529 Object::TypeOf(isolate, array), array));
4530 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004531
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004532 if (FLAG_trace_external_array_abuse &&
4533 array->HasFixedTypedArrayElements()) {
4534 CheckArrayAbuse(array, "typed elements write", it->index(), true);
4535 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004536
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004537 if (FLAG_trace_js_array_abuse && !array->HasFixedTypedArrayElements()) {
4538 CheckArrayAbuse(array, "elements write", it->index(), false);
Steve Blocka7e24c12009-10-30 11:49:00 +00004539 }
4540 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004541
4542 Maybe<bool> result = JSObject::AddDataElement(receiver, it->index(), value,
4543 attributes, should_throw);
4544 JSObject::ValidateElements(receiver);
4545 return result;
4546 } else {
4547 // Migrate to the most up-to-date map that will be able to store |value|
4548 // under it->name() with |attributes|.
Ben Murdoch097c5b22016-05-18 11:27:45 +01004549 it->PrepareTransitionToDataProperty(receiver, value, attributes,
4550 store_mode);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004551 DCHECK_EQ(LookupIterator::TRANSITION, it->state());
Ben Murdoch097c5b22016-05-18 11:27:45 +01004552 it->ApplyTransitionToDataProperty(receiver);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004553
4554 // TODO(verwaest): Encapsulate dictionary handling better.
4555 if (receiver->map()->is_dictionary_map()) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004556 // TODO(dcarney): just populate TransitionPropertyCell here?
4557 JSObject::AddSlowProperty(receiver, it->name(), value, attributes);
4558 } else {
4559 // Write the property value.
4560 it->WriteDataValue(value);
4561 }
4562
4563 // Send the change record if there are observers.
Ben Murdoch097c5b22016-05-18 11:27:45 +01004564 if (receiver->map()->is_observed() && !it->name()->IsPrivate()) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004565 RETURN_ON_EXCEPTION_VALUE(isolate, JSObject::EnqueueChangeRecord(
4566 receiver, "add", it->name(),
4567 it->factory()->the_hole_value()),
4568 Nothing<bool>());
4569 }
4570#if VERIFY_HEAP
4571 if (FLAG_verify_heap) {
4572 receiver->JSObjectVerify();
4573 }
4574#endif
Steve Blocka7e24c12009-10-30 11:49:00 +00004575 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004576
4577 return Just(true);
Steve Blocka7e24c12009-10-30 11:49:00 +00004578}
4579
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004580
4581void Map::EnsureDescriptorSlack(Handle<Map> map, int slack) {
4582 // Only supports adding slack to owned descriptors.
4583 DCHECK(map->owns_descriptors());
4584
4585 Handle<DescriptorArray> descriptors(map->instance_descriptors());
4586 int old_size = map->NumberOfOwnDescriptors();
4587 if (slack <= descriptors->NumberOfSlackDescriptors()) return;
4588
4589 Handle<DescriptorArray> new_descriptors = DescriptorArray::CopyUpTo(
4590 descriptors, old_size, slack);
4591
Emily Bernierd0a1eb72015-03-24 16:35:39 -04004592 DisallowHeapAllocation no_allocation;
4593 // The descriptors are still the same, so keep the layout descriptor.
4594 LayoutDescriptor* layout_descriptor = map->GetLayoutDescriptor();
4595
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004596 if (old_size == 0) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -04004597 map->UpdateDescriptors(*new_descriptors, layout_descriptor);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004598 return;
4599 }
4600
4601 // If the source descriptors had an enum cache we copy it. This ensures
4602 // that the maps to which we push the new descriptor array back can rely
4603 // on a cache always being available once it is set. If the map has more
4604 // enumerated descriptors than available in the original cache, the cache
4605 // will be lazily replaced by the extended cache when needed.
4606 if (descriptors->HasEnumCache()) {
4607 new_descriptors->CopyEnumCacheFrom(*descriptors);
4608 }
4609
4610 // Replace descriptors by new_descriptors in all maps that share it.
4611 map->GetHeap()->incremental_marking()->RecordWrites(*descriptors);
4612
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004613 Map* current = *map;
4614 while (current->instance_descriptors() == *descriptors) {
4615 Object* next = current->GetBackPointer();
4616 if (next->IsUndefined()) break; // Stop overwriting at initial map.
4617 current->UpdateDescriptors(*new_descriptors, layout_descriptor);
4618 current = Map::cast(next);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004619 }
Emily Bernierd0a1eb72015-03-24 16:35:39 -04004620 map->UpdateDescriptors(*new_descriptors, layout_descriptor);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004621}
4622
4623
4624template<class T>
4625static int AppendUniqueCallbacks(NeanderArray* callbacks,
4626 Handle<typename T::Array> array,
4627 int valid_descriptors) {
4628 int nof_callbacks = callbacks->length();
4629
4630 Isolate* isolate = array->GetIsolate();
4631 // Ensure the keys are unique names before writing them into the
4632 // instance descriptor. Since it may cause a GC, it has to be done before we
4633 // temporarily put the heap in an invalid state while appending descriptors.
4634 for (int i = 0; i < nof_callbacks; ++i) {
4635 Handle<AccessorInfo> entry(AccessorInfo::cast(callbacks->get(i)));
4636 if (entry->name()->IsUniqueName()) continue;
4637 Handle<String> key =
4638 isolate->factory()->InternalizeString(
4639 Handle<String>(String::cast(entry->name())));
4640 entry->set_name(*key);
4641 }
4642
4643 // Fill in new callback descriptors. Process the callbacks from
4644 // back to front so that the last callback with a given name takes
4645 // precedence over previously added callbacks with that name.
4646 for (int i = nof_callbacks - 1; i >= 0; i--) {
4647 Handle<AccessorInfo> entry(AccessorInfo::cast(callbacks->get(i)));
4648 Handle<Name> key(Name::cast(entry->name()));
4649 // Check if a descriptor with this name already exists before writing.
4650 if (!T::Contains(key, entry, valid_descriptors, array)) {
4651 T::Insert(key, entry, valid_descriptors, array);
4652 valid_descriptors++;
Ben Murdoch3ef787d2012-04-12 10:51:47 +01004653 }
4654 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004655
4656 return valid_descriptors;
4657}
4658
4659struct DescriptorArrayAppender {
4660 typedef DescriptorArray Array;
4661 static bool Contains(Handle<Name> key,
4662 Handle<AccessorInfo> entry,
4663 int valid_descriptors,
4664 Handle<DescriptorArray> array) {
4665 DisallowHeapAllocation no_gc;
4666 return array->Search(*key, valid_descriptors) != DescriptorArray::kNotFound;
4667 }
4668 static void Insert(Handle<Name> key,
4669 Handle<AccessorInfo> entry,
4670 int valid_descriptors,
4671 Handle<DescriptorArray> array) {
4672 DisallowHeapAllocation no_gc;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004673 AccessorConstantDescriptor desc(key, entry, entry->property_attributes());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004674 array->Append(&desc);
4675 }
4676};
4677
4678
4679struct FixedArrayAppender {
4680 typedef FixedArray Array;
4681 static bool Contains(Handle<Name> key,
4682 Handle<AccessorInfo> entry,
4683 int valid_descriptors,
4684 Handle<FixedArray> array) {
4685 for (int i = 0; i < valid_descriptors; i++) {
4686 if (*key == AccessorInfo::cast(array->get(i))->name()) return true;
4687 }
4688 return false;
4689 }
4690 static void Insert(Handle<Name> key,
4691 Handle<AccessorInfo> entry,
4692 int valid_descriptors,
4693 Handle<FixedArray> array) {
4694 DisallowHeapAllocation no_gc;
4695 array->set(valid_descriptors, *entry);
4696 }
4697};
4698
4699
4700void Map::AppendCallbackDescriptors(Handle<Map> map,
4701 Handle<Object> descriptors) {
4702 int nof = map->NumberOfOwnDescriptors();
4703 Handle<DescriptorArray> array(map->instance_descriptors());
4704 NeanderArray callbacks(descriptors);
4705 DCHECK(array->NumberOfSlackDescriptors() >= callbacks.length());
4706 nof = AppendUniqueCallbacks<DescriptorArrayAppender>(&callbacks, array, nof);
4707 map->SetNumberOfOwnDescriptors(nof);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01004708}
4709
Steve Blocka7e24c12009-10-30 11:49:00 +00004710
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004711int AccessorInfo::AppendUnique(Handle<Object> descriptors,
4712 Handle<FixedArray> array,
4713 int valid_descriptors) {
4714 NeanderArray callbacks(descriptors);
4715 DCHECK(array->length() >= callbacks.length() + valid_descriptors);
4716 return AppendUniqueCallbacks<FixedArrayAppender>(&callbacks,
4717 array,
4718 valid_descriptors);
Ben Murdochb0fe1622011-05-05 13:52:32 +01004719}
4720
4721
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004722static bool ContainsMap(MapHandleList* maps, Map* map) {
4723 DCHECK_NOT_NULL(map);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01004724 for (int i = 0; i < maps->length(); ++i) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004725 if (!maps->at(i).is_null() && *maps->at(i) == map) return true;
Ben Murdoch3ef787d2012-04-12 10:51:47 +01004726 }
4727 return false;
4728}
Ben Murdoch592a9fc2012-03-05 11:04:45 +00004729
Ben Murdoch85b71792012-04-11 18:30:58 +01004730
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004731Handle<Map> Map::FindTransitionedMap(Handle<Map> map,
4732 MapHandleList* candidates) {
4733 ElementsKind kind = map->elements_kind();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004734 bool packed = IsFastPackedElementsKind(kind);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004735
4736 Map* transition = nullptr;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004737 if (IsTransitionableFastElementsKind(kind)) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004738 for (Map* current = map->ElementsTransitionMap();
4739 current != nullptr && current->has_fast_elements();
4740 current = current->ElementsTransitionMap()) {
4741 if (ContainsMap(candidates, current) &&
4742 (packed || !IsFastPackedElementsKind(current->elements_kind()))) {
4743 transition = current;
4744 packed = packed && IsFastPackedElementsKind(current->elements_kind());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004745 }
Ben Murdoch85b71792012-04-11 18:30:58 +01004746 }
Ben Murdoch3ef787d2012-04-12 10:51:47 +01004747 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004748 return transition == nullptr ? Handle<Map>() : handle(transition);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01004749}
Ben Murdoch85b71792012-04-11 18:30:58 +01004750
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004751
4752static Map* FindClosestElementsTransition(Map* map, ElementsKind to_kind) {
4753 Map* current_map = map;
Ben Murdoch3ef787d2012-04-12 10:51:47 +01004754
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004755 ElementsKind kind = map->elements_kind();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004756 while (kind != to_kind) {
4757 Map* next_map = current_map->ElementsTransitionMap();
4758 if (next_map == nullptr) return current_map;
4759 kind = next_map->elements_kind();
4760 current_map = next_map;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004761 }
4762
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004763 DCHECK_EQ(to_kind, current_map->elements_kind());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004764 return current_map;
4765}
4766
4767
4768Map* Map::LookupElementsTransitionMap(ElementsKind to_kind) {
4769 Map* to_map = FindClosestElementsTransition(this, to_kind);
4770 if (to_map->elements_kind() == to_kind) return to_map;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004771 return nullptr;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004772}
4773
4774
4775bool Map::IsMapInArrayPrototypeChain() {
4776 Isolate* isolate = GetIsolate();
4777 if (isolate->initial_array_prototype()->map() == this) {
4778 return true;
4779 }
4780
4781 if (isolate->initial_object_prototype()->map() == this) {
4782 return true;
4783 }
4784
4785 return false;
4786}
4787
4788
Emily Bernierd0a1eb72015-03-24 16:35:39 -04004789Handle<WeakCell> Map::WeakCellForMap(Handle<Map> map) {
4790 Isolate* isolate = map->GetIsolate();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004791 if (map->weak_cell_cache()->IsWeakCell()) {
4792 return Handle<WeakCell>(WeakCell::cast(map->weak_cell_cache()));
Emily Bernierd0a1eb72015-03-24 16:35:39 -04004793 }
4794 Handle<WeakCell> weak_cell = isolate->factory()->NewWeakCell(map);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004795 map->set_weak_cell_cache(*weak_cell);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04004796 return weak_cell;
4797}
4798
4799
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004800static Handle<Map> AddMissingElementsTransitions(Handle<Map> map,
4801 ElementsKind to_kind) {
4802 DCHECK(IsTransitionElementsKind(map->elements_kind()));
4803
4804 Handle<Map> current_map = map;
4805
4806 ElementsKind kind = map->elements_kind();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004807 TransitionFlag flag;
4808 if (map->is_prototype_map()) {
4809 flag = OMIT_TRANSITION;
4810 } else {
4811 flag = INSERT_TRANSITION;
4812 if (IsFastElementsKind(kind)) {
4813 while (kind != to_kind && !IsTerminalElementsKind(kind)) {
4814 kind = GetNextTransitionElementsKind(kind);
4815 current_map = Map::CopyAsElementsKind(current_map, kind, flag);
4816 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004817 }
4818 }
4819
4820 // In case we are exiting the fast elements kind system, just add the map in
4821 // the end.
4822 if (kind != to_kind) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004823 current_map = Map::CopyAsElementsKind(current_map, to_kind, flag);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004824 }
4825
4826 DCHECK(current_map->elements_kind() == to_kind);
4827 return current_map;
4828}
4829
4830
4831Handle<Map> Map::TransitionElementsTo(Handle<Map> map,
4832 ElementsKind to_kind) {
4833 ElementsKind from_kind = map->elements_kind();
4834 if (from_kind == to_kind) return map;
4835
4836 Isolate* isolate = map->GetIsolate();
4837 Context* native_context = isolate->context()->native_context();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004838 if (from_kind == FAST_SLOPPY_ARGUMENTS_ELEMENTS) {
4839 if (*map == native_context->fast_aliased_arguments_map()) {
4840 DCHECK_EQ(SLOW_SLOPPY_ARGUMENTS_ELEMENTS, to_kind);
4841 return handle(native_context->slow_aliased_arguments_map());
4842 }
4843 } else if (from_kind == SLOW_SLOPPY_ARGUMENTS_ELEMENTS) {
4844 if (*map == native_context->slow_aliased_arguments_map()) {
4845 DCHECK_EQ(FAST_SLOPPY_ARGUMENTS_ELEMENTS, to_kind);
4846 return handle(native_context->fast_aliased_arguments_map());
4847 }
4848 } else if (IsFastElementsKind(from_kind) && IsFastElementsKind(to_kind)) {
4849 // Reuse map transitions for JSArrays.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004850 DisallowHeapAllocation no_gc;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004851 Strength strength = map->is_strong() ? Strength::STRONG : Strength::WEAK;
4852 if (native_context->get(Context::ArrayMapIndex(from_kind, strength)) ==
4853 *map) {
4854 Object* maybe_transitioned_map =
4855 native_context->get(Context::ArrayMapIndex(to_kind, strength));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004856 if (maybe_transitioned_map->IsMap()) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004857 return handle(Map::cast(maybe_transitioned_map), isolate);
Ben Murdoch85b71792012-04-11 18:30:58 +01004858 }
Ben Murdoch592a9fc2012-03-05 11:04:45 +00004859 }
4860 }
4861
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004862 DCHECK(!map->IsUndefined());
4863 // Check if we can go back in the elements kind transition chain.
4864 if (IsHoleyElementsKind(from_kind) &&
4865 to_kind == GetPackedElementsKind(from_kind) &&
4866 map->GetBackPointer()->IsMap() &&
4867 Map::cast(map->GetBackPointer())->elements_kind() == to_kind) {
4868 return handle(Map::cast(map->GetBackPointer()));
Ben Murdoch3ef787d2012-04-12 10:51:47 +01004869 }
4870
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004871 bool allow_store_transition = IsTransitionElementsKind(from_kind);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004872 // Only store fast element maps in ascending generality.
4873 if (IsFastElementsKind(to_kind)) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004874 allow_store_transition =
4875 allow_store_transition && IsTransitionableFastElementsKind(from_kind) &&
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004876 IsMoreGeneralElementsKindTransition(from_kind, to_kind);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01004877 }
4878
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004879 if (!allow_store_transition) {
4880 return Map::CopyAsElementsKind(map, to_kind, OMIT_TRANSITION);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01004881 }
4882
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004883 return Map::AsElementsKind(map, to_kind);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01004884}
4885
4886
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004887// static
4888Handle<Map> Map::AsElementsKind(Handle<Map> map, ElementsKind kind) {
4889 Handle<Map> closest_map(FindClosestElementsTransition(*map, kind));
Ben Murdoch3ef787d2012-04-12 10:51:47 +01004890
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004891 if (closest_map->elements_kind() == kind) {
4892 return closest_map;
Ben Murdoch3ef787d2012-04-12 10:51:47 +01004893 }
4894
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004895 return AddMissingElementsTransitions(closest_map, kind);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01004896}
4897
4898
4899Handle<Map> JSObject::GetElementsTransitionMap(Handle<JSObject> object,
4900 ElementsKind to_kind) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004901 Handle<Map> map(object->map());
4902 return Map::TransitionElementsTo(map, to_kind);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01004903}
4904
4905
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004906void JSProxy::Revoke(Handle<JSProxy> proxy) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004907 Isolate* isolate = proxy->GetIsolate();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004908 if (!proxy->IsRevoked()) proxy->set_handler(isolate->heap()->null_value());
4909 DCHECK(proxy->IsRevoked());
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00004910}
4911
4912
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004913Maybe<bool> JSProxy::HasProperty(Isolate* isolate, Handle<JSProxy> proxy,
4914 Handle<Name> name) {
4915 DCHECK(!name->IsPrivate());
4916 STACK_CHECK(Nothing<bool>());
4917 // 1. (Assert)
4918 // 2. Let handler be the value of the [[ProxyHandler]] internal slot of O.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004919 Handle<Object> handler(proxy->handler(), isolate);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004920 // 3. If handler is null, throw a TypeError exception.
4921 // 4. Assert: Type(handler) is Object.
4922 if (proxy->IsRevoked()) {
4923 isolate->Throw(*isolate->factory()->NewTypeError(
4924 MessageTemplate::kProxyRevoked, isolate->factory()->has_string()));
4925 return Nothing<bool>();
4926 }
4927 // 5. Let target be the value of the [[ProxyTarget]] internal slot of O.
4928 Handle<JSReceiver> target(proxy->target(), isolate);
4929 // 6. Let trap be ? GetMethod(handler, "has").
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004930 Handle<Object> trap;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004931 ASSIGN_RETURN_ON_EXCEPTION_VALUE(
4932 isolate, trap, Object::GetMethod(Handle<JSReceiver>::cast(handler),
4933 isolate->factory()->has_string()),
4934 Nothing<bool>());
4935 // 7. If trap is undefined, then
Ben Murdoch3ef787d2012-04-12 10:51:47 +01004936 if (trap->IsUndefined()) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004937 // 7a. Return target.[[HasProperty]](P).
4938 return JSReceiver::HasProperty(target, name);
4939 }
4940 // 8. Let booleanTrapResult be ToBoolean(? Call(trap, handler, «target, P»)).
4941 Handle<Object> trap_result_obj;
4942 Handle<Object> args[] = {target, name};
4943 ASSIGN_RETURN_ON_EXCEPTION_VALUE(
4944 isolate, trap_result_obj,
4945 Execution::Call(isolate, trap, handler, arraysize(args), args),
4946 Nothing<bool>());
4947 bool boolean_trap_result = trap_result_obj->BooleanValue();
4948 // 9. If booleanTrapResult is false, then:
4949 if (!boolean_trap_result) {
4950 // 9a. Let targetDesc be ? target.[[GetOwnProperty]](P).
4951 PropertyDescriptor target_desc;
4952 Maybe<bool> target_found = JSReceiver::GetOwnPropertyDescriptor(
4953 isolate, target, name, &target_desc);
4954 MAYBE_RETURN(target_found, Nothing<bool>());
4955 // 9b. If targetDesc is not undefined, then:
4956 if (target_found.FromJust()) {
4957 // 9b i. If targetDesc.[[Configurable]] is false, throw a TypeError
4958 // exception.
4959 if (!target_desc.configurable()) {
4960 isolate->Throw(*isolate->factory()->NewTypeError(
4961 MessageTemplate::kProxyHasNonConfigurable, name));
4962 return Nothing<bool>();
4963 }
4964 // 9b ii. Let extensibleTarget be ? IsExtensible(target).
4965 Maybe<bool> extensible_target = JSReceiver::IsExtensible(target);
4966 MAYBE_RETURN(extensible_target, Nothing<bool>());
4967 // 9b iii. If extensibleTarget is false, throw a TypeError exception.
4968 if (!extensible_target.FromJust()) {
4969 isolate->Throw(*isolate->factory()->NewTypeError(
4970 MessageTemplate::kProxyHasNonExtensible, name));
4971 return Nothing<bool>();
4972 }
Ben Murdoch3ef787d2012-04-12 10:51:47 +01004973 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004974 }
4975 // 10. Return booleanTrapResult.
4976 return Just(boolean_trap_result);
4977}
4978
4979
4980Maybe<bool> JSProxy::SetProperty(Handle<JSProxy> proxy, Handle<Name> name,
4981 Handle<Object> value, Handle<Object> receiver,
4982 LanguageMode language_mode) {
4983 DCHECK(!name->IsPrivate());
4984 Isolate* isolate = proxy->GetIsolate();
4985 STACK_CHECK(Nothing<bool>());
4986 Factory* factory = isolate->factory();
4987 Handle<String> trap_name = factory->set_string();
4988 ShouldThrow should_throw =
4989 is_sloppy(language_mode) ? DONT_THROW : THROW_ON_ERROR;
4990
4991 if (proxy->IsRevoked()) {
4992 isolate->Throw(
4993 *factory->NewTypeError(MessageTemplate::kProxyRevoked, trap_name));
4994 return Nothing<bool>();
4995 }
4996 Handle<JSReceiver> target(proxy->target(), isolate);
4997 Handle<JSReceiver> handler(JSReceiver::cast(proxy->handler()), isolate);
4998
4999 Handle<Object> trap;
5000 ASSIGN_RETURN_ON_EXCEPTION_VALUE(
5001 isolate, trap, Object::GetMethod(handler, trap_name), Nothing<bool>());
5002 if (trap->IsUndefined()) {
5003 LookupIterator it =
5004 LookupIterator::PropertyOrElement(isolate, receiver, name, target);
5005 return Object::SetSuperProperty(&it, value, language_mode,
5006 Object::MAY_BE_STORE_FROM_KEYED);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01005007 }
5008
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00005009 Handle<Object> trap_result;
5010 Handle<Object> args[] = {target, name, value, receiver};
5011 ASSIGN_RETURN_ON_EXCEPTION_VALUE(
5012 isolate, trap_result,
5013 Execution::Call(isolate, trap, handler, arraysize(args), args),
5014 Nothing<bool>());
5015 if (!trap_result->BooleanValue()) {
5016 RETURN_FAILURE(isolate, should_throw,
5017 NewTypeError(MessageTemplate::kProxyTrapReturnedFalsishFor,
5018 trap_name, name));
5019 }
5020
5021 // Enforce the invariant.
5022 PropertyDescriptor target_desc;
5023 Maybe<bool> owned =
5024 JSReceiver::GetOwnPropertyDescriptor(isolate, target, name, &target_desc);
5025 MAYBE_RETURN(owned, Nothing<bool>());
5026 if (owned.FromJust()) {
5027 bool inconsistent = PropertyDescriptor::IsDataDescriptor(&target_desc) &&
5028 !target_desc.configurable() &&
5029 !target_desc.writable() &&
5030 !value->SameValue(*target_desc.value());
5031 if (inconsistent) {
5032 isolate->Throw(*isolate->factory()->NewTypeError(
5033 MessageTemplate::kProxySetFrozenData, name));
5034 return Nothing<bool>();
5035 }
5036 inconsistent = PropertyDescriptor::IsAccessorDescriptor(&target_desc) &&
5037 !target_desc.configurable() &&
5038 target_desc.set()->IsUndefined();
5039 if (inconsistent) {
5040 isolate->Throw(*isolate->factory()->NewTypeError(
5041 MessageTemplate::kProxySetFrozenAccessor, name));
5042 return Nothing<bool>();
5043 }
5044 }
5045 return Just(true);
5046}
5047
5048
5049Maybe<bool> JSProxy::DeletePropertyOrElement(Handle<JSProxy> proxy,
5050 Handle<Name> name,
5051 LanguageMode language_mode) {
5052 DCHECK(!name->IsPrivate());
5053 ShouldThrow should_throw =
5054 is_sloppy(language_mode) ? DONT_THROW : THROW_ON_ERROR;
5055 Isolate* isolate = proxy->GetIsolate();
5056 STACK_CHECK(Nothing<bool>());
5057 Factory* factory = isolate->factory();
5058 Handle<String> trap_name = factory->deleteProperty_string();
5059
5060 if (proxy->IsRevoked()) {
5061 isolate->Throw(
5062 *factory->NewTypeError(MessageTemplate::kProxyRevoked, trap_name));
5063 return Nothing<bool>();
5064 }
5065 Handle<JSReceiver> target(proxy->target(), isolate);
5066 Handle<JSReceiver> handler(JSReceiver::cast(proxy->handler()), isolate);
5067
5068 Handle<Object> trap;
5069 ASSIGN_RETURN_ON_EXCEPTION_VALUE(
5070 isolate, trap, Object::GetMethod(handler, trap_name), Nothing<bool>());
5071 if (trap->IsUndefined()) {
5072 return JSReceiver::DeletePropertyOrElement(target, name, language_mode);
5073 }
5074
5075 Handle<Object> trap_result;
5076 Handle<Object> args[] = {target, name};
5077 ASSIGN_RETURN_ON_EXCEPTION_VALUE(
5078 isolate, trap_result,
5079 Execution::Call(isolate, trap, handler, arraysize(args), args),
5080 Nothing<bool>());
5081 if (!trap_result->BooleanValue()) {
5082 RETURN_FAILURE(isolate, should_throw,
5083 NewTypeError(MessageTemplate::kProxyTrapReturnedFalsishFor,
5084 trap_name, name));
5085 }
5086
5087 // Enforce the invariant.
5088 PropertyDescriptor target_desc;
5089 Maybe<bool> owned =
5090 JSReceiver::GetOwnPropertyDescriptor(isolate, target, name, &target_desc);
5091 MAYBE_RETURN(owned, Nothing<bool>());
5092 if (owned.FromJust() && !target_desc.configurable()) {
5093 isolate->Throw(*factory->NewTypeError(
5094 MessageTemplate::kProxyDeletePropertyNonConfigurable, name));
5095 return Nothing<bool>();
5096 }
5097 return Just(true);
5098}
5099
5100
5101// static
5102MaybeHandle<JSProxy> JSProxy::New(Isolate* isolate, Handle<Object> target,
5103 Handle<Object> handler) {
5104 if (!target->IsJSReceiver()) {
5105 THROW_NEW_ERROR(isolate, NewTypeError(MessageTemplate::kProxyNonObject),
5106 JSProxy);
5107 }
5108 if (target->IsJSProxy() && JSProxy::cast(*target)->IsRevoked()) {
5109 THROW_NEW_ERROR(isolate,
5110 NewTypeError(MessageTemplate::kProxyHandlerOrTargetRevoked),
5111 JSProxy);
5112 }
5113 if (!handler->IsJSReceiver()) {
5114 THROW_NEW_ERROR(isolate, NewTypeError(MessageTemplate::kProxyNonObject),
5115 JSProxy);
5116 }
5117 if (handler->IsJSProxy() && JSProxy::cast(*handler)->IsRevoked()) {
5118 THROW_NEW_ERROR(isolate,
5119 NewTypeError(MessageTemplate::kProxyHandlerOrTargetRevoked),
5120 JSProxy);
5121 }
5122 return isolate->factory()->NewJSProxy(Handle<JSReceiver>::cast(target),
5123 Handle<JSReceiver>::cast(handler));
5124}
5125
5126
5127// static
5128MaybeHandle<Context> JSProxy::GetFunctionRealm(Handle<JSProxy> proxy) {
5129 DCHECK(proxy->map()->is_constructor());
5130 if (proxy->IsRevoked()) {
5131 THROW_NEW_ERROR(proxy->GetIsolate(),
5132 NewTypeError(MessageTemplate::kProxyRevoked), Context);
5133 }
5134 Handle<JSReceiver> target(JSReceiver::cast(proxy->target()));
5135 return JSReceiver::GetFunctionRealm(target);
5136}
5137
5138
5139// static
5140MaybeHandle<Context> JSBoundFunction::GetFunctionRealm(
5141 Handle<JSBoundFunction> function) {
5142 DCHECK(function->map()->is_constructor());
5143 return JSReceiver::GetFunctionRealm(
5144 handle(function->bound_target_function()));
5145}
5146
5147
5148// static
5149Handle<Context> JSFunction::GetFunctionRealm(Handle<JSFunction> function) {
5150 DCHECK(function->map()->is_constructor());
5151 return handle(function->context()->native_context());
5152}
5153
5154
5155// static
5156MaybeHandle<Context> JSObject::GetFunctionRealm(Handle<JSObject> object) {
5157 DCHECK(object->map()->is_constructor());
5158 DCHECK(!object->IsJSFunction());
5159 return handle(object->GetCreationContext());
5160}
5161
5162
5163// static
5164MaybeHandle<Context> JSReceiver::GetFunctionRealm(Handle<JSReceiver> receiver) {
5165 if (receiver->IsJSProxy()) {
5166 return JSProxy::GetFunctionRealm(Handle<JSProxy>::cast(receiver));
5167 }
5168
5169 if (receiver->IsJSFunction()) {
5170 return JSFunction::GetFunctionRealm(Handle<JSFunction>::cast(receiver));
5171 }
5172
5173 if (receiver->IsJSBoundFunction()) {
5174 return JSBoundFunction::GetFunctionRealm(
5175 Handle<JSBoundFunction>::cast(receiver));
5176 }
5177
5178 return JSObject::GetFunctionRealm(Handle<JSObject>::cast(receiver));
5179}
5180
5181
5182Maybe<PropertyAttributes> JSProxy::GetPropertyAttributes(LookupIterator* it) {
5183 Isolate* isolate = it->isolate();
5184 HandleScope scope(isolate);
5185 PropertyDescriptor desc;
5186 Maybe<bool> found = JSProxy::GetOwnPropertyDescriptor(
5187 isolate, it->GetHolder<JSProxy>(), it->GetName(), &desc);
5188 MAYBE_RETURN(found, Nothing<PropertyAttributes>());
5189 if (!found.FromJust()) return Just(ABSENT);
5190 return Just(desc.ToAttributes());
Ben Murdoch3ef787d2012-04-12 10:51:47 +01005191}
5192
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00005193
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005194void JSObject::AllocateStorageForMap(Handle<JSObject> object, Handle<Map> map) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00005195 DCHECK(object->map()->GetInObjectProperties() ==
5196 map->GetInObjectProperties());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005197 ElementsKind obj_kind = object->map()->elements_kind();
5198 ElementsKind map_kind = map->elements_kind();
5199 if (map_kind != obj_kind) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00005200 ElementsKind to_kind = GetMoreGeneralElementsKind(map_kind, obj_kind);
5201 if (IsDictionaryElementsKind(obj_kind)) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005202 to_kind = obj_kind;
John Reck59135872010-11-02 12:39:01 -07005203 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005204 if (IsDictionaryElementsKind(to_kind)) {
5205 NormalizeElements(object);
Ben Murdoche0cee9b2011-05-25 10:26:03 +01005206 } else {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005207 TransitionElementsKind(object, to_kind);
Ben Murdoche0cee9b2011-05-25 10:26:03 +01005208 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005209 map = Map::AsElementsKind(map, to_kind);
Ben Murdoche0cee9b2011-05-25 10:26:03 +01005210 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005211 JSObject::MigrateToMap(object, map);
5212}
5213
5214
5215void JSObject::MigrateInstance(Handle<JSObject> object) {
5216 Handle<Map> original_map(object->map());
5217 Handle<Map> map = Map::Update(original_map);
5218 map->set_migration_target(true);
5219 MigrateToMap(object, map);
5220 if (FLAG_trace_migration) {
5221 object->PrintInstanceMigration(stdout, *original_map, *map);
5222 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00005223#if VERIFY_HEAP
5224 if (FLAG_verify_heap) {
5225 object->JSObjectVerify();
5226 }
5227#endif
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005228}
5229
5230
5231// static
5232bool JSObject::TryMigrateInstance(Handle<JSObject> object) {
5233 Isolate* isolate = object->GetIsolate();
5234 DisallowDeoptimization no_deoptimization(isolate);
5235 Handle<Map> original_map(object->map(), isolate);
5236 Handle<Map> new_map;
5237 if (!Map::TryUpdate(original_map).ToHandle(&new_map)) {
5238 return false;
5239 }
5240 JSObject::MigrateToMap(object, new_map);
5241 if (FLAG_trace_migration) {
5242 object->PrintInstanceMigration(stdout, *original_map, object->map());
5243 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00005244#if VERIFY_HEAP
5245 if (FLAG_verify_heap) {
5246 object->JSObjectVerify();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005247 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00005248#endif
5249 return true;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005250}
5251
5252
5253void JSObject::AddProperty(Handle<JSObject> object, Handle<Name> name,
5254 Handle<Object> value,
5255 PropertyAttributes attributes) {
5256 LookupIterator it(object, name, LookupIterator::OWN_SKIP_INTERCEPTOR);
5257 CHECK_NE(LookupIterator::ACCESS_CHECK, it.state());
5258#ifdef DEBUG
5259 uint32_t index;
5260 DCHECK(!object->IsJSProxy());
5261 DCHECK(!name->AsArrayIndex(&index));
5262 Maybe<PropertyAttributes> maybe = GetPropertyAttributes(&it);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00005263 DCHECK(maybe.IsJust());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005264 DCHECK(!it.IsFound());
Ben Murdoch097c5b22016-05-18 11:27:45 +01005265 DCHECK(object->map()->is_extensible() || name->IsPrivate());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005266#endif
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00005267 CHECK(AddDataProperty(&it, value, attributes, THROW_ON_ERROR,
5268 CERTAINLY_NOT_STORE_FROM_KEYED)
5269 .IsJust());
5270}
5271
5272
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005273// Reconfigures a property to a data property with attributes, even if it is not
5274// reconfigurable.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00005275// Requires a LookupIterator that does not look at the prototype chain beyond
5276// hidden prototypes.
5277MaybeHandle<Object> JSObject::DefineOwnPropertyIgnoreAttributes(
5278 LookupIterator* it, Handle<Object> value, PropertyAttributes attributes,
Ben Murdoch097c5b22016-05-18 11:27:45 +01005279 AccessorInfoHandling handling) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00005280 MAYBE_RETURN_NULL(DefineOwnPropertyIgnoreAttributes(
5281 it, value, attributes, THROW_ON_ERROR, handling));
5282 return value;
5283}
5284
5285
5286Maybe<bool> JSObject::DefineOwnPropertyIgnoreAttributes(
5287 LookupIterator* it, Handle<Object> value, PropertyAttributes attributes,
Ben Murdoch097c5b22016-05-18 11:27:45 +01005288 ShouldThrow should_throw, AccessorInfoHandling handling) {
5289 it->UpdateProtector();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00005290 Handle<JSObject> object = Handle<JSObject>::cast(it->GetReceiver());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005291 bool is_observed = object->map()->is_observed() &&
Ben Murdoch097c5b22016-05-18 11:27:45 +01005292 (it->IsElement() || !it->name()->IsPrivate());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00005293
5294 for (; it->IsFound(); it->Next()) {
5295 switch (it->state()) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005296 case LookupIterator::JSPROXY:
5297 case LookupIterator::NOT_FOUND:
5298 case LookupIterator::TRANSITION:
5299 UNREACHABLE();
5300
5301 case LookupIterator::ACCESS_CHECK:
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00005302 if (!it->HasAccess()) {
5303 it->isolate()->ReportFailedAccessCheck(it->GetHolder<JSObject>());
5304 RETURN_VALUE_IF_SCHEDULED_EXCEPTION(it->isolate(), Nothing<bool>());
5305 return Just(true);
5306 }
5307 break;
5308
5309 // If there's an interceptor, try to store the property with the
5310 // interceptor.
5311 // In case of success, the attributes will have been reset to the default
5312 // attributes of the interceptor, rather than the incoming attributes.
5313 //
5314 // TODO(verwaest): JSProxy afterwards verify the attributes that the
5315 // JSProxy claims it has, and verifies that they are compatible. If not,
5316 // they throw. Here we should do the same.
5317 case LookupIterator::INTERCEPTOR:
5318 if (handling == DONT_FORCE_FIELD) {
Ben Murdoch097c5b22016-05-18 11:27:45 +01005319 Maybe<bool> result =
5320 JSObject::SetPropertyWithInterceptor(it, should_throw, value);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00005321 if (result.IsNothing() || result.FromJust()) return result;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005322 }
5323 break;
5324
5325 case LookupIterator::ACCESSOR: {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00005326 Handle<Object> accessors = it->GetAccessors();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005327
Ben Murdoch097c5b22016-05-18 11:27:45 +01005328 // Special handling for AccessorInfo, which behaves like a data
5329 // property.
5330 if (accessors->IsAccessorInfo() && handling == DONT_FORCE_FIELD) {
5331 PropertyAttributes current_attributes = it->property_attributes();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00005332 // Ensure the context isn't changed after calling into accessors.
5333 AssertNoContextChange ncc(it->isolate());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005334
Ben Murdoch097c5b22016-05-18 11:27:45 +01005335 // Update the attributes before calling the setter. The setter may
5336 // later change the shape of the property.
5337 if (current_attributes != attributes) {
5338 it->TransitionToAccessorPair(accessors, attributes);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005339 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005340
Ben Murdoch097c5b22016-05-18 11:27:45 +01005341 Maybe<bool> result =
5342 JSObject::SetPropertyWithAccessor(it, value, should_throw);
5343
5344 if (current_attributes == attributes || result.IsNothing()) {
5345 return result;
5346 }
5347
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00005348 } else {
5349 it->ReconfigureDataProperty(value, attributes);
5350 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005351
5352 if (is_observed) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00005353 RETURN_ON_EXCEPTION_VALUE(
5354 it->isolate(),
5355 EnqueueChangeRecord(object, "reconfigure", it->GetName(),
5356 it->factory()->the_hole_value()),
5357 Nothing<bool>());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005358 }
5359
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00005360 return Just(true);
Iain Merrick75681382010-08-19 15:07:18 +01005361 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00005362 case LookupIterator::INTEGER_INDEXED_EXOTIC:
5363 return RedefineIncompatibleProperty(it->isolate(), it->GetName(), value,
5364 should_throw);
Steve Blocka7e24c12009-10-30 11:49:00 +00005365
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005366 case LookupIterator::DATA: {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00005367 Handle<Object> old_value = it->factory()->the_hole_value();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005368 // Regular property update if the attributes match.
Ben Murdoch097c5b22016-05-18 11:27:45 +01005369 if (it->property_attributes() == attributes) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00005370 return SetDataProperty(it, value);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005371 }
Steve Blocka7e24c12009-10-30 11:49:00 +00005372
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00005373 // Special case: properties of typed arrays cannot be reconfigured to
5374 // non-writable nor to non-enumerable.
5375 if (it->IsElement() && object->HasFixedTypedArrayElements()) {
5376 return RedefineIncompatibleProperty(it->isolate(), it->GetName(),
5377 value, should_throw);
5378 }
5379
5380 // Reconfigure the data property if the attributes mismatch.
5381 if (is_observed) old_value = it->GetDataValue();
5382
5383 it->ReconfigureDataProperty(value, attributes);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01005384
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005385 if (is_observed) {
5386 if (old_value->SameValue(*value)) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00005387 old_value = it->factory()->the_hole_value();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005388 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00005389 RETURN_ON_EXCEPTION_VALUE(
5390 it->isolate(), EnqueueChangeRecord(object, "reconfigure",
5391 it->GetName(), old_value),
5392 Nothing<bool>());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005393 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00005394 return Just(true);
Steve Blocka7e24c12009-10-30 11:49:00 +00005395 }
Steve Blocka7e24c12009-10-30 11:49:00 +00005396 }
5397 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005398
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00005399 return AddDataProperty(it, value, attributes, should_throw,
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005400 CERTAINLY_NOT_STORE_FROM_KEYED);
Steve Blocka7e24c12009-10-30 11:49:00 +00005401}
5402
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00005403MaybeHandle<Object> JSObject::SetOwnPropertyIgnoreAttributes(
5404 Handle<JSObject> object, Handle<Name> name, Handle<Object> value,
Ben Murdoch097c5b22016-05-18 11:27:45 +01005405 PropertyAttributes attributes) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00005406 DCHECK(!value->IsTheHole());
5407 LookupIterator it(object, name, LookupIterator::OWN);
Ben Murdoch097c5b22016-05-18 11:27:45 +01005408 return DefineOwnPropertyIgnoreAttributes(&it, value, attributes);
Steve Blocka7e24c12009-10-30 11:49:00 +00005409}
5410
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00005411MaybeHandle<Object> JSObject::SetOwnElementIgnoreAttributes(
5412 Handle<JSObject> object, uint32_t index, Handle<Object> value,
Ben Murdoch097c5b22016-05-18 11:27:45 +01005413 PropertyAttributes attributes) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00005414 Isolate* isolate = object->GetIsolate();
5415 LookupIterator it(isolate, object, index, LookupIterator::OWN);
Ben Murdoch097c5b22016-05-18 11:27:45 +01005416 return DefineOwnPropertyIgnoreAttributes(&it, value, attributes);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00005417}
5418
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00005419MaybeHandle<Object> JSObject::DefinePropertyOrElementIgnoreAttributes(
5420 Handle<JSObject> object, Handle<Name> name, Handle<Object> value,
Ben Murdoch097c5b22016-05-18 11:27:45 +01005421 PropertyAttributes attributes) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00005422 Isolate* isolate = object->GetIsolate();
5423 LookupIterator it = LookupIterator::PropertyOrElement(isolate, object, name,
5424 LookupIterator::OWN);
Ben Murdoch097c5b22016-05-18 11:27:45 +01005425 return DefineOwnPropertyIgnoreAttributes(&it, value, attributes);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00005426}
5427
5428
5429Maybe<PropertyAttributes> JSObject::GetPropertyAttributesWithInterceptor(
5430 LookupIterator* it) {
5431 Isolate* isolate = it->isolate();
5432 // Make sure that the top context does not change when doing
5433 // callbacks or interceptor calls.
5434 AssertNoContextChange ncc(isolate);
5435 HandleScope scope(isolate);
5436
5437 Handle<JSObject> holder = it->GetHolder<JSObject>();
5438 Handle<InterceptorInfo> interceptor(it->GetInterceptor());
5439 if (!it->IsElement() && it->name()->IsSymbol() &&
5440 !interceptor->can_intercept_symbols()) {
5441 return Just(ABSENT);
Steve Blocka7e24c12009-10-30 11:49:00 +00005442 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00005443 PropertyCallbackArguments args(isolate, interceptor->data(),
Ben Murdoch097c5b22016-05-18 11:27:45 +01005444 *it->GetReceiver(), *holder,
5445 Object::DONT_THROW);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00005446 if (!interceptor->query()->IsUndefined()) {
5447 v8::Local<v8::Integer> result;
5448 if (it->IsElement()) {
5449 uint32_t index = it->index();
5450 v8::IndexedPropertyQueryCallback query =
5451 v8::ToCData<v8::IndexedPropertyQueryCallback>(interceptor->query());
5452 LOG(isolate,
5453 ApiIndexedPropertyAccess("interceptor-indexed-has", *holder, index));
5454 result = args.Call(query, index);
5455 } else {
5456 Handle<Name> name = it->name();
5457 DCHECK(!name->IsPrivate());
5458 v8::GenericNamedPropertyQueryCallback query =
5459 v8::ToCData<v8::GenericNamedPropertyQueryCallback>(
5460 interceptor->query());
5461 LOG(isolate,
5462 ApiNamedPropertyAccess("interceptor-named-has", *holder, *name));
5463 result = args.Call(query, v8::Utils::ToLocal(name));
5464 }
5465 if (!result.IsEmpty()) {
5466 DCHECK(result->IsInt32());
5467 return Just(static_cast<PropertyAttributes>(
5468 result->Int32Value(reinterpret_cast<v8::Isolate*>(isolate)
5469 ->GetCurrentContext()).FromJust()));
5470 }
5471 } else if (!interceptor->getter()->IsUndefined()) {
5472 // TODO(verwaest): Use GetPropertyWithInterceptor?
5473 v8::Local<v8::Value> result;
5474 if (it->IsElement()) {
5475 uint32_t index = it->index();
5476 v8::IndexedPropertyGetterCallback getter =
5477 v8::ToCData<v8::IndexedPropertyGetterCallback>(interceptor->getter());
5478 LOG(isolate, ApiIndexedPropertyAccess("interceptor-indexed-get-has",
5479 *holder, index));
5480 result = args.Call(getter, index);
5481 } else {
5482 Handle<Name> name = it->name();
5483 DCHECK(!name->IsPrivate());
5484 v8::GenericNamedPropertyGetterCallback getter =
5485 v8::ToCData<v8::GenericNamedPropertyGetterCallback>(
5486 interceptor->getter());
5487 LOG(isolate,
5488 ApiNamedPropertyAccess("interceptor-named-get-has", *holder, *name));
5489 result = args.Call(getter, v8::Utils::ToLocal(name));
5490 }
5491 if (!result.IsEmpty()) return Just(DONT_ENUM);
5492 }
5493
5494 RETURN_VALUE_IF_SCHEDULED_EXCEPTION(isolate, Nothing<PropertyAttributes>());
5495 return Just(ABSENT);
Steve Blocka7e24c12009-10-30 11:49:00 +00005496}
5497
5498
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005499Maybe<PropertyAttributes> JSReceiver::GetPropertyAttributes(
5500 LookupIterator* it) {
5501 for (; it->IsFound(); it->Next()) {
5502 switch (it->state()) {
5503 case LookupIterator::NOT_FOUND:
5504 case LookupIterator::TRANSITION:
5505 UNREACHABLE();
5506 case LookupIterator::JSPROXY:
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00005507 return JSProxy::GetPropertyAttributes(it);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005508 case LookupIterator::INTERCEPTOR: {
5509 Maybe<PropertyAttributes> result =
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00005510 JSObject::GetPropertyAttributesWithInterceptor(it);
5511 if (!result.IsJust()) return result;
5512 if (result.FromJust() != ABSENT) return result;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005513 break;
Kristian Monsen80d68ea2010-09-08 11:05:35 +01005514 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005515 case LookupIterator::ACCESS_CHECK:
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00005516 if (it->HasAccess()) break;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005517 return JSObject::GetPropertyAttributesWithFailedAccessCheck(it);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00005518 case LookupIterator::INTEGER_INDEXED_EXOTIC:
5519 return Just(ABSENT);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005520 case LookupIterator::ACCESSOR:
5521 case LookupIterator::DATA:
Ben Murdoch097c5b22016-05-18 11:27:45 +01005522 return Just(it->property_attributes());
Kristian Monsen80d68ea2010-09-08 11:05:35 +01005523 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005524 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00005525 return Just(ABSENT);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005526}
5527
5528
5529Handle<NormalizedMapCache> NormalizedMapCache::New(Isolate* isolate) {
5530 Handle<FixedArray> array(
5531 isolate->factory()->NewFixedArray(kEntries, TENURED));
5532 return Handle<NormalizedMapCache>::cast(array);
5533}
5534
5535
5536MaybeHandle<Map> NormalizedMapCache::Get(Handle<Map> fast_map,
5537 PropertyNormalizationMode mode) {
5538 DisallowHeapAllocation no_gc;
5539 Object* value = FixedArray::get(GetIndex(fast_map));
5540 if (!value->IsMap() ||
5541 !Map::cast(value)->EquivalentToForNormalization(*fast_map, mode)) {
5542 return MaybeHandle<Map>();
5543 }
5544 return handle(Map::cast(value));
5545}
5546
5547
5548void NormalizedMapCache::Set(Handle<Map> fast_map,
5549 Handle<Map> normalized_map) {
5550 DisallowHeapAllocation no_gc;
5551 DCHECK(normalized_map->is_dictionary_map());
5552 FixedArray::set(GetIndex(fast_map), *normalized_map);
Kristian Monsen80d68ea2010-09-08 11:05:35 +01005553}
5554
5555
Kristian Monsen80d68ea2010-09-08 11:05:35 +01005556void NormalizedMapCache::Clear() {
5557 int entries = length();
5558 for (int i = 0; i != entries; i++) {
5559 set_undefined(i);
5560 }
5561}
5562
5563
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005564void HeapObject::UpdateMapCodeCache(Handle<HeapObject> object,
5565 Handle<Name> name,
5566 Handle<Code> code) {
5567 Handle<Map> map(object->map());
5568 Map::UpdateCodeCache(map, name, code);
Kristian Monsen80d68ea2010-09-08 11:05:35 +01005569}
5570
5571
Ben Murdoch3ef787d2012-04-12 10:51:47 +01005572void JSObject::NormalizeProperties(Handle<JSObject> object,
5573 PropertyNormalizationMode mode,
Emily Bernierd0a1eb72015-03-24 16:35:39 -04005574 int expected_additional_properties,
5575 const char* reason) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005576 if (!object->HasFastProperties()) return;
5577
5578 Handle<Map> map(object->map());
Emily Bernierd0a1eb72015-03-24 16:35:39 -04005579 Handle<Map> new_map = Map::Normalize(map, mode, reason);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005580
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00005581 MigrateToMap(object, new_map, expected_additional_properties);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01005582}
5583
5584
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005585void JSObject::MigrateSlowToFast(Handle<JSObject> object,
Emily Bernierd0a1eb72015-03-24 16:35:39 -04005586 int unused_property_fields,
5587 const char* reason) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005588 if (object->HasFastProperties()) return;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00005589 DCHECK(!object->IsJSGlobalObject());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005590 Isolate* isolate = object->GetIsolate();
5591 Factory* factory = isolate->factory();
5592 Handle<NameDictionary> dictionary(object->property_dictionary());
5593
5594 // Make sure we preserve dictionary representation if there are too many
5595 // descriptors.
5596 int number_of_elements = dictionary->NumberOfElements();
5597 if (number_of_elements > kMaxNumberOfDescriptors) return;
5598
Emily Bernierd0a1eb72015-03-24 16:35:39 -04005599 Handle<FixedArray> iteration_order;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005600 if (number_of_elements != dictionary->NextEnumerationIndex()) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -04005601 iteration_order =
5602 NameDictionary::DoGenerateNewEnumerationIndices(dictionary);
5603 } else {
5604 iteration_order = NameDictionary::BuildIterationIndicesArray(dictionary);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005605 }
5606
Emily Bernierd0a1eb72015-03-24 16:35:39 -04005607 int instance_descriptor_length = iteration_order->length();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005608 int number_of_fields = 0;
5609
5610 // Compute the length of the instance descriptor.
Emily Bernierd0a1eb72015-03-24 16:35:39 -04005611 for (int i = 0; i < instance_descriptor_length; i++) {
5612 int index = Smi::cast(iteration_order->get(i))->value();
5613 DCHECK(dictionary->IsKey(dictionary->KeyAt(index)));
5614
5615 Object* value = dictionary->ValueAt(index);
5616 PropertyType type = dictionary->DetailsAt(index).type();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00005617 if (type == DATA && !value->IsJSFunction()) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -04005618 number_of_fields += 1;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005619 }
5620 }
5621
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00005622 Handle<Map> old_map(object->map(), isolate);
5623
5624 int inobject_props = old_map->GetInObjectProperties();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005625
5626 // Allocate new map.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00005627 Handle<Map> new_map = Map::CopyDropDescriptors(old_map);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005628 new_map->set_dictionary_map(false);
5629
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00005630 UpdatePrototypeUserRegistration(old_map, new_map, isolate);
5631
Emily Bernierd0a1eb72015-03-24 16:35:39 -04005632#if TRACE_MAPS
5633 if (FLAG_trace_maps) {
5634 PrintF("[TraceMaps: SlowToFast from= %p to= %p reason= %s ]\n",
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00005635 reinterpret_cast<void*>(*old_map), reinterpret_cast<void*>(*new_map),
5636 reason);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04005637 }
5638#endif
5639
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005640 if (instance_descriptor_length == 0) {
5641 DisallowHeapAllocation no_gc;
5642 DCHECK_LE(unused_property_fields, inobject_props);
5643 // Transform the object.
5644 new_map->set_unused_property_fields(inobject_props);
5645 object->synchronized_set_map(*new_map);
5646 object->set_properties(isolate->heap()->empty_fixed_array());
5647 // Check that it really works.
5648 DCHECK(object->HasFastProperties());
5649 return;
5650 }
5651
5652 // Allocate the instance descriptor.
5653 Handle<DescriptorArray> descriptors = DescriptorArray::Allocate(
Ben Murdoch097c5b22016-05-18 11:27:45 +01005654 isolate, instance_descriptor_length, 0, TENURED);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005655
5656 int number_of_allocated_fields =
5657 number_of_fields + unused_property_fields - inobject_props;
5658 if (number_of_allocated_fields < 0) {
5659 // There is enough inobject space for all fields (including unused).
5660 number_of_allocated_fields = 0;
5661 unused_property_fields = inobject_props - number_of_fields;
5662 }
5663
5664 // Allocate the fixed array for the fields.
5665 Handle<FixedArray> fields = factory->NewFixedArray(
5666 number_of_allocated_fields);
5667
5668 // Fill in the instance descriptor and the fields.
5669 int current_offset = 0;
Emily Bernierd0a1eb72015-03-24 16:35:39 -04005670 for (int i = 0; i < instance_descriptor_length; i++) {
5671 int index = Smi::cast(iteration_order->get(i))->value();
5672 Object* k = dictionary->KeyAt(index);
5673 DCHECK(dictionary->IsKey(k));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00005674 // Dictionary keys are internalized upon insertion.
5675 // TODO(jkummerow): Turn this into a DCHECK if it's not hit in the wild.
5676 CHECK(k->IsUniqueName());
5677 Handle<Name> key(Name::cast(k), isolate);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005678
Emily Bernierd0a1eb72015-03-24 16:35:39 -04005679 Object* value = dictionary->ValueAt(index);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005680
Emily Bernierd0a1eb72015-03-24 16:35:39 -04005681 PropertyDetails details = dictionary->DetailsAt(index);
5682 int enumeration_index = details.dictionary_index();
5683 PropertyType type = details.type();
5684
5685 if (value->IsJSFunction()) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00005686 DataConstantDescriptor d(key, handle(value, isolate),
5687 details.attributes());
Emily Bernierd0a1eb72015-03-24 16:35:39 -04005688 descriptors->Set(enumeration_index - 1, &d);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00005689 } else if (type == DATA) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -04005690 if (current_offset < inobject_props) {
5691 object->InObjectPropertyAtPut(current_offset, value,
5692 UPDATE_WRITE_BARRIER);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005693 } else {
Emily Bernierd0a1eb72015-03-24 16:35:39 -04005694 int offset = current_offset - inobject_props;
5695 fields->set(offset, value);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005696 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00005697 DataDescriptor d(key, current_offset, details.attributes(),
5698 // TODO(verwaest): value->OptimalRepresentation();
5699 Representation::Tagged());
Emily Bernierd0a1eb72015-03-24 16:35:39 -04005700 current_offset += d.GetDetails().field_width_in_words();
5701 descriptors->Set(enumeration_index - 1, &d);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00005702 } else if (type == ACCESSOR_CONSTANT) {
5703 AccessorConstantDescriptor d(key, handle(value, isolate),
5704 details.attributes());
Emily Bernierd0a1eb72015-03-24 16:35:39 -04005705 descriptors->Set(enumeration_index - 1, &d);
5706 } else {
5707 UNREACHABLE();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005708 }
5709 }
5710 DCHECK(current_offset == number_of_fields);
5711
5712 descriptors->Sort();
5713
Emily Bernierd0a1eb72015-03-24 16:35:39 -04005714 Handle<LayoutDescriptor> layout_descriptor = LayoutDescriptor::New(
5715 new_map, descriptors, descriptors->number_of_descriptors());
5716
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005717 DisallowHeapAllocation no_gc;
Emily Bernierd0a1eb72015-03-24 16:35:39 -04005718 new_map->InitializeDescriptors(*descriptors, *layout_descriptor);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005719 new_map->set_unused_property_fields(unused_property_fields);
5720
5721 // Transform the object.
5722 object->synchronized_set_map(*new_map);
5723
5724 object->set_properties(*fields);
5725 DCHECK(object->IsJSObject());
5726
5727 // Check that it really works.
5728 DCHECK(object->HasFastProperties());
Ben Murdoch3ef787d2012-04-12 10:51:47 +01005729}
5730
5731
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005732void JSObject::ResetElements(Handle<JSObject> object) {
5733 Isolate* isolate = object->GetIsolate();
5734 CHECK(object->map() != isolate->heap()->sloppy_arguments_elements_map());
5735 if (object->map()->has_dictionary_elements()) {
5736 Handle<SeededNumberDictionary> new_elements =
5737 SeededNumberDictionary::New(isolate, 0);
5738 object->set_elements(*new_elements);
5739 } else {
5740 object->set_elements(object->map()->GetInitialElements());
5741 }
5742}
5743
5744
5745static Handle<SeededNumberDictionary> CopyFastElementsToDictionary(
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00005746 Handle<FixedArrayBase> array, int length,
5747 Handle<SeededNumberDictionary> dictionary, bool used_as_prototype) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005748 Isolate* isolate = array->GetIsolate();
5749 Factory* factory = isolate->factory();
5750 bool has_double_elements = array->IsFixedDoubleArray();
5751 for (int i = 0; i < length; i++) {
5752 Handle<Object> value;
5753 if (has_double_elements) {
5754 Handle<FixedDoubleArray> double_array =
5755 Handle<FixedDoubleArray>::cast(array);
5756 if (double_array->is_the_hole(i)) {
5757 value = factory->the_hole_value();
5758 } else {
5759 value = factory->NewHeapNumber(double_array->get_scalar(i));
5760 }
5761 } else {
5762 value = handle(Handle<FixedArray>::cast(array)->get(i), isolate);
5763 }
5764 if (!value->IsTheHole()) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00005765 PropertyDetails details = PropertyDetails::Empty();
5766 dictionary = SeededNumberDictionary::AddNumberEntry(
5767 dictionary, i, value, details, used_as_prototype);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005768 }
5769 }
5770 return dictionary;
Steve Blocka7e24c12009-10-30 11:49:00 +00005771}
5772
5773
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00005774void JSObject::RequireSlowElements(SeededNumberDictionary* dictionary) {
5775 if (dictionary->requires_slow_elements()) return;
5776 dictionary->set_requires_slow_elements();
5777 // TODO(verwaest): Remove this hack.
5778 if (map()->is_prototype_map()) {
5779 TypeFeedbackVector::ClearAllKeyedStoreICs(GetIsolate());
5780 }
5781}
5782
5783
5784Handle<SeededNumberDictionary> JSObject::GetNormalizedElementDictionary(
5785 Handle<JSObject> object, Handle<FixedArrayBase> elements) {
5786 DCHECK(!object->HasDictionaryElements());
5787 DCHECK(!object->HasSlowArgumentsElements());
5788 Isolate* isolate = object->GetIsolate();
5789 // Ensure that notifications fire if the array or object prototypes are
5790 // normalizing.
5791 isolate->UpdateArrayProtectorOnNormalizeElements(object);
5792 int length = object->IsJSArray()
5793 ? Smi::cast(Handle<JSArray>::cast(object)->length())->value()
5794 : elements->length();
5795 int used = object->GetFastElementsUsage();
5796 Handle<SeededNumberDictionary> dictionary =
5797 SeededNumberDictionary::New(isolate, used);
5798 return CopyFastElementsToDictionary(elements, length, dictionary,
5799 object->map()->is_prototype_map());
5800}
5801
5802
Ben Murdoch3ef787d2012-04-12 10:51:47 +01005803Handle<SeededNumberDictionary> JSObject::NormalizeElements(
5804 Handle<JSObject> object) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00005805 DCHECK(!object->HasFixedTypedArrayElements());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005806 Isolate* isolate = object->GetIsolate();
Steve Block8defd9f2010-07-08 12:39:36 +01005807
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00005808 // Find the backing store.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00005809 Handle<FixedArrayBase> elements(object->elements(), isolate);
5810 bool is_arguments = object->HasSloppyArgumentsElements();
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00005811 if (is_arguments) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00005812 FixedArray* parameter_map = FixedArray::cast(*elements);
5813 elements = handle(FixedArrayBase::cast(parameter_map->get(1)), isolate);
John Reck59135872010-11-02 12:39:01 -07005814 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00005815
5816 if (elements->IsDictionary()) {
5817 return Handle<SeededNumberDictionary>::cast(elements);
5818 }
Steve Blocka7e24c12009-10-30 11:49:00 +00005819
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005820 DCHECK(object->HasFastSmiOrObjectElements() ||
5821 object->HasFastDoubleElements() ||
Ben Murdoch097c5b22016-05-18 11:27:45 +01005822 object->HasFastArgumentsElements() ||
5823 object->HasFastStringWrapperElements());
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00005824
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00005825 Handle<SeededNumberDictionary> dictionary =
5826 GetNormalizedElementDictionary(object, elements);
Steve Blocka7e24c12009-10-30 11:49:00 +00005827
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00005828 // Switch to using the dictionary as the backing storage for elements.
Ben Murdoch097c5b22016-05-18 11:27:45 +01005829 ElementsKind target_kind = is_arguments
5830 ? SLOW_SLOPPY_ARGUMENTS_ELEMENTS
5831 : object->HasFastStringWrapperElements()
5832 ? SLOW_STRING_WRAPPER_ELEMENTS
5833 : DICTIONARY_ELEMENTS;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00005834 Handle<Map> new_map = JSObject::GetElementsTransitionMap(object, target_kind);
5835 // Set the new map first to satify the elements type assert in set_elements().
5836 JSObject::MigrateToMap(object, new_map);
5837
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00005838 if (is_arguments) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005839 FixedArray::cast(object->elements())->set(1, *dictionary);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00005840 } else {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005841 object->set_elements(*dictionary);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00005842 }
5843
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005844 isolate->counters()->elements_to_dictionary()->Increment();
Steve Blocka7e24c12009-10-30 11:49:00 +00005845
5846#ifdef DEBUG
5847 if (FLAG_trace_normalization) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005848 OFStream os(stdout);
5849 os << "Object elements have been normalized:\n";
5850 object->Print(os);
Steve Blocka7e24c12009-10-30 11:49:00 +00005851 }
5852#endif
5853
Ben Murdoch097c5b22016-05-18 11:27:45 +01005854 DCHECK(object->HasDictionaryElements() ||
5855 object->HasSlowArgumentsElements() ||
5856 object->HasSlowStringWrapperElements());
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00005857 return dictionary;
Steve Blocka7e24c12009-10-30 11:49:00 +00005858}
5859
5860
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005861static Smi* GenerateIdentityHash(Isolate* isolate) {
Ben Murdoch69a99ed2011-11-30 16:03:39 +00005862 int hash_value;
5863 int attempts = 0;
5864 do {
5865 // Generate a random 32-bit hash value but limit range to fit
5866 // within a smi.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005867 hash_value = isolate->random_number_generator()->NextInt() & Smi::kMaxValue;
Ben Murdoch69a99ed2011-11-30 16:03:39 +00005868 attempts++;
5869 } while (hash_value == 0 && attempts < 30);
5870 hash_value = hash_value != 0 ? hash_value : 1; // never return 0
5871
Ben Murdoch3ef787d2012-04-12 10:51:47 +01005872 return Smi::FromInt(hash_value);
5873}
5874
5875
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005876void JSObject::SetIdentityHash(Handle<JSObject> object, Handle<Smi> hash) {
5877 DCHECK(!object->IsJSGlobalProxy());
5878 Isolate* isolate = object->GetIsolate();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00005879 Handle<Name> hash_code_symbol(isolate->heap()->hash_code_symbol());
5880 JSObject::AddProperty(object, hash_code_symbol, hash, NONE);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01005881}
5882
5883
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005884template<typename ProxyType>
5885static Handle<Smi> GetOrCreateIdentityHashHelper(Handle<ProxyType> proxy) {
5886 Isolate* isolate = proxy->GetIsolate();
Ben Murdoch3ef787d2012-04-12 10:51:47 +01005887
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005888 Handle<Object> maybe_hash(proxy->hash(), isolate);
5889 if (maybe_hash->IsSmi()) return Handle<Smi>::cast(maybe_hash);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01005890
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005891 Handle<Smi> hash(GenerateIdentityHash(isolate), isolate);
5892 proxy->set_hash(*hash);
Ben Murdoch69a99ed2011-11-30 16:03:39 +00005893 return hash;
5894}
5895
5896
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005897Object* JSObject::GetIdentityHash() {
5898 DisallowHeapAllocation no_gc;
5899 Isolate* isolate = GetIsolate();
5900 if (IsJSGlobalProxy()) {
5901 return JSGlobalProxy::cast(this)->hash();
Ben Murdoch3ef787d2012-04-12 10:51:47 +01005902 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00005903 Handle<Name> hash_code_symbol(isolate->heap()->hash_code_symbol());
5904 Handle<Object> stored_value =
5905 Object::GetPropertyOrElement(Handle<Object>(this, isolate),
5906 hash_code_symbol).ToHandleChecked();
5907 return stored_value->IsSmi() ? *stored_value
5908 : isolate->heap()->undefined_value();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005909}
5910
5911
5912Handle<Smi> JSObject::GetOrCreateIdentityHash(Handle<JSObject> object) {
5913 if (object->IsJSGlobalProxy()) {
5914 return GetOrCreateIdentityHashHelper(Handle<JSGlobalProxy>::cast(object));
5915 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005916 Isolate* isolate = object->GetIsolate();
5917
5918 Handle<Object> maybe_hash(object->GetIdentityHash(), isolate);
5919 if (maybe_hash->IsSmi()) return Handle<Smi>::cast(maybe_hash);
5920
5921 Handle<Smi> hash(GenerateIdentityHash(isolate), isolate);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00005922 Handle<Name> hash_code_symbol(isolate->heap()->hash_code_symbol());
5923 JSObject::AddProperty(object, hash_code_symbol, hash, NONE);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01005924 return hash;
5925}
5926
5927
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005928Object* JSProxy::GetIdentityHash() {
5929 return this->hash();
Ben Murdoch3ef787d2012-04-12 10:51:47 +01005930}
5931
5932
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005933Handle<Smi> JSProxy::GetOrCreateIdentityHash(Handle<JSProxy> proxy) {
5934 return GetOrCreateIdentityHashHelper(proxy);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01005935}
5936
5937
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005938Object* JSObject::GetHiddenProperty(Handle<Name> key) {
5939 DisallowHeapAllocation no_gc;
5940 DCHECK(key->IsUniqueName());
Ben Murdoch3ef787d2012-04-12 10:51:47 +01005941 if (IsJSGlobalProxy()) {
5942 // For a proxy, use the prototype as target object.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005943 PrototypeIterator iter(GetIsolate(), this);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01005944 // If the proxy is detached, return undefined.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005945 if (iter.IsAtEnd()) return GetHeap()->the_hole_value();
5946 DCHECK(iter.GetCurrent()->IsJSGlobalObject());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00005947 return iter.GetCurrent<JSObject>()->GetHiddenProperty(key);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01005948 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005949 DCHECK(!IsJSGlobalProxy());
5950 Object* inline_value = GetHiddenPropertiesHashTable();
5951
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005952 if (inline_value->IsUndefined()) return GetHeap()->the_hole_value();
5953
5954 ObjectHashTable* hashtable = ObjectHashTable::cast(inline_value);
5955 Object* entry = hashtable->Lookup(key);
5956 return entry;
5957}
5958
5959
5960Handle<Object> JSObject::SetHiddenProperty(Handle<JSObject> object,
5961 Handle<Name> key,
5962 Handle<Object> value) {
5963 Isolate* isolate = object->GetIsolate();
5964
5965 DCHECK(key->IsUniqueName());
5966 if (object->IsJSGlobalProxy()) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005967 // For a proxy, use the prototype as target object.
5968 PrototypeIterator iter(isolate, object);
5969 // If the proxy is detached, return undefined.
5970 if (iter.IsAtEnd()) return isolate->factory()->undefined_value();
5971 DCHECK(PrototypeIterator::GetCurrent(iter)->IsJSGlobalObject());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00005972 return SetHiddenProperty(PrototypeIterator::GetCurrent<JSObject>(iter), key,
5973 value);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005974 }
5975 DCHECK(!object->IsJSGlobalProxy());
5976
5977 Handle<Object> inline_value(object->GetHiddenPropertiesHashTable(), isolate);
5978
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005979 Handle<ObjectHashTable> hashtable =
5980 GetOrCreateHiddenPropertiesHashtable(object);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01005981
5982 // If it was found, check if the key is already in the dictionary.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005983 Handle<ObjectHashTable> new_table = ObjectHashTable::Put(hashtable, key,
5984 value);
5985 if (*new_table != *hashtable) {
Ben Murdoch3ef787d2012-04-12 10:51:47 +01005986 // If adding the key expanded the dictionary (i.e., Add returned a new
5987 // dictionary), store it back to the object.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005988 SetHiddenPropertiesHashTable(object, new_table);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01005989 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005990
Ben Murdoch3ef787d2012-04-12 10:51:47 +01005991 // Return this to mark success.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005992 return object;
Ben Murdoch3ef787d2012-04-12 10:51:47 +01005993}
5994
5995
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005996void JSObject::DeleteHiddenProperty(Handle<JSObject> object, Handle<Name> key) {
5997 Isolate* isolate = object->GetIsolate();
5998 DCHECK(key->IsUniqueName());
5999
6000 if (object->IsJSGlobalProxy()) {
6001 PrototypeIterator iter(isolate, object);
6002 if (iter.IsAtEnd()) return;
6003 DCHECK(PrototypeIterator::GetCurrent(iter)->IsJSGlobalObject());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00006004 return DeleteHiddenProperty(PrototypeIterator::GetCurrent<JSObject>(iter),
6005 key);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01006006 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006007
6008 Object* inline_value = object->GetHiddenPropertiesHashTable();
6009
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00006010 if (inline_value->IsUndefined()) return;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006011
6012 Handle<ObjectHashTable> hashtable(ObjectHashTable::cast(inline_value));
6013 bool was_present = false;
6014 ObjectHashTable::Remove(hashtable, key, &was_present);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01006015}
6016
6017
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006018bool JSObject::HasHiddenProperties(Handle<JSObject> object) {
Ben Murdoch097c5b22016-05-18 11:27:45 +01006019 Isolate* isolate = object->GetIsolate();
6020 Handle<Symbol> hidden = isolate->factory()->hidden_properties_symbol();
6021 LookupIterator it(object, hidden);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006022 Maybe<PropertyAttributes> maybe = GetPropertyAttributes(&it);
Ben Murdoch097c5b22016-05-18 11:27:45 +01006023 // Cannot get an exception since the hidden_properties_symbol isn't exposed to
6024 // JS.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00006025 DCHECK(maybe.IsJust());
6026 return maybe.FromJust() != ABSENT;
Ben Murdoch3ef787d2012-04-12 10:51:47 +01006027}
6028
6029
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006030Object* JSObject::GetHiddenPropertiesHashTable() {
6031 DCHECK(!IsJSGlobalProxy());
Ben Murdoch3ef787d2012-04-12 10:51:47 +01006032 if (HasFastProperties()) {
6033 // If the object has fast properties, check whether the first slot
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006034 // in the descriptor array matches the hidden string. Since the
6035 // hidden strings hash code is zero (and no other name has hash
Ben Murdoch3ef787d2012-04-12 10:51:47 +01006036 // code zero) it will always occupy the first entry if present.
6037 DescriptorArray* descriptors = this->map()->instance_descriptors();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006038 if (descriptors->number_of_descriptors() > 0) {
6039 int sorted_index = descriptors->GetSortedKeyIndex(0);
Ben Murdoch097c5b22016-05-18 11:27:45 +01006040 if (descriptors->GetKey(sorted_index) ==
6041 GetHeap()->hidden_properties_symbol() &&
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006042 sorted_index < map()->NumberOfOwnDescriptors()) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00006043 DCHECK(descriptors->GetType(sorted_index) == DATA);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006044 DCHECK(descriptors->GetDetails(sorted_index).representation().
6045 IsCompatibleForLoad(Representation::Tagged()));
6046 FieldIndex index = FieldIndex::ForDescriptor(this->map(),
6047 sorted_index);
6048 return this->RawFastPropertyAt(index);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01006049 } else {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006050 return GetHeap()->undefined_value();
Ben Murdoch3ef787d2012-04-12 10:51:47 +01006051 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006052 } else {
6053 return GetHeap()->undefined_value();
Ben Murdoch3ef787d2012-04-12 10:51:47 +01006054 }
6055 } else {
Ben Murdoch097c5b22016-05-18 11:27:45 +01006056 Handle<Symbol> hidden = GetIsolate()->factory()->hidden_properties_symbol();
6057 LookupIterator it(handle(this), hidden);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006058 // Access check is always skipped for the hidden string anyways.
6059 return *GetDataProperty(&it);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01006060 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006061}
6062
6063Handle<ObjectHashTable> JSObject::GetOrCreateHiddenPropertiesHashtable(
6064 Handle<JSObject> object) {
6065 Isolate* isolate = object->GetIsolate();
6066
6067 static const int kInitialCapacity = 4;
6068 Handle<Object> inline_value(object->GetHiddenPropertiesHashTable(), isolate);
6069 if (inline_value->IsHashTable()) {
6070 return Handle<ObjectHashTable>::cast(inline_value);
6071 }
6072
6073 Handle<ObjectHashTable> hashtable = ObjectHashTable::New(
6074 isolate, kInitialCapacity, USE_CUSTOM_MINIMUM_CAPACITY);
6075
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00006076 DCHECK(inline_value->IsUndefined());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006077 SetHiddenPropertiesHashTable(object, hashtable);
6078 return hashtable;
Ben Murdoch3ef787d2012-04-12 10:51:47 +01006079}
6080
6081
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006082Handle<Object> JSObject::SetHiddenPropertiesHashTable(Handle<JSObject> object,
6083 Handle<Object> value) {
6084 DCHECK(!object->IsJSGlobalProxy());
6085 Isolate* isolate = object->GetIsolate();
Ben Murdoch097c5b22016-05-18 11:27:45 +01006086 Handle<Symbol> name = isolate->factory()->hidden_properties_symbol();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006087 SetOwnPropertyIgnoreAttributes(object, name, value, DONT_ENUM).Assert();
6088 return object;
6089}
6090
6091
Ben Murdoch097c5b22016-05-18 11:27:45 +01006092Maybe<bool> JSObject::DeletePropertyWithInterceptor(LookupIterator* it,
6093 ShouldThrow should_throw) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00006094 Isolate* isolate = it->isolate();
6095 // Make sure that the top context does not change when doing callbacks or
6096 // interceptor calls.
6097 AssertNoContextChange ncc(isolate);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006098
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00006099 DCHECK_EQ(LookupIterator::INTERCEPTOR, it->state());
6100 Handle<InterceptorInfo> interceptor(it->GetInterceptor());
6101 if (interceptor->deleter()->IsUndefined()) return Nothing<bool>();
6102
6103 Handle<JSObject> holder = it->GetHolder<JSObject>();
6104
6105 PropertyCallbackArguments args(isolate, interceptor->data(),
Ben Murdoch097c5b22016-05-18 11:27:45 +01006106 *it->GetReceiver(), *holder, should_throw);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00006107 v8::Local<v8::Boolean> result;
6108 if (it->IsElement()) {
6109 uint32_t index = it->index();
6110 v8::IndexedPropertyDeleterCallback deleter =
6111 v8::ToCData<v8::IndexedPropertyDeleterCallback>(interceptor->deleter());
6112 LOG(isolate,
6113 ApiIndexedPropertyAccess("interceptor-indexed-delete", *holder, index));
6114 result = args.Call(deleter, index);
6115 } else if (it->name()->IsSymbol() && !interceptor->can_intercept_symbols()) {
6116 return Nothing<bool>();
6117 } else {
6118 Handle<Name> name = it->name();
6119 DCHECK(!name->IsPrivate());
6120 v8::GenericNamedPropertyDeleterCallback deleter =
6121 v8::ToCData<v8::GenericNamedPropertyDeleterCallback>(
6122 interceptor->deleter());
6123 LOG(isolate,
6124 ApiNamedPropertyAccess("interceptor-named-delete", *holder, *name));
6125 result = args.Call(deleter, v8::Utils::ToLocal(name));
Emily Bernierd0a1eb72015-03-24 16:35:39 -04006126 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006127
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00006128 RETURN_VALUE_IF_SCHEDULED_EXCEPTION(isolate, Nothing<bool>());
6129 if (result.IsEmpty()) return Nothing<bool>();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006130
6131 DCHECK(result->IsBoolean());
6132 Handle<Object> result_internal = v8::Utils::OpenHandle(*result);
6133 result_internal->VerifyApiCallResultType();
6134 // Rebox CustomArguments::kReturnValueOffset before returning.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00006135 return Just(result_internal->BooleanValue());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006136}
6137
6138
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00006139void JSReceiver::DeleteNormalizedProperty(Handle<JSReceiver> object,
6140 Handle<Name> name, int entry) {
6141 DCHECK(!object->HasFastProperties());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006142 Isolate* isolate = object->GetIsolate();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006143
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00006144 if (object->IsJSGlobalObject()) {
6145 // If we have a global object, invalidate the cell and swap in a new one.
6146 Handle<GlobalDictionary> dictionary(
6147 JSObject::cast(*object)->global_dictionary());
6148 DCHECK_NE(GlobalDictionary::kNotFound, entry);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006149
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00006150 auto cell = PropertyCell::InvalidateEntry(dictionary, entry);
6151 cell->set_value(isolate->heap()->the_hole_value());
6152 // TODO(ishell): InvalidateForDelete
6153 cell->set_property_details(
6154 cell->property_details().set_cell_type(PropertyCellType::kInvalidated));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006155 } else {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00006156 Handle<NameDictionary> dictionary(object->property_dictionary());
6157 DCHECK_NE(NameDictionary::kNotFound, entry);
Steve Blocka7e24c12009-10-30 11:49:00 +00006158
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00006159 NameDictionary::DeleteProperty(dictionary, entry);
6160 Handle<NameDictionary> new_properties =
6161 NameDictionary::Shrink(dictionary, name);
6162 object->set_properties(*new_properties);
Steve Blocka7e24c12009-10-30 11:49:00 +00006163 }
Steve Blocka7e24c12009-10-30 11:49:00 +00006164}
6165
6166
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00006167Maybe<bool> JSReceiver::DeleteProperty(LookupIterator* it,
6168 LanguageMode language_mode) {
Ben Murdoch097c5b22016-05-18 11:27:45 +01006169 it->UpdateProtector();
6170
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00006171 Isolate* isolate = it->isolate();
Steve Blocka7e24c12009-10-30 11:49:00 +00006172
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00006173 if (it->state() == LookupIterator::JSPROXY) {
6174 return JSProxy::DeletePropertyOrElement(it->GetHolder<JSProxy>(),
6175 it->GetName(), language_mode);
Steve Blocka7e24c12009-10-30 11:49:00 +00006176 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006177
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00006178 if (it->GetReceiver()->IsJSProxy()) {
6179 if (it->state() != LookupIterator::NOT_FOUND) {
6180 DCHECK_EQ(LookupIterator::DATA, it->state());
Ben Murdoch097c5b22016-05-18 11:27:45 +01006181 DCHECK(it->name()->IsPrivate());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00006182 it->Delete();
6183 }
6184 return Just(true);
6185 }
6186 Handle<JSObject> receiver = Handle<JSObject>::cast(it->GetReceiver());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006187
Ben Murdoch097c5b22016-05-18 11:27:45 +01006188 bool is_observed = receiver->map()->is_observed() &&
6189 (it->IsElement() || !it->name()->IsPrivate());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006190
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00006191 Handle<Object> old_value = it->factory()->the_hole_value();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006192
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00006193 for (; it->IsFound(); it->Next()) {
6194 switch (it->state()) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006195 case LookupIterator::JSPROXY:
6196 case LookupIterator::NOT_FOUND:
6197 case LookupIterator::TRANSITION:
6198 UNREACHABLE();
6199 case LookupIterator::ACCESS_CHECK:
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00006200 if (it->HasAccess()) break;
6201 isolate->ReportFailedAccessCheck(it->GetHolder<JSObject>());
6202 RETURN_VALUE_IF_SCHEDULED_EXCEPTION(isolate, Nothing<bool>());
6203 return Just(false);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006204 case LookupIterator::INTERCEPTOR: {
Ben Murdoch097c5b22016-05-18 11:27:45 +01006205 ShouldThrow should_throw =
6206 is_sloppy(language_mode) ? DONT_THROW : THROW_ON_ERROR;
6207 Maybe<bool> result =
6208 JSObject::DeletePropertyWithInterceptor(it, should_throw);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006209 // An exception was thrown in the interceptor. Propagate.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00006210 if (isolate->has_pending_exception()) return Nothing<bool>();
6211 // Delete with interceptor succeeded. Return result.
6212 // TODO(neis): In strict mode, we should probably throw if the
6213 // interceptor returns false.
6214 if (result.IsJust()) return result;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006215 break;
6216 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00006217 case LookupIterator::INTEGER_INDEXED_EXOTIC:
6218 return Just(true);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006219 case LookupIterator::DATA:
6220 if (is_observed) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00006221 old_value = it->GetDataValue();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006222 }
6223 // Fall through.
6224 case LookupIterator::ACCESSOR: {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00006225 if (!it->IsConfigurable() || receiver->map()->is_strong()) {
6226 // Fail if the property is not configurable, or on a strong object.
6227 if (is_strict(language_mode)) {
6228 MessageTemplate::Template templ =
6229 receiver->map()->is_strong()
6230 ? MessageTemplate::kStrongDeleteProperty
6231 : MessageTemplate::kStrictDeleteProperty;
6232 isolate->Throw(*isolate->factory()->NewTypeError(
6233 templ, it->GetName(), receiver));
6234 return Nothing<bool>();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006235 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00006236 return Just(false);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006237 }
6238
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00006239 it->Delete();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006240
6241 if (is_observed) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00006242 RETURN_ON_EXCEPTION_VALUE(
6243 isolate, JSObject::EnqueueChangeRecord(receiver, "delete",
6244 it->GetName(), old_value),
6245 Nothing<bool>());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006246 }
6247
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00006248 return Just(true);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006249 }
6250 }
6251 }
6252
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00006253 return Just(true);
Steve Blocka7e24c12009-10-30 11:49:00 +00006254}
6255
6256
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00006257Maybe<bool> JSReceiver::DeleteElement(Handle<JSReceiver> object, uint32_t index,
6258 LanguageMode language_mode) {
6259 LookupIterator it(object->GetIsolate(), object, index,
6260 LookupIterator::HIDDEN);
6261 return DeleteProperty(&it, language_mode);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01006262}
6263
6264
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00006265Maybe<bool> JSReceiver::DeleteProperty(Handle<JSReceiver> object,
6266 Handle<Name> name,
6267 LanguageMode language_mode) {
6268 LookupIterator it(object, name, LookupIterator::HIDDEN);
6269 return DeleteProperty(&it, language_mode);
6270}
6271
6272
6273Maybe<bool> JSReceiver::DeletePropertyOrElement(Handle<JSReceiver> object,
6274 Handle<Name> name,
6275 LanguageMode language_mode) {
6276 LookupIterator it = LookupIterator::PropertyOrElement(
6277 name->GetIsolate(), object, name, LookupIterator::HIDDEN);
6278 return DeleteProperty(&it, language_mode);
6279}
6280
6281
6282// ES6 7.1.14
6283MaybeHandle<Object> ToPropertyKey(Isolate* isolate, Handle<Object> value) {
6284 // 1. Let key be ToPrimitive(argument, hint String).
6285 MaybeHandle<Object> maybe_key =
6286 Object::ToPrimitive(value, ToPrimitiveHint::kString);
6287 // 2. ReturnIfAbrupt(key).
6288 Handle<Object> key;
6289 if (!maybe_key.ToHandle(&key)) return key;
6290 // 3. If Type(key) is Symbol, then return key.
6291 if (key->IsSymbol()) return key;
6292 // 4. Return ToString(key).
6293 // Extending spec'ed behavior, we'd be happy to return an element index.
6294 if (key->IsSmi()) return key;
6295 if (key->IsHeapNumber()) {
6296 uint32_t uint_value;
6297 if (value->ToArrayLength(&uint_value) &&
6298 uint_value <= static_cast<uint32_t>(Smi::kMaxValue)) {
6299 return handle(Smi::FromInt(static_cast<int>(uint_value)), isolate);
6300 }
Ben Murdoch3ef787d2012-04-12 10:51:47 +01006301 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00006302 return Object::ToString(isolate, key);
6303}
6304
6305
6306// ES6 19.1.2.4
6307// static
6308Object* JSReceiver::DefineProperty(Isolate* isolate, Handle<Object> object,
6309 Handle<Object> key,
6310 Handle<Object> attributes) {
6311 // 1. If Type(O) is not Object, throw a TypeError exception.
6312 if (!object->IsJSReceiver()) {
6313 Handle<String> fun_name =
6314 isolate->factory()->InternalizeUtf8String("Object.defineProperty");
6315 THROW_NEW_ERROR_RETURN_FAILURE(
6316 isolate, NewTypeError(MessageTemplate::kCalledOnNonObject, fun_name));
6317 }
6318 // 2. Let key be ToPropertyKey(P).
6319 // 3. ReturnIfAbrupt(key).
6320 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, key, ToPropertyKey(isolate, key));
6321 // 4. Let desc be ToPropertyDescriptor(Attributes).
6322 // 5. ReturnIfAbrupt(desc).
6323 PropertyDescriptor desc;
6324 if (!PropertyDescriptor::ToPropertyDescriptor(isolate, attributes, &desc)) {
6325 return isolate->heap()->exception();
6326 }
6327 // 6. Let success be DefinePropertyOrThrow(O,key, desc).
6328 Maybe<bool> success = DefineOwnProperty(
6329 isolate, Handle<JSReceiver>::cast(object), key, &desc, THROW_ON_ERROR);
6330 // 7. ReturnIfAbrupt(success).
6331 MAYBE_RETURN(success, isolate->heap()->exception());
6332 CHECK(success.FromJust());
6333 // 8. Return O.
6334 return *object;
6335}
6336
6337
6338// ES6 19.1.2.3.1
6339// static
6340MaybeHandle<Object> JSReceiver::DefineProperties(Isolate* isolate,
6341 Handle<Object> object,
6342 Handle<Object> properties) {
6343 // 1. If Type(O) is not Object, throw a TypeError exception.
6344 if (!object->IsJSReceiver()) {
6345 Handle<String> fun_name =
6346 isolate->factory()->InternalizeUtf8String("Object.defineProperties");
6347 THROW_NEW_ERROR(isolate,
6348 NewTypeError(MessageTemplate::kCalledOnNonObject, fun_name),
6349 Object);
6350 }
6351 // 2. Let props be ToObject(Properties).
6352 // 3. ReturnIfAbrupt(props).
6353 Handle<JSReceiver> props;
6354 if (!Object::ToObject(isolate, properties).ToHandle(&props)) {
6355 THROW_NEW_ERROR(isolate,
6356 NewTypeError(MessageTemplate::kUndefinedOrNullToObject),
6357 Object);
6358 }
6359 // 4. Let keys be props.[[OwnPropertyKeys]]().
6360 // 5. ReturnIfAbrupt(keys).
6361 Handle<FixedArray> keys;
6362 ASSIGN_RETURN_ON_EXCEPTION(
Ben Murdoch097c5b22016-05-18 11:27:45 +01006363 isolate, keys, JSReceiver::GetKeys(props, OWN_ONLY, ALL_PROPERTIES),
6364 Object);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00006365 // 6. Let descriptors be an empty List.
6366 int capacity = keys->length();
6367 std::vector<PropertyDescriptor> descriptors(capacity);
6368 size_t descriptors_index = 0;
6369 // 7. Repeat for each element nextKey of keys in List order,
6370 for (int i = 0; i < keys->length(); ++i) {
6371 Handle<Object> next_key(keys->get(i), isolate);
6372 // 7a. Let propDesc be props.[[GetOwnProperty]](nextKey).
6373 // 7b. ReturnIfAbrupt(propDesc).
6374 bool success = false;
6375 LookupIterator it = LookupIterator::PropertyOrElement(
6376 isolate, props, next_key, &success, LookupIterator::HIDDEN);
6377 DCHECK(success);
6378 Maybe<PropertyAttributes> maybe = JSReceiver::GetPropertyAttributes(&it);
6379 if (!maybe.IsJust()) return MaybeHandle<Object>();
6380 PropertyAttributes attrs = maybe.FromJust();
6381 // 7c. If propDesc is not undefined and propDesc.[[Enumerable]] is true:
6382 if (attrs == ABSENT) continue;
6383 if (attrs & DONT_ENUM) continue;
6384 // 7c i. Let descObj be Get(props, nextKey).
6385 // 7c ii. ReturnIfAbrupt(descObj).
6386 Handle<Object> desc_obj;
6387 ASSIGN_RETURN_ON_EXCEPTION(isolate, desc_obj, Object::GetProperty(&it),
6388 Object);
6389 // 7c iii. Let desc be ToPropertyDescriptor(descObj).
6390 success = PropertyDescriptor::ToPropertyDescriptor(
6391 isolate, desc_obj, &descriptors[descriptors_index]);
6392 // 7c iv. ReturnIfAbrupt(desc).
6393 if (!success) return MaybeHandle<Object>();
6394 // 7c v. Append the pair (a two element List) consisting of nextKey and
6395 // desc to the end of descriptors.
6396 descriptors[descriptors_index].set_name(next_key);
6397 descriptors_index++;
6398 }
6399 // 8. For each pair from descriptors in list order,
6400 for (size_t i = 0; i < descriptors_index; ++i) {
6401 PropertyDescriptor* desc = &descriptors[i];
6402 // 8a. Let P be the first element of pair.
6403 // 8b. Let desc be the second element of pair.
6404 // 8c. Let status be DefinePropertyOrThrow(O, P, desc).
6405 Maybe<bool> status =
6406 DefineOwnProperty(isolate, Handle<JSReceiver>::cast(object),
6407 desc->name(), desc, THROW_ON_ERROR);
6408 // 8d. ReturnIfAbrupt(status).
6409 if (!status.IsJust()) return MaybeHandle<Object>();
6410 CHECK(status.FromJust());
6411 }
6412 // 9. Return o.
6413 return object;
6414}
6415
6416
6417// static
6418Maybe<bool> JSReceiver::DefineOwnProperty(Isolate* isolate,
6419 Handle<JSReceiver> object,
6420 Handle<Object> key,
6421 PropertyDescriptor* desc,
6422 ShouldThrow should_throw) {
6423 if (object->IsJSArray()) {
6424 return JSArray::DefineOwnProperty(isolate, Handle<JSArray>::cast(object),
6425 key, desc, should_throw);
6426 }
6427 if (object->IsJSProxy()) {
6428 return JSProxy::DefineOwnProperty(isolate, Handle<JSProxy>::cast(object),
6429 key, desc, should_throw);
6430 }
6431 // TODO(jkummerow): Support Modules (ES6 9.4.6.6)
6432
6433 // OrdinaryDefineOwnProperty, by virtue of calling
6434 // DefineOwnPropertyIgnoreAttributes, can handle arguments (ES6 9.4.4.2)
6435 // and IntegerIndexedExotics (ES6 9.4.5.3), with one exception:
6436 // TODO(jkummerow): Setting an indexed accessor on a typed array should throw.
6437 return OrdinaryDefineOwnProperty(isolate, Handle<JSObject>::cast(object), key,
6438 desc, should_throw);
6439}
6440
6441
6442// static
6443Maybe<bool> JSReceiver::OrdinaryDefineOwnProperty(Isolate* isolate,
6444 Handle<JSObject> object,
6445 Handle<Object> key,
6446 PropertyDescriptor* desc,
6447 ShouldThrow should_throw) {
6448 bool success = false;
6449 DCHECK(key->IsName() || key->IsNumber()); // |key| is a PropertyKey...
6450 LookupIterator it = LookupIterator::PropertyOrElement(
6451 isolate, object, key, &success, LookupIterator::HIDDEN);
6452 DCHECK(success); // ...so creating a LookupIterator can't fail.
6453
6454 // Deal with access checks first.
6455 if (it.state() == LookupIterator::ACCESS_CHECK) {
6456 if (!it.HasAccess()) {
6457 isolate->ReportFailedAccessCheck(it.GetHolder<JSObject>());
6458 RETURN_VALUE_IF_SCHEDULED_EXCEPTION(isolate, Nothing<bool>());
6459 return Just(true);
6460 }
6461 it.Next();
6462 }
6463
6464 return OrdinaryDefineOwnProperty(&it, desc, should_throw);
6465}
6466
6467
6468// ES6 9.1.6.1
6469// static
6470Maybe<bool> JSReceiver::OrdinaryDefineOwnProperty(LookupIterator* it,
6471 PropertyDescriptor* desc,
6472 ShouldThrow should_throw) {
6473 Isolate* isolate = it->isolate();
6474 // 1. Let current be O.[[GetOwnProperty]](P).
6475 // 2. ReturnIfAbrupt(current).
6476 PropertyDescriptor current;
6477 MAYBE_RETURN(GetOwnPropertyDescriptor(it, &current), Nothing<bool>());
6478
6479 // TODO(jkummerow/verwaest): It would be nice if we didn't have to reset
6480 // the iterator every time. Currently, the reasons why we need it are:
6481 // - handle interceptors correctly
6482 // - handle accessors correctly (which might change the holder's map)
6483 it->Restart();
6484 // 3. Let extensible be the value of the [[Extensible]] internal slot of O.
6485 Handle<JSObject> object = Handle<JSObject>::cast(it->GetReceiver());
6486 bool extensible = JSObject::IsExtensible(object);
6487
6488 return ValidateAndApplyPropertyDescriptor(isolate, it, extensible, desc,
6489 &current, should_throw);
6490}
6491
6492
6493// ES6 9.1.6.2
6494// static
6495Maybe<bool> JSReceiver::IsCompatiblePropertyDescriptor(
6496 Isolate* isolate, bool extensible, PropertyDescriptor* desc,
6497 PropertyDescriptor* current, Handle<Name> property_name,
6498 ShouldThrow should_throw) {
6499 // 1. Return ValidateAndApplyPropertyDescriptor(undefined, undefined,
6500 // Extensible, Desc, Current).
6501 return ValidateAndApplyPropertyDescriptor(
6502 isolate, NULL, extensible, desc, current, should_throw, property_name);
6503}
6504
6505
6506// ES6 9.1.6.3
6507// static
6508Maybe<bool> JSReceiver::ValidateAndApplyPropertyDescriptor(
6509 Isolate* isolate, LookupIterator* it, bool extensible,
6510 PropertyDescriptor* desc, PropertyDescriptor* current,
6511 ShouldThrow should_throw, Handle<Name> property_name) {
6512 // We either need a LookupIterator, or a property name.
6513 DCHECK((it == NULL) != property_name.is_null());
6514 Handle<JSObject> object;
6515 if (it != NULL) object = Handle<JSObject>::cast(it->GetReceiver());
6516 bool desc_is_data_descriptor = PropertyDescriptor::IsDataDescriptor(desc);
6517 bool desc_is_accessor_descriptor =
6518 PropertyDescriptor::IsAccessorDescriptor(desc);
6519 bool desc_is_generic_descriptor =
6520 PropertyDescriptor::IsGenericDescriptor(desc);
6521 // 1. (Assert)
6522 // 2. If current is undefined, then
6523 if (current->is_empty()) {
6524 // 2a. If extensible is false, return false.
6525 if (!extensible) {
6526 RETURN_FAILURE(isolate, should_throw,
6527 NewTypeError(MessageTemplate::kDefineDisallowed,
6528 it != NULL ? it->GetName() : property_name));
6529 }
6530 // 2c. If IsGenericDescriptor(Desc) or IsDataDescriptor(Desc) is true, then:
6531 // (This is equivalent to !IsAccessorDescriptor(desc).)
6532 DCHECK((desc_is_generic_descriptor || desc_is_data_descriptor) ==
6533 !desc_is_accessor_descriptor);
6534 if (!desc_is_accessor_descriptor) {
6535 // 2c i. If O is not undefined, create an own data property named P of
6536 // object O whose [[Value]], [[Writable]], [[Enumerable]] and
6537 // [[Configurable]] attribute values are described by Desc. If the value
6538 // of an attribute field of Desc is absent, the attribute of the newly
6539 // created property is set to its default value.
6540 if (it != NULL) {
6541 if (!desc->has_writable()) desc->set_writable(false);
6542 if (!desc->has_enumerable()) desc->set_enumerable(false);
6543 if (!desc->has_configurable()) desc->set_configurable(false);
6544 Handle<Object> value(
6545 desc->has_value()
6546 ? desc->value()
6547 : Handle<Object>::cast(isolate->factory()->undefined_value()));
6548 MaybeHandle<Object> result =
Ben Murdoch097c5b22016-05-18 11:27:45 +01006549 JSObject::DefineOwnPropertyIgnoreAttributes(it, value,
6550 desc->ToAttributes());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00006551 if (result.is_null()) return Nothing<bool>();
6552 }
6553 } else {
6554 // 2d. Else Desc must be an accessor Property Descriptor,
6555 DCHECK(desc_is_accessor_descriptor);
6556 // 2d i. If O is not undefined, create an own accessor property named P
6557 // of object O whose [[Get]], [[Set]], [[Enumerable]] and
6558 // [[Configurable]] attribute values are described by Desc. If the value
6559 // of an attribute field of Desc is absent, the attribute of the newly
6560 // created property is set to its default value.
6561 if (it != NULL) {
6562 if (!desc->has_enumerable()) desc->set_enumerable(false);
6563 if (!desc->has_configurable()) desc->set_configurable(false);
6564 Handle<Object> getter(
6565 desc->has_get()
6566 ? desc->get()
6567 : Handle<Object>::cast(isolate->factory()->null_value()));
6568 Handle<Object> setter(
6569 desc->has_set()
6570 ? desc->set()
6571 : Handle<Object>::cast(isolate->factory()->null_value()));
6572 MaybeHandle<Object> result =
6573 JSObject::DefineAccessor(it, getter, setter, desc->ToAttributes());
6574 if (result.is_null()) return Nothing<bool>();
6575 }
6576 }
6577 // 2e. Return true.
6578 return Just(true);
6579 }
6580 // 3. Return true, if every field in Desc is absent.
6581 // 4. Return true, if every field in Desc also occurs in current and the
6582 // value of every field in Desc is the same value as the corresponding field
6583 // in current when compared using the SameValue algorithm.
6584 if ((!desc->has_enumerable() ||
6585 desc->enumerable() == current->enumerable()) &&
6586 (!desc->has_configurable() ||
6587 desc->configurable() == current->configurable()) &&
6588 (!desc->has_value() ||
6589 (current->has_value() && current->value()->SameValue(*desc->value()))) &&
6590 (!desc->has_writable() ||
6591 (current->has_writable() && current->writable() == desc->writable())) &&
6592 (!desc->has_get() ||
6593 (current->has_get() && current->get()->SameValue(*desc->get()))) &&
6594 (!desc->has_set() ||
6595 (current->has_set() && current->set()->SameValue(*desc->set())))) {
6596 return Just(true);
6597 }
6598 // 5. If the [[Configurable]] field of current is false, then
6599 if (!current->configurable()) {
6600 // 5a. Return false, if the [[Configurable]] field of Desc is true.
6601 if (desc->has_configurable() && desc->configurable()) {
6602 RETURN_FAILURE(isolate, should_throw,
6603 NewTypeError(MessageTemplate::kRedefineDisallowed,
6604 it != NULL ? it->GetName() : property_name));
6605 }
6606 // 5b. Return false, if the [[Enumerable]] field of Desc is present and the
6607 // [[Enumerable]] fields of current and Desc are the Boolean negation of
6608 // each other.
6609 if (desc->has_enumerable() && desc->enumerable() != current->enumerable()) {
6610 RETURN_FAILURE(isolate, should_throw,
6611 NewTypeError(MessageTemplate::kRedefineDisallowed,
6612 it != NULL ? it->GetName() : property_name));
6613 }
6614 }
6615
6616 bool current_is_data_descriptor =
6617 PropertyDescriptor::IsDataDescriptor(current);
6618 // 6. If IsGenericDescriptor(Desc) is true, no further validation is required.
6619 if (desc_is_generic_descriptor) {
6620 // Nothing to see here.
6621
6622 // 7. Else if IsDataDescriptor(current) and IsDataDescriptor(Desc) have
6623 // different results, then:
6624 } else if (current_is_data_descriptor != desc_is_data_descriptor) {
6625 // 7a. Return false, if the [[Configurable]] field of current is false.
6626 if (!current->configurable()) {
6627 RETURN_FAILURE(isolate, should_throw,
6628 NewTypeError(MessageTemplate::kRedefineDisallowed,
6629 it != NULL ? it->GetName() : property_name));
6630 }
6631 // 7b. If IsDataDescriptor(current) is true, then:
6632 if (current_is_data_descriptor) {
6633 // 7b i. If O is not undefined, convert the property named P of object O
6634 // from a data property to an accessor property. Preserve the existing
6635 // values of the converted property's [[Configurable]] and [[Enumerable]]
6636 // attributes and set the rest of the property's attributes to their
6637 // default values.
6638 // --> Folded into step 10.
6639 } else {
6640 // 7c i. If O is not undefined, convert the property named P of object O
6641 // from an accessor property to a data property. Preserve the existing
6642 // values of the converted property’s [[Configurable]] and [[Enumerable]]
6643 // attributes and set the rest of the property’s attributes to their
6644 // default values.
6645 // --> Folded into step 10.
6646 }
6647
6648 // 8. Else if IsDataDescriptor(current) and IsDataDescriptor(Desc) are both
6649 // true, then:
6650 } else if (current_is_data_descriptor && desc_is_data_descriptor) {
6651 // 8a. If the [[Configurable]] field of current is false, then:
6652 if (!current->configurable()) {
6653 // [Strong mode] Disallow changing writable -> readonly for
6654 // non-configurable properties.
6655 if (it != NULL && current->writable() && desc->has_writable() &&
6656 !desc->writable() && object->map()->is_strong()) {
6657 RETURN_FAILURE(isolate, should_throw,
6658 NewTypeError(MessageTemplate::kStrongRedefineDisallowed,
6659 object, it->GetName()));
6660 }
6661 // 8a i. Return false, if the [[Writable]] field of current is false and
6662 // the [[Writable]] field of Desc is true.
6663 if (!current->writable() && desc->has_writable() && desc->writable()) {
6664 RETURN_FAILURE(
6665 isolate, should_throw,
6666 NewTypeError(MessageTemplate::kRedefineDisallowed,
6667 it != NULL ? it->GetName() : property_name));
6668 }
6669 // 8a ii. If the [[Writable]] field of current is false, then:
6670 if (!current->writable()) {
6671 // 8a ii 1. Return false, if the [[Value]] field of Desc is present and
6672 // SameValue(Desc.[[Value]], current.[[Value]]) is false.
6673 if (desc->has_value() && !desc->value()->SameValue(*current->value())) {
6674 RETURN_FAILURE(
6675 isolate, should_throw,
6676 NewTypeError(MessageTemplate::kRedefineDisallowed,
6677 it != NULL ? it->GetName() : property_name));
6678 }
6679 }
6680 }
6681 } else {
6682 // 9. Else IsAccessorDescriptor(current) and IsAccessorDescriptor(Desc)
6683 // are both true,
6684 DCHECK(PropertyDescriptor::IsAccessorDescriptor(current) &&
6685 desc_is_accessor_descriptor);
6686 // 9a. If the [[Configurable]] field of current is false, then:
6687 if (!current->configurable()) {
6688 // 9a i. Return false, if the [[Set]] field of Desc is present and
6689 // SameValue(Desc.[[Set]], current.[[Set]]) is false.
6690 if (desc->has_set() && !desc->set()->SameValue(*current->set())) {
6691 RETURN_FAILURE(
6692 isolate, should_throw,
6693 NewTypeError(MessageTemplate::kRedefineDisallowed,
6694 it != NULL ? it->GetName() : property_name));
6695 }
6696 // 9a ii. Return false, if the [[Get]] field of Desc is present and
6697 // SameValue(Desc.[[Get]], current.[[Get]]) is false.
6698 if (desc->has_get() && !desc->get()->SameValue(*current->get())) {
6699 RETURN_FAILURE(
6700 isolate, should_throw,
6701 NewTypeError(MessageTemplate::kRedefineDisallowed,
6702 it != NULL ? it->GetName() : property_name));
6703 }
6704 }
6705 }
6706
6707 // 10. If O is not undefined, then:
6708 if (it != NULL) {
6709 // 10a. For each field of Desc that is present, set the corresponding
6710 // attribute of the property named P of object O to the value of the field.
6711 PropertyAttributes attrs = NONE;
6712
6713 if (desc->has_enumerable()) {
6714 attrs = static_cast<PropertyAttributes>(
6715 attrs | (desc->enumerable() ? NONE : DONT_ENUM));
6716 } else {
6717 attrs = static_cast<PropertyAttributes>(
6718 attrs | (current->enumerable() ? NONE : DONT_ENUM));
6719 }
6720 if (desc->has_configurable()) {
6721 attrs = static_cast<PropertyAttributes>(
6722 attrs | (desc->configurable() ? NONE : DONT_DELETE));
6723 } else {
6724 attrs = static_cast<PropertyAttributes>(
6725 attrs | (current->configurable() ? NONE : DONT_DELETE));
6726 }
6727 if (desc_is_data_descriptor ||
6728 (desc_is_generic_descriptor && current_is_data_descriptor)) {
6729 if (desc->has_writable()) {
6730 attrs = static_cast<PropertyAttributes>(
6731 attrs | (desc->writable() ? NONE : READ_ONLY));
6732 } else {
6733 attrs = static_cast<PropertyAttributes>(
6734 attrs | (current->writable() ? NONE : READ_ONLY));
6735 }
6736 Handle<Object> value(
6737 desc->has_value() ? desc->value()
6738 : current->has_value()
6739 ? current->value()
6740 : Handle<Object>::cast(
6741 isolate->factory()->undefined_value()));
Ben Murdoch097c5b22016-05-18 11:27:45 +01006742 MaybeHandle<Object> result =
6743 JSObject::DefineOwnPropertyIgnoreAttributes(it, value, attrs);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00006744 if (result.is_null()) return Nothing<bool>();
6745 } else {
6746 DCHECK(desc_is_accessor_descriptor ||
6747 (desc_is_generic_descriptor &&
6748 PropertyDescriptor::IsAccessorDescriptor(current)));
6749 Handle<Object> getter(
6750 desc->has_get()
6751 ? desc->get()
6752 : current->has_get()
6753 ? current->get()
6754 : Handle<Object>::cast(isolate->factory()->null_value()));
6755 Handle<Object> setter(
6756 desc->has_set()
6757 ? desc->set()
6758 : current->has_set()
6759 ? current->set()
6760 : Handle<Object>::cast(isolate->factory()->null_value()));
6761 MaybeHandle<Object> result =
6762 JSObject::DefineAccessor(it, getter, setter, attrs);
6763 if (result.is_null()) return Nothing<bool>();
6764 }
6765 }
6766
6767 // 11. Return true.
6768 return Just(true);
6769}
6770
6771
6772// static
6773Maybe<bool> JSReceiver::CreateDataProperty(LookupIterator* it,
6774 Handle<Object> value,
6775 ShouldThrow should_throw) {
6776 DCHECK(!it->check_prototype_chain());
6777 Handle<JSReceiver> receiver = Handle<JSReceiver>::cast(it->GetReceiver());
6778 Isolate* isolate = receiver->GetIsolate();
6779
6780 if (receiver->IsJSObject()) {
6781 return JSObject::CreateDataProperty(it, value); // Shortcut.
6782 }
6783
6784 PropertyDescriptor new_desc;
6785 new_desc.set_value(value);
6786 new_desc.set_writable(true);
6787 new_desc.set_enumerable(true);
6788 new_desc.set_configurable(true);
6789
6790 return JSReceiver::DefineOwnProperty(isolate, receiver, it->GetName(),
6791 &new_desc, should_throw);
6792}
6793
6794
6795Maybe<bool> JSObject::CreateDataProperty(LookupIterator* it,
6796 Handle<Object> value) {
6797 DCHECK(it->GetReceiver()->IsJSObject());
6798 MAYBE_RETURN(JSReceiver::GetPropertyAttributes(it), Nothing<bool>());
6799
6800 if (it->IsFound()) {
6801 if (!it->IsConfigurable()) return Just(false);
6802 } else {
6803 if (!JSObject::IsExtensible(Handle<JSObject>::cast(it->GetReceiver())))
6804 return Just(false);
6805 }
6806
Ben Murdoch097c5b22016-05-18 11:27:45 +01006807 RETURN_ON_EXCEPTION_VALUE(it->isolate(),
6808 DefineOwnPropertyIgnoreAttributes(it, value, NONE),
6809 Nothing<bool>());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00006810
6811 return Just(true);
6812}
6813
6814
6815// TODO(jkummerow): Consider unification with FastAsArrayLength() in
6816// accessors.cc.
6817bool PropertyKeyToArrayLength(Handle<Object> value, uint32_t* length) {
6818 DCHECK(value->IsNumber() || value->IsName());
6819 if (value->ToArrayLength(length)) return true;
6820 if (value->IsString()) return String::cast(*value)->AsArrayIndex(length);
6821 return false;
6822}
6823
6824
6825bool PropertyKeyToArrayIndex(Handle<Object> index_obj, uint32_t* output) {
6826 return PropertyKeyToArrayLength(index_obj, output) && *output != kMaxUInt32;
6827}
6828
6829
6830// ES6 9.4.2.1
6831// static
6832Maybe<bool> JSArray::DefineOwnProperty(Isolate* isolate, Handle<JSArray> o,
6833 Handle<Object> name,
6834 PropertyDescriptor* desc,
6835 ShouldThrow should_throw) {
6836 // 1. Assert: IsPropertyKey(P) is true. ("P" is |name|.)
6837 // 2. If P is "length", then:
6838 // TODO(jkummerow): Check if we need slow string comparison.
6839 if (*name == isolate->heap()->length_string()) {
6840 // 2a. Return ArraySetLength(A, Desc).
6841 return ArraySetLength(isolate, o, desc, should_throw);
6842 }
6843 // 3. Else if P is an array index, then:
6844 uint32_t index = 0;
6845 if (PropertyKeyToArrayIndex(name, &index)) {
6846 // 3a. Let oldLenDesc be OrdinaryGetOwnProperty(A, "length").
6847 PropertyDescriptor old_len_desc;
6848 Maybe<bool> success = GetOwnPropertyDescriptor(
6849 isolate, o, isolate->factory()->length_string(), &old_len_desc);
6850 // 3b. (Assert)
6851 DCHECK(success.FromJust());
6852 USE(success);
6853 // 3c. Let oldLen be oldLenDesc.[[Value]].
6854 uint32_t old_len = 0;
6855 CHECK(old_len_desc.value()->ToArrayLength(&old_len));
6856 // 3d. Let index be ToUint32(P).
6857 // (Already done above.)
6858 // 3e. (Assert)
6859 // 3f. If index >= oldLen and oldLenDesc.[[Writable]] is false,
6860 // return false.
6861 if (index >= old_len && old_len_desc.has_writable() &&
6862 !old_len_desc.writable()) {
6863 RETURN_FAILURE(isolate, should_throw,
6864 NewTypeError(MessageTemplate::kDefineDisallowed, name));
6865 }
6866 // 3g. Let succeeded be OrdinaryDefineOwnProperty(A, P, Desc).
6867 Maybe<bool> succeeded =
6868 OrdinaryDefineOwnProperty(isolate, o, name, desc, should_throw);
6869 // 3h. Assert: succeeded is not an abrupt completion.
6870 // In our case, if should_throw == THROW_ON_ERROR, it can be!
6871 // 3i. If succeeded is false, return false.
6872 if (succeeded.IsNothing() || !succeeded.FromJust()) return succeeded;
6873 // 3j. If index >= oldLen, then:
6874 if (index >= old_len) {
6875 // 3j i. Set oldLenDesc.[[Value]] to index + 1.
6876 old_len_desc.set_value(isolate->factory()->NewNumberFromUint(index + 1));
6877 // 3j ii. Let succeeded be
6878 // OrdinaryDefineOwnProperty(A, "length", oldLenDesc).
6879 succeeded = OrdinaryDefineOwnProperty(isolate, o,
6880 isolate->factory()->length_string(),
6881 &old_len_desc, should_throw);
6882 // 3j iii. Assert: succeeded is true.
6883 DCHECK(succeeded.FromJust());
6884 USE(succeeded);
6885 }
6886 // 3k. Return true.
6887 return Just(true);
6888 }
6889
6890 // 4. Return OrdinaryDefineOwnProperty(A, P, Desc).
6891 return OrdinaryDefineOwnProperty(isolate, o, name, desc, should_throw);
6892}
6893
6894
6895// Part of ES6 9.4.2.4 ArraySetLength.
6896// static
6897bool JSArray::AnythingToArrayLength(Isolate* isolate,
6898 Handle<Object> length_object,
6899 uint32_t* output) {
6900 // Fast path: check numbers and strings that can be converted directly
6901 // and unobservably.
6902 if (length_object->ToArrayLength(output)) return true;
6903 if (length_object->IsString() &&
6904 Handle<String>::cast(length_object)->AsArrayIndex(output)) {
6905 return true;
6906 }
6907 // Slow path: follow steps in ES6 9.4.2.4 "ArraySetLength".
6908 // 3. Let newLen be ToUint32(Desc.[[Value]]).
6909 Handle<Object> uint32_v;
6910 if (!Object::ToUint32(isolate, length_object).ToHandle(&uint32_v)) {
6911 // 4. ReturnIfAbrupt(newLen).
6912 return false;
6913 }
6914 // 5. Let numberLen be ToNumber(Desc.[[Value]]).
6915 Handle<Object> number_v;
6916 if (!Object::ToNumber(length_object).ToHandle(&number_v)) {
6917 // 6. ReturnIfAbrupt(newLen).
6918 return false;
6919 }
6920 // 7. If newLen != numberLen, throw a RangeError exception.
6921 if (uint32_v->Number() != number_v->Number()) {
6922 Handle<Object> exception =
6923 isolate->factory()->NewRangeError(MessageTemplate::kInvalidArrayLength);
6924 isolate->Throw(*exception);
6925 return false;
6926 }
6927 CHECK(uint32_v->ToArrayLength(output));
6928 return true;
6929}
6930
6931
6932// ES6 9.4.2.4
6933// static
6934Maybe<bool> JSArray::ArraySetLength(Isolate* isolate, Handle<JSArray> a,
6935 PropertyDescriptor* desc,
6936 ShouldThrow should_throw) {
6937 // 1. If the [[Value]] field of Desc is absent, then
6938 if (!desc->has_value()) {
6939 // 1a. Return OrdinaryDefineOwnProperty(A, "length", Desc).
6940 return OrdinaryDefineOwnProperty(
6941 isolate, a, isolate->factory()->length_string(), desc, should_throw);
6942 }
6943 // 2. Let newLenDesc be a copy of Desc.
6944 // (Actual copying is not necessary.)
6945 PropertyDescriptor* new_len_desc = desc;
6946 // 3. - 7. Convert Desc.[[Value]] to newLen.
6947 uint32_t new_len = 0;
6948 if (!AnythingToArrayLength(isolate, desc->value(), &new_len)) {
6949 DCHECK(isolate->has_pending_exception());
6950 return Nothing<bool>();
6951 }
6952 // 8. Set newLenDesc.[[Value]] to newLen.
6953 // (Done below, if needed.)
6954 // 9. Let oldLenDesc be OrdinaryGetOwnProperty(A, "length").
6955 PropertyDescriptor old_len_desc;
6956 Maybe<bool> success = GetOwnPropertyDescriptor(
6957 isolate, a, isolate->factory()->length_string(), &old_len_desc);
6958 // 10. (Assert)
6959 DCHECK(success.FromJust());
6960 USE(success);
6961 // 11. Let oldLen be oldLenDesc.[[Value]].
6962 uint32_t old_len = 0;
6963 CHECK(old_len_desc.value()->ToArrayLength(&old_len));
6964 // 12. If newLen >= oldLen, then
6965 if (new_len >= old_len) {
6966 // 8. Set newLenDesc.[[Value]] to newLen.
6967 // 12a. Return OrdinaryDefineOwnProperty(A, "length", newLenDesc).
6968 new_len_desc->set_value(isolate->factory()->NewNumberFromUint(new_len));
6969 return OrdinaryDefineOwnProperty(isolate, a,
6970 isolate->factory()->length_string(),
6971 new_len_desc, should_throw);
6972 }
6973 // 13. If oldLenDesc.[[Writable]] is false, return false.
6974 if (!old_len_desc.writable()) {
6975 RETURN_FAILURE(isolate, should_throw,
6976 NewTypeError(MessageTemplate::kRedefineDisallowed,
6977 isolate->factory()->length_string()));
6978 }
6979 // 14. If newLenDesc.[[Writable]] is absent or has the value true,
6980 // let newWritable be true.
6981 bool new_writable = false;
6982 if (!new_len_desc->has_writable() || new_len_desc->writable()) {
6983 new_writable = true;
6984 } else {
6985 // 15. Else,
6986 // 15a. Need to defer setting the [[Writable]] attribute to false in case
6987 // any elements cannot be deleted.
6988 // 15b. Let newWritable be false. (It's initialized as "false" anyway.)
6989 // 15c. Set newLenDesc.[[Writable]] to true.
6990 // (Not needed.)
6991 }
6992 // Most of steps 16 through 19 is implemented by JSArray::SetLength.
6993 if (JSArray::ObservableSetLength(a, new_len).is_null()) {
6994 DCHECK(isolate->has_pending_exception());
6995 return Nothing<bool>();
6996 }
6997 // Steps 19d-ii, 20.
6998 if (!new_writable) {
6999 PropertyDescriptor readonly;
7000 readonly.set_writable(false);
7001 Maybe<bool> success = OrdinaryDefineOwnProperty(
7002 isolate, a, isolate->factory()->length_string(), &readonly,
7003 should_throw);
7004 DCHECK(success.FromJust());
7005 USE(success);
7006 }
7007 uint32_t actual_new_len = 0;
7008 CHECK(a->length()->ToArrayLength(&actual_new_len));
7009 // Steps 19d-v, 21. Return false if there were non-deletable elements.
7010 bool result = actual_new_len == new_len;
7011 if (!result) {
7012 RETURN_FAILURE(
7013 isolate, should_throw,
7014 NewTypeError(MessageTemplate::kStrictDeleteProperty,
7015 isolate->factory()->NewNumberFromUint(actual_new_len - 1),
7016 a));
7017 }
7018 return Just(result);
7019}
7020
7021
7022// ES6 9.5.6
7023// static
7024Maybe<bool> JSProxy::DefineOwnProperty(Isolate* isolate, Handle<JSProxy> proxy,
7025 Handle<Object> key,
7026 PropertyDescriptor* desc,
7027 ShouldThrow should_throw) {
7028 STACK_CHECK(Nothing<bool>());
7029 if (key->IsSymbol() && Handle<Symbol>::cast(key)->IsPrivate()) {
Ben Murdoch097c5b22016-05-18 11:27:45 +01007030 return SetPrivateProperty(isolate, proxy, Handle<Symbol>::cast(key), desc,
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00007031 should_throw);
7032 }
7033 Handle<String> trap_name = isolate->factory()->defineProperty_string();
7034 // 1. Assert: IsPropertyKey(P) is true.
7035 DCHECK(key->IsName() || key->IsNumber());
7036 // 2. Let handler be the value of the [[ProxyHandler]] internal slot of O.
7037 Handle<Object> handler(proxy->handler(), isolate);
7038 // 3. If handler is null, throw a TypeError exception.
7039 // 4. Assert: Type(handler) is Object.
7040 if (proxy->IsRevoked()) {
7041 isolate->Throw(*isolate->factory()->NewTypeError(
7042 MessageTemplate::kProxyRevoked, trap_name));
7043 return Nothing<bool>();
7044 }
7045 // 5. Let target be the value of the [[ProxyTarget]] internal slot of O.
7046 Handle<JSReceiver> target(proxy->target(), isolate);
7047 // 6. Let trap be ? GetMethod(handler, "defineProperty").
7048 Handle<Object> trap;
7049 ASSIGN_RETURN_ON_EXCEPTION_VALUE(
7050 isolate, trap,
7051 Object::GetMethod(Handle<JSReceiver>::cast(handler), trap_name),
7052 Nothing<bool>());
7053 // 7. If trap is undefined, then:
7054 if (trap->IsUndefined()) {
7055 // 7a. Return target.[[DefineOwnProperty]](P, Desc).
7056 return JSReceiver::DefineOwnProperty(isolate, target, key, desc,
7057 should_throw);
7058 }
7059 // 8. Let descObj be FromPropertyDescriptor(Desc).
7060 Handle<Object> desc_obj = desc->ToObject(isolate);
7061 // 9. Let booleanTrapResult be
7062 // ToBoolean(? Call(trap, handler, «target, P, descObj»)).
7063 Handle<Name> property_name =
7064 key->IsName()
7065 ? Handle<Name>::cast(key)
7066 : Handle<Name>::cast(isolate->factory()->NumberToString(key));
7067 // Do not leak private property names.
7068 DCHECK(!property_name->IsPrivate());
7069 Handle<Object> trap_result_obj;
7070 Handle<Object> args[] = {target, property_name, desc_obj};
7071 ASSIGN_RETURN_ON_EXCEPTION_VALUE(
7072 isolate, trap_result_obj,
7073 Execution::Call(isolate, trap, handler, arraysize(args), args),
7074 Nothing<bool>());
7075 // 10. If booleanTrapResult is false, return false.
7076 if (!trap_result_obj->BooleanValue()) {
7077 RETURN_FAILURE(isolate, should_throw,
7078 NewTypeError(MessageTemplate::kProxyTrapReturnedFalsishFor,
7079 trap_name, property_name));
7080 }
7081 // 11. Let targetDesc be ? target.[[GetOwnProperty]](P).
7082 PropertyDescriptor target_desc;
7083 Maybe<bool> target_found =
7084 JSReceiver::GetOwnPropertyDescriptor(isolate, target, key, &target_desc);
7085 MAYBE_RETURN(target_found, Nothing<bool>());
7086 // 12. Let extensibleTarget be ? IsExtensible(target).
7087 Maybe<bool> maybe_extensible = JSReceiver::IsExtensible(target);
7088 MAYBE_RETURN(maybe_extensible, Nothing<bool>());
7089 bool extensible_target = maybe_extensible.FromJust();
7090 // 13. If Desc has a [[Configurable]] field and if Desc.[[Configurable]]
7091 // is false, then:
7092 // 13a. Let settingConfigFalse be true.
7093 // 14. Else let settingConfigFalse be false.
7094 bool setting_config_false = desc->has_configurable() && !desc->configurable();
7095 // 15. If targetDesc is undefined, then
7096 if (!target_found.FromJust()) {
7097 // 15a. If extensibleTarget is false, throw a TypeError exception.
7098 if (!extensible_target) {
7099 isolate->Throw(*isolate->factory()->NewTypeError(
7100 MessageTemplate::kProxyDefinePropertyNonExtensible, property_name));
7101 return Nothing<bool>();
7102 }
7103 // 15b. If settingConfigFalse is true, throw a TypeError exception.
7104 if (setting_config_false) {
7105 isolate->Throw(*isolate->factory()->NewTypeError(
7106 MessageTemplate::kProxyDefinePropertyNonConfigurable, property_name));
7107 return Nothing<bool>();
7108 }
7109 } else {
7110 // 16. Else targetDesc is not undefined,
7111 // 16a. If IsCompatiblePropertyDescriptor(extensibleTarget, Desc,
7112 // targetDesc) is false, throw a TypeError exception.
7113 Maybe<bool> valid =
7114 IsCompatiblePropertyDescriptor(isolate, extensible_target, desc,
7115 &target_desc, property_name, DONT_THROW);
7116 MAYBE_RETURN(valid, Nothing<bool>());
7117 if (!valid.FromJust()) {
7118 isolate->Throw(*isolate->factory()->NewTypeError(
7119 MessageTemplate::kProxyDefinePropertyIncompatible, property_name));
7120 return Nothing<bool>();
7121 }
7122 // 16b. If settingConfigFalse is true and targetDesc.[[Configurable]] is
7123 // true, throw a TypeError exception.
7124 if (setting_config_false && target_desc.configurable()) {
7125 isolate->Throw(*isolate->factory()->NewTypeError(
7126 MessageTemplate::kProxyDefinePropertyNonConfigurable, property_name));
7127 return Nothing<bool>();
7128 }
7129 }
7130 // 17. Return true.
7131 return Just(true);
7132}
7133
7134
7135// static
Ben Murdoch097c5b22016-05-18 11:27:45 +01007136Maybe<bool> JSProxy::SetPrivateProperty(Isolate* isolate, Handle<JSProxy> proxy,
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00007137 Handle<Symbol> private_name,
7138 PropertyDescriptor* desc,
7139 ShouldThrow should_throw) {
7140 // Despite the generic name, this can only add private data properties.
7141 if (!PropertyDescriptor::IsDataDescriptor(desc) ||
7142 desc->ToAttributes() != DONT_ENUM) {
7143 RETURN_FAILURE(isolate, should_throw,
7144 NewTypeError(MessageTemplate::kProxyPrivate));
7145 }
7146 DCHECK(proxy->map()->is_dictionary_map());
7147 Handle<Object> value =
7148 desc->has_value()
7149 ? desc->value()
7150 : Handle<Object>::cast(isolate->factory()->undefined_value());
7151
7152 LookupIterator it(proxy, private_name);
7153
7154 if (it.IsFound()) {
7155 DCHECK_EQ(LookupIterator::DATA, it.state());
Ben Murdoch097c5b22016-05-18 11:27:45 +01007156 DCHECK_EQ(DONT_ENUM, it.property_attributes());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00007157 it.WriteDataValue(value);
7158 return Just(true);
7159 }
7160
7161 Handle<NameDictionary> dict(proxy->property_dictionary());
7162 PropertyDetails details(DONT_ENUM, DATA, 0, PropertyCellType::kNoCell);
7163 Handle<NameDictionary> result =
7164 NameDictionary::Add(dict, private_name, value, details);
7165 if (!dict.is_identical_to(result)) proxy->set_properties(*result);
7166 return Just(true);
7167}
7168
7169
7170// static
7171Maybe<bool> JSReceiver::GetOwnPropertyDescriptor(Isolate* isolate,
7172 Handle<JSReceiver> object,
7173 Handle<Object> key,
7174 PropertyDescriptor* desc) {
7175 bool success = false;
7176 DCHECK(key->IsName() || key->IsNumber()); // |key| is a PropertyKey...
7177 LookupIterator it = LookupIterator::PropertyOrElement(
7178 isolate, object, key, &success, LookupIterator::HIDDEN);
7179 DCHECK(success); // ...so creating a LookupIterator can't fail.
7180 return GetOwnPropertyDescriptor(&it, desc);
7181}
7182
7183
7184// ES6 9.1.5.1
7185// Returns true on success, false if the property didn't exist, nothing if
7186// an exception was thrown.
7187// static
7188Maybe<bool> JSReceiver::GetOwnPropertyDescriptor(LookupIterator* it,
7189 PropertyDescriptor* desc) {
7190 Isolate* isolate = it->isolate();
7191 // "Virtual" dispatch.
7192 if (it->IsFound() && it->GetHolder<JSReceiver>()->IsJSProxy()) {
7193 return JSProxy::GetOwnPropertyDescriptor(isolate, it->GetHolder<JSProxy>(),
7194 it->GetName(), desc);
7195 }
7196
7197 // 1. (Assert)
7198 // 2. If O does not have an own property with key P, return undefined.
7199 Maybe<PropertyAttributes> maybe = JSObject::GetPropertyAttributes(it);
7200 MAYBE_RETURN(maybe, Nothing<bool>());
7201 PropertyAttributes attrs = maybe.FromJust();
7202 if (attrs == ABSENT) return Just(false);
7203 DCHECK(!isolate->has_pending_exception());
7204
7205 // 3. Let D be a newly created Property Descriptor with no fields.
7206 DCHECK(desc->is_empty());
7207 // 4. Let X be O's own property whose key is P.
7208 // 5. If X is a data property, then
7209 bool is_accessor_pair = it->state() == LookupIterator::ACCESSOR &&
7210 it->GetAccessors()->IsAccessorPair();
7211 if (!is_accessor_pair) {
7212 // 5a. Set D.[[Value]] to the value of X's [[Value]] attribute.
7213 Handle<Object> value;
7214 if (!JSObject::GetProperty(it).ToHandle(&value)) {
7215 DCHECK(isolate->has_pending_exception());
7216 return Nothing<bool>();
7217 }
7218 desc->set_value(value);
7219 // 5b. Set D.[[Writable]] to the value of X's [[Writable]] attribute
7220 desc->set_writable((attrs & READ_ONLY) == 0);
7221 } else {
7222 // 6. Else X is an accessor property, so
7223 Handle<AccessorPair> accessors =
7224 Handle<AccessorPair>::cast(it->GetAccessors());
7225 // 6a. Set D.[[Get]] to the value of X's [[Get]] attribute.
Ben Murdoch097c5b22016-05-18 11:27:45 +01007226 desc->set_get(AccessorPair::GetComponent(accessors, ACCESSOR_GETTER));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00007227 // 6b. Set D.[[Set]] to the value of X's [[Set]] attribute.
Ben Murdoch097c5b22016-05-18 11:27:45 +01007228 desc->set_set(AccessorPair::GetComponent(accessors, ACCESSOR_SETTER));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00007229 }
7230
7231 // 7. Set D.[[Enumerable]] to the value of X's [[Enumerable]] attribute.
7232 desc->set_enumerable((attrs & DONT_ENUM) == 0);
7233 // 8. Set D.[[Configurable]] to the value of X's [[Configurable]] attribute.
7234 desc->set_configurable((attrs & DONT_DELETE) == 0);
7235 // 9. Return D.
7236 DCHECK(PropertyDescriptor::IsAccessorDescriptor(desc) !=
7237 PropertyDescriptor::IsDataDescriptor(desc));
7238 return Just(true);
7239}
7240
7241
7242// ES6 9.5.5
7243// static
7244Maybe<bool> JSProxy::GetOwnPropertyDescriptor(Isolate* isolate,
7245 Handle<JSProxy> proxy,
7246 Handle<Name> name,
7247 PropertyDescriptor* desc) {
7248 DCHECK(!name->IsPrivate());
7249 STACK_CHECK(Nothing<bool>());
7250
7251 Handle<String> trap_name =
7252 isolate->factory()->getOwnPropertyDescriptor_string();
7253 // 1. (Assert)
7254 // 2. Let handler be the value of the [[ProxyHandler]] internal slot of O.
7255 Handle<Object> handler(proxy->handler(), isolate);
7256 // 3. If handler is null, throw a TypeError exception.
7257 // 4. Assert: Type(handler) is Object.
7258 if (proxy->IsRevoked()) {
7259 isolate->Throw(*isolate->factory()->NewTypeError(
7260 MessageTemplate::kProxyRevoked, trap_name));
7261 return Nothing<bool>();
7262 }
7263 // 5. Let target be the value of the [[ProxyTarget]] internal slot of O.
7264 Handle<JSReceiver> target(proxy->target(), isolate);
7265 // 6. Let trap be ? GetMethod(handler, "getOwnPropertyDescriptor").
7266 Handle<Object> trap;
7267 ASSIGN_RETURN_ON_EXCEPTION_VALUE(
7268 isolate, trap,
7269 Object::GetMethod(Handle<JSReceiver>::cast(handler), trap_name),
7270 Nothing<bool>());
7271 // 7. If trap is undefined, then
7272 if (trap->IsUndefined()) {
7273 // 7a. Return target.[[GetOwnProperty]](P).
7274 return JSReceiver::GetOwnPropertyDescriptor(isolate, target, name, desc);
7275 }
7276 // 8. Let trapResultObj be ? Call(trap, handler, «target, P»).
7277 Handle<Object> trap_result_obj;
7278 Handle<Object> args[] = {target, name};
7279 ASSIGN_RETURN_ON_EXCEPTION_VALUE(
7280 isolate, trap_result_obj,
7281 Execution::Call(isolate, trap, handler, arraysize(args), args),
7282 Nothing<bool>());
7283 // 9. If Type(trapResultObj) is neither Object nor Undefined, throw a
7284 // TypeError exception.
7285 if (!trap_result_obj->IsJSReceiver() && !trap_result_obj->IsUndefined()) {
7286 isolate->Throw(*isolate->factory()->NewTypeError(
7287 MessageTemplate::kProxyGetOwnPropertyDescriptorInvalid, name));
7288 return Nothing<bool>();
7289 }
7290 // 10. Let targetDesc be ? target.[[GetOwnProperty]](P).
7291 PropertyDescriptor target_desc;
7292 Maybe<bool> found =
7293 JSReceiver::GetOwnPropertyDescriptor(isolate, target, name, &target_desc);
7294 MAYBE_RETURN(found, Nothing<bool>());
7295 // 11. If trapResultObj is undefined, then
7296 if (trap_result_obj->IsUndefined()) {
7297 // 11a. If targetDesc is undefined, return undefined.
7298 if (!found.FromJust()) return Just(false);
7299 // 11b. If targetDesc.[[Configurable]] is false, throw a TypeError
7300 // exception.
7301 if (!target_desc.configurable()) {
7302 isolate->Throw(*isolate->factory()->NewTypeError(
7303 MessageTemplate::kProxyGetOwnPropertyDescriptorUndefined, name));
7304 return Nothing<bool>();
7305 }
7306 // 11c. Let extensibleTarget be ? IsExtensible(target).
7307 Maybe<bool> extensible_target = JSReceiver::IsExtensible(target);
7308 MAYBE_RETURN(extensible_target, Nothing<bool>());
7309 // 11d. (Assert)
7310 // 11e. If extensibleTarget is false, throw a TypeError exception.
7311 if (!extensible_target.FromJust()) {
7312 isolate->Throw(*isolate->factory()->NewTypeError(
7313 MessageTemplate::kProxyGetOwnPropertyDescriptorNonExtensible, name));
7314 return Nothing<bool>();
7315 }
7316 // 11f. Return undefined.
7317 return Just(false);
7318 }
7319 // 12. Let extensibleTarget be ? IsExtensible(target).
7320 Maybe<bool> extensible_target = JSReceiver::IsExtensible(target);
7321 MAYBE_RETURN(extensible_target, Nothing<bool>());
7322 // 13. Let resultDesc be ? ToPropertyDescriptor(trapResultObj).
7323 if (!PropertyDescriptor::ToPropertyDescriptor(isolate, trap_result_obj,
7324 desc)) {
7325 DCHECK(isolate->has_pending_exception());
7326 return Nothing<bool>();
7327 }
7328 // 14. Call CompletePropertyDescriptor(resultDesc).
7329 PropertyDescriptor::CompletePropertyDescriptor(isolate, desc);
7330 // 15. Let valid be IsCompatiblePropertyDescriptor (extensibleTarget,
7331 // resultDesc, targetDesc).
7332 Maybe<bool> valid =
7333 IsCompatiblePropertyDescriptor(isolate, extensible_target.FromJust(),
7334 desc, &target_desc, name, DONT_THROW);
7335 MAYBE_RETURN(valid, Nothing<bool>());
7336 // 16. If valid is false, throw a TypeError exception.
7337 if (!valid.FromJust()) {
7338 isolate->Throw(*isolate->factory()->NewTypeError(
7339 MessageTemplate::kProxyGetOwnPropertyDescriptorIncompatible, name));
7340 return Nothing<bool>();
7341 }
7342 // 17. If resultDesc.[[Configurable]] is false, then
7343 if (!desc->configurable()) {
7344 // 17a. If targetDesc is undefined or targetDesc.[[Configurable]] is true:
7345 if (target_desc.is_empty() || target_desc.configurable()) {
7346 // 17a i. Throw a TypeError exception.
7347 isolate->Throw(*isolate->factory()->NewTypeError(
7348 MessageTemplate::kProxyGetOwnPropertyDescriptorNonConfigurable,
7349 name));
7350 return Nothing<bool>();
7351 }
7352 }
7353 // 18. Return resultDesc.
7354 return Just(true);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01007355}
7356
7357
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00007358bool JSObject::ReferencesObjectFromElements(FixedArray* elements,
7359 ElementsKind kind,
7360 Object* object) {
Ben Murdoch097c5b22016-05-18 11:27:45 +01007361 if (IsFastObjectElementsKind(kind) || kind == FAST_STRING_WRAPPER_ELEMENTS) {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00007362 int length = IsJSArray()
7363 ? Smi::cast(JSArray::cast(this)->length())->value()
7364 : elements->length();
7365 for (int i = 0; i < length; ++i) {
7366 Object* element = elements->get(i);
7367 if (!element->IsTheHole() && element == object) return true;
7368 }
7369 } else {
Ben Murdoch097c5b22016-05-18 11:27:45 +01007370 DCHECK(kind == DICTIONARY_ELEMENTS || kind == SLOW_STRING_WRAPPER_ELEMENTS);
Ben Murdochc7cc0282012-03-05 14:35:55 +00007371 Object* key =
7372 SeededNumberDictionary::cast(elements)->SlowReverseLookup(object);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00007373 if (!key->IsUndefined()) return true;
7374 }
7375 return false;
7376}
7377
7378
Steve Blocka7e24c12009-10-30 11:49:00 +00007379// Check whether this object references another object.
7380bool JSObject::ReferencesObject(Object* obj) {
Ben Murdoch8b112d22011-06-08 16:22:53 +01007381 Map* map_of_this = map();
Ben Murdoch3ef787d2012-04-12 10:51:47 +01007382 Heap* heap = GetHeap();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007383 DisallowHeapAllocation no_allocation;
Steve Blocka7e24c12009-10-30 11:49:00 +00007384
7385 // Is the object the constructor for this object?
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00007386 if (map_of_this->GetConstructor() == obj) {
Steve Blocka7e24c12009-10-30 11:49:00 +00007387 return true;
7388 }
7389
7390 // Is the object the prototype for this object?
Ben Murdoch8b112d22011-06-08 16:22:53 +01007391 if (map_of_this->prototype() == obj) {
Steve Blocka7e24c12009-10-30 11:49:00 +00007392 return true;
7393 }
7394
7395 // Check if the object is among the named properties.
7396 Object* key = SlowReverseLookup(obj);
Steve Block44f0eee2011-05-26 01:26:41 +01007397 if (!key->IsUndefined()) {
Steve Blocka7e24c12009-10-30 11:49:00 +00007398 return true;
7399 }
7400
7401 // Check if the object is among the indexed properties.
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00007402 ElementsKind kind = GetElementsKind();
7403 switch (kind) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007404 // Raw pixels and external arrays do not reference other
7405 // objects.
7406#define TYPED_ARRAY_CASE(Type, type, TYPE, ctype, size) \
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007407 case TYPE##_ELEMENTS: \
Steve Blocka7e24c12009-10-30 11:49:00 +00007408 break;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007409
7410 TYPED_ARRAYS(TYPED_ARRAY_CASE)
7411#undef TYPED_ARRAY_CASE
7412
7413 case FAST_DOUBLE_ELEMENTS:
7414 case FAST_HOLEY_DOUBLE_ELEMENTS:
7415 break;
7416 case FAST_SMI_ELEMENTS:
7417 case FAST_HOLEY_SMI_ELEMENTS:
Ben Murdoch3ef787d2012-04-12 10:51:47 +01007418 break;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00007419 case FAST_ELEMENTS:
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007420 case FAST_HOLEY_ELEMENTS:
Ben Murdoch097c5b22016-05-18 11:27:45 +01007421 case DICTIONARY_ELEMENTS:
7422 case FAST_STRING_WRAPPER_ELEMENTS:
7423 case SLOW_STRING_WRAPPER_ELEMENTS: {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00007424 FixedArray* elements = FixedArray::cast(this->elements());
7425 if (ReferencesObjectFromElements(elements, kind, obj)) return true;
Steve Blocka7e24c12009-10-30 11:49:00 +00007426 break;
7427 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00007428 case FAST_SLOPPY_ARGUMENTS_ELEMENTS:
7429 case SLOW_SLOPPY_ARGUMENTS_ELEMENTS: {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00007430 FixedArray* parameter_map = FixedArray::cast(elements());
7431 // Check the mapped parameters.
7432 int length = parameter_map->length();
7433 for (int i = 2; i < length; ++i) {
7434 Object* value = parameter_map->get(i);
7435 if (!value->IsTheHole() && value == obj) return true;
7436 }
7437 // Check the arguments.
7438 FixedArray* arguments = FixedArray::cast(parameter_map->get(1));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007439 kind = arguments->IsDictionary() ? DICTIONARY_ELEMENTS :
7440 FAST_HOLEY_ELEMENTS;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00007441 if (ReferencesObjectFromElements(arguments, kind, obj)) return true;
Steve Blocka7e24c12009-10-30 11:49:00 +00007442 break;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00007443 }
Ben Murdoch097c5b22016-05-18 11:27:45 +01007444 case NO_ELEMENTS:
7445 break;
Steve Blocka7e24c12009-10-30 11:49:00 +00007446 }
7447
Steve Block6ded16b2010-05-10 14:33:55 +01007448 // For functions check the context.
7449 if (IsJSFunction()) {
Steve Blocka7e24c12009-10-30 11:49:00 +00007450 // Get the constructor function for arguments array.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007451 Map* arguments_map =
7452 heap->isolate()->context()->native_context()->sloppy_arguments_map();
Steve Blocka7e24c12009-10-30 11:49:00 +00007453 JSFunction* arguments_function =
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00007454 JSFunction::cast(arguments_map->GetConstructor());
Steve Blocka7e24c12009-10-30 11:49:00 +00007455
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007456 // Get the context and don't check if it is the native context.
Steve Blocka7e24c12009-10-30 11:49:00 +00007457 JSFunction* f = JSFunction::cast(this);
7458 Context* context = f->context();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007459 if (context->IsNativeContext()) {
Steve Blocka7e24c12009-10-30 11:49:00 +00007460 return false;
7461 }
7462
7463 // Check the non-special context slots.
7464 for (int i = Context::MIN_CONTEXT_SLOTS; i < context->length(); i++) {
7465 // Only check JS objects.
7466 if (context->get(i)->IsJSObject()) {
7467 JSObject* ctxobj = JSObject::cast(context->get(i));
7468 // If it is an arguments array check the content.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00007469 if (ctxobj->map()->GetConstructor() == arguments_function) {
Steve Blocka7e24c12009-10-30 11:49:00 +00007470 if (ctxobj->ReferencesObject(obj)) {
7471 return true;
7472 }
7473 } else if (ctxobj == obj) {
7474 return true;
7475 }
7476 }
7477 }
7478
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00007479 // Check the context extension (if any) if it can have references.
7480 if (context->has_extension() && !context->IsCatchContext()) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00007481 // With harmony scoping, a JSFunction may have a script context.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007482 // TODO(mvstanton): walk into the ScopeInfo.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00007483 if (context->IsScriptContext()) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007484 return false;
7485 }
7486
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00007487 return context->extension_object()->ReferencesObject(obj);
Steve Blocka7e24c12009-10-30 11:49:00 +00007488 }
7489 }
7490
7491 // No references to object.
7492 return false;
7493}
7494
7495
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00007496Maybe<bool> JSReceiver::SetIntegrityLevel(Handle<JSReceiver> receiver,
7497 IntegrityLevel level,
7498 ShouldThrow should_throw) {
7499 DCHECK(level == SEALED || level == FROZEN);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01007500
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00007501 if (receiver->IsJSObject()) {
7502 Handle<JSObject> object = Handle<JSObject>::cast(receiver);
7503 if (!object->HasSloppyArgumentsElements() &&
7504 !object->map()->is_observed() &&
7505 (!object->map()->is_strong() || level == SEALED)) { // Fast path.
7506 if (level == SEALED) {
7507 return JSObject::PreventExtensionsWithTransition<SEALED>(object,
7508 should_throw);
7509 } else {
7510 return JSObject::PreventExtensionsWithTransition<FROZEN>(object,
7511 should_throw);
7512 }
7513 }
Emily Bernierd0a1eb72015-03-24 16:35:39 -04007514 }
7515
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00007516 Isolate* isolate = receiver->GetIsolate();
7517
7518 MAYBE_RETURN(JSReceiver::PreventExtensions(receiver, should_throw),
7519 Nothing<bool>());
7520
7521 Handle<FixedArray> keys;
7522 ASSIGN_RETURN_ON_EXCEPTION_VALUE(
7523 isolate, keys, JSReceiver::OwnPropertyKeys(receiver), Nothing<bool>());
7524
7525 PropertyDescriptor no_conf;
7526 no_conf.set_configurable(false);
7527
7528 PropertyDescriptor no_conf_no_write;
7529 no_conf_no_write.set_configurable(false);
7530 no_conf_no_write.set_writable(false);
7531
7532 if (level == SEALED) {
7533 for (int i = 0; i < keys->length(); ++i) {
7534 Handle<Object> key(keys->get(i), isolate);
7535 MAYBE_RETURN(
7536 DefineOwnProperty(isolate, receiver, key, &no_conf, THROW_ON_ERROR),
7537 Nothing<bool>());
7538 }
7539 return Just(true);
7540 }
7541
7542 for (int i = 0; i < keys->length(); ++i) {
7543 Handle<Object> key(keys->get(i), isolate);
7544 PropertyDescriptor current_desc;
7545 Maybe<bool> owned = JSReceiver::GetOwnPropertyDescriptor(
7546 isolate, receiver, key, &current_desc);
7547 MAYBE_RETURN(owned, Nothing<bool>());
7548 if (owned.FromJust()) {
7549 PropertyDescriptor desc =
7550 PropertyDescriptor::IsAccessorDescriptor(&current_desc)
7551 ? no_conf
7552 : no_conf_no_write;
7553 MAYBE_RETURN(
7554 DefineOwnProperty(isolate, receiver, key, &desc, THROW_ON_ERROR),
7555 Nothing<bool>());
7556 }
7557 }
7558 return Just(true);
7559}
7560
7561
7562Maybe<bool> JSReceiver::TestIntegrityLevel(Handle<JSReceiver> object,
7563 IntegrityLevel level) {
7564 DCHECK(level == SEALED || level == FROZEN);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04007565 Isolate* isolate = object->GetIsolate();
7566
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00007567 Maybe<bool> extensible = JSReceiver::IsExtensible(object);
7568 MAYBE_RETURN(extensible, Nothing<bool>());
7569 if (extensible.FromJust()) return Just(false);
7570
7571 Handle<FixedArray> keys;
7572 ASSIGN_RETURN_ON_EXCEPTION_VALUE(
7573 isolate, keys, JSReceiver::OwnPropertyKeys(object), Nothing<bool>());
7574
7575 for (int i = 0; i < keys->length(); ++i) {
7576 Handle<Object> key(keys->get(i), isolate);
7577 PropertyDescriptor current_desc;
7578 Maybe<bool> owned = JSReceiver::GetOwnPropertyDescriptor(
7579 isolate, object, key, &current_desc);
7580 MAYBE_RETURN(owned, Nothing<bool>());
7581 if (owned.FromJust()) {
7582 if (current_desc.configurable()) return Just(false);
7583 if (level == FROZEN &&
7584 PropertyDescriptor::IsDataDescriptor(&current_desc) &&
7585 current_desc.writable()) {
7586 return Just(false);
7587 }
7588 }
Ben Murdoche0cee9b2011-05-25 10:26:03 +01007589 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00007590 return Just(true);
7591}
7592
7593
7594Maybe<bool> JSReceiver::PreventExtensions(Handle<JSReceiver> object,
7595 ShouldThrow should_throw) {
7596 if (object->IsJSProxy()) {
7597 return JSProxy::PreventExtensions(Handle<JSProxy>::cast(object),
7598 should_throw);
7599 }
7600 DCHECK(object->IsJSObject());
7601 return JSObject::PreventExtensions(Handle<JSObject>::cast(object),
7602 should_throw);
7603}
7604
7605
7606Maybe<bool> JSProxy::PreventExtensions(Handle<JSProxy> proxy,
7607 ShouldThrow should_throw) {
7608 Isolate* isolate = proxy->GetIsolate();
7609 STACK_CHECK(Nothing<bool>());
7610 Factory* factory = isolate->factory();
7611 Handle<String> trap_name = factory->preventExtensions_string();
7612
7613 if (proxy->IsRevoked()) {
7614 isolate->Throw(
7615 *factory->NewTypeError(MessageTemplate::kProxyRevoked, trap_name));
7616 return Nothing<bool>();
7617 }
7618 Handle<JSReceiver> target(proxy->target(), isolate);
7619 Handle<JSReceiver> handler(JSReceiver::cast(proxy->handler()), isolate);
7620
7621 Handle<Object> trap;
7622 ASSIGN_RETURN_ON_EXCEPTION_VALUE(
7623 isolate, trap, Object::GetMethod(handler, trap_name), Nothing<bool>());
7624 if (trap->IsUndefined()) {
7625 return JSReceiver::PreventExtensions(target, should_throw);
7626 }
7627
7628 Handle<Object> trap_result;
7629 Handle<Object> args[] = {target};
7630 ASSIGN_RETURN_ON_EXCEPTION_VALUE(
7631 isolate, trap_result,
7632 Execution::Call(isolate, trap, handler, arraysize(args), args),
7633 Nothing<bool>());
7634 if (!trap_result->BooleanValue()) {
7635 RETURN_FAILURE(
7636 isolate, should_throw,
7637 NewTypeError(MessageTemplate::kProxyTrapReturnedFalsish, trap_name));
7638 }
7639
7640 // Enforce the invariant.
7641 Maybe<bool> target_result = JSReceiver::IsExtensible(target);
7642 MAYBE_RETURN(target_result, Nothing<bool>());
7643 if (target_result.FromJust()) {
7644 isolate->Throw(*factory->NewTypeError(
7645 MessageTemplate::kProxyPreventExtensionsExtensible));
7646 return Nothing<bool>();
7647 }
7648 return Just(true);
7649}
7650
7651
7652Maybe<bool> JSObject::PreventExtensions(Handle<JSObject> object,
7653 ShouldThrow should_throw) {
7654 Isolate* isolate = object->GetIsolate();
7655
7656 if (!object->HasSloppyArgumentsElements() && !object->map()->is_observed()) {
7657 return PreventExtensionsWithTransition<NONE>(object, should_throw);
7658 }
7659
7660 if (object->IsAccessCheckNeeded() &&
7661 !isolate->MayAccess(handle(isolate->context()), object)) {
7662 isolate->ReportFailedAccessCheck(object);
7663 RETURN_VALUE_IF_SCHEDULED_EXCEPTION(isolate, Nothing<bool>());
7664 RETURN_FAILURE(isolate, should_throw,
7665 NewTypeError(MessageTemplate::kNoAccess));
7666 }
7667
7668 if (!object->map()->is_extensible()) return Just(true);
Ben Murdoche0cee9b2011-05-25 10:26:03 +01007669
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007670 if (object->IsJSGlobalProxy()) {
7671 PrototypeIterator iter(isolate, object);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00007672 if (iter.IsAtEnd()) return Just(true);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007673 DCHECK(PrototypeIterator::GetCurrent(iter)->IsJSGlobalObject());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00007674 return PreventExtensions(PrototypeIterator::GetCurrent<JSObject>(iter),
7675 should_throw);
Steve Block1e0659c2011-05-24 12:43:12 +01007676 }
7677
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00007678 if (!object->HasFixedTypedArrayElements()) {
7679 // If there are fast elements we normalize.
7680 Handle<SeededNumberDictionary> dictionary = NormalizeElements(object);
7681 DCHECK(object->HasDictionaryElements() ||
7682 object->HasSlowArgumentsElements());
7683
7684 // Make sure that we never go back to fast case.
7685 object->RequireSlowElements(*dictionary);
Ben Murdoch257744e2011-11-30 15:57:28 +00007686 }
7687
Steve Block8defd9f2010-07-08 12:39:36 +01007688 // Do a map transition, other objects with this map may still
7689 // be extensible.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007690 // TODO(adamk): Extend the NormalizedMapCache to handle non-extensible maps.
Emily Bernierd0a1eb72015-03-24 16:35:39 -04007691 Handle<Map> new_map = Map::Copy(handle(object->map()), "PreventExtensions");
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007692
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00007693 new_map->set_is_extensible(false);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007694 JSObject::MigrateToMap(object, new_map);
7695 DCHECK(!object->map()->is_extensible());
7696
7697 if (object->map()->is_observed()) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00007698 RETURN_ON_EXCEPTION_VALUE(
Emily Bernierd0a1eb72015-03-24 16:35:39 -04007699 isolate,
7700 EnqueueChangeRecord(object, "preventExtensions", Handle<Name>(),
7701 isolate->factory()->the_hole_value()),
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00007702 Nothing<bool>());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007703 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00007704 return Just(true);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007705}
7706
7707
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00007708Maybe<bool> JSReceiver::IsExtensible(Handle<JSReceiver> object) {
7709 if (object->IsJSProxy()) {
7710 return JSProxy::IsExtensible(Handle<JSProxy>::cast(object));
Emily Bernierd0a1eb72015-03-24 16:35:39 -04007711 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00007712 return Just(JSObject::IsExtensible(Handle<JSObject>::cast(object)));
7713}
7714
7715
7716Maybe<bool> JSProxy::IsExtensible(Handle<JSProxy> proxy) {
7717 Isolate* isolate = proxy->GetIsolate();
7718 STACK_CHECK(Nothing<bool>());
7719 Factory* factory = isolate->factory();
7720 Handle<String> trap_name = factory->isExtensible_string();
7721
7722 if (proxy->IsRevoked()) {
7723 isolate->Throw(
7724 *factory->NewTypeError(MessageTemplate::kProxyRevoked, trap_name));
7725 return Nothing<bool>();
7726 }
7727 Handle<JSReceiver> target(proxy->target(), isolate);
7728 Handle<JSReceiver> handler(JSReceiver::cast(proxy->handler()), isolate);
7729
7730 Handle<Object> trap;
7731 ASSIGN_RETURN_ON_EXCEPTION_VALUE(
7732 isolate, trap, Object::GetMethod(handler, trap_name), Nothing<bool>());
7733 if (trap->IsUndefined()) {
7734 return JSReceiver::IsExtensible(target);
7735 }
7736
7737 Handle<Object> trap_result;
7738 Handle<Object> args[] = {target};
7739 ASSIGN_RETURN_ON_EXCEPTION_VALUE(
7740 isolate, trap_result,
7741 Execution::Call(isolate, trap, handler, arraysize(args), args),
7742 Nothing<bool>());
7743
7744 // Enforce the invariant.
7745 Maybe<bool> target_result = JSReceiver::IsExtensible(target);
7746 MAYBE_RETURN(target_result, Nothing<bool>());
7747 if (target_result.FromJust() != trap_result->BooleanValue()) {
7748 isolate->Throw(
7749 *factory->NewTypeError(MessageTemplate::kProxyIsExtensibleInconsistent,
7750 factory->ToBoolean(target_result.FromJust())));
7751 return Nothing<bool>();
7752 }
7753 return target_result;
7754}
7755
7756
7757bool JSObject::IsExtensible(Handle<JSObject> object) {
7758 Isolate* isolate = object->GetIsolate();
7759 if (object->IsAccessCheckNeeded() &&
7760 !isolate->MayAccess(handle(isolate->context()), object)) {
7761 return true;
7762 }
7763 if (object->IsJSGlobalProxy()) {
7764 PrototypeIterator iter(isolate, *object);
7765 if (iter.IsAtEnd()) return false;
7766 DCHECK(iter.GetCurrent()->IsJSGlobalObject());
7767 return iter.GetCurrent<JSObject>()->map()->is_extensible();
7768 }
7769 return object->map()->is_extensible();
Emily Bernierd0a1eb72015-03-24 16:35:39 -04007770}
7771
7772
7773template <typename Dictionary>
7774static void ApplyAttributesToDictionary(Dictionary* dictionary,
7775 const PropertyAttributes attributes) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007776 int capacity = dictionary->Capacity();
7777 for (int i = 0; i < capacity; i++) {
7778 Object* k = dictionary->KeyAt(i);
7779 if (dictionary->IsKey(k) &&
7780 !(k->IsSymbol() && Symbol::cast(k)->is_private())) {
7781 PropertyDetails details = dictionary->DetailsAt(i);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04007782 int attrs = attributes;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007783 // READ_ONLY is an invalid attribute for JS setters/getters.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00007784 if ((attributes & READ_ONLY) && details.type() == ACCESSOR_CONSTANT) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007785 Object* v = dictionary->ValueAt(i);
7786 if (v->IsPropertyCell()) v = PropertyCell::cast(v)->value();
Emily Bernierd0a1eb72015-03-24 16:35:39 -04007787 if (v->IsAccessorPair()) attrs &= ~READ_ONLY;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007788 }
7789 details = details.CopyAddAttributes(
7790 static_cast<PropertyAttributes>(attrs));
7791 dictionary->DetailsAtPut(i, details);
7792 }
7793 }
7794}
7795
7796
Emily Bernierd0a1eb72015-03-24 16:35:39 -04007797template <PropertyAttributes attrs>
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00007798Maybe<bool> JSObject::PreventExtensionsWithTransition(
7799 Handle<JSObject> object, ShouldThrow should_throw) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -04007800 STATIC_ASSERT(attrs == NONE || attrs == SEALED || attrs == FROZEN);
7801
7802 // Sealing/freezing sloppy arguments should be handled elsewhere.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007803 DCHECK(!object->HasSloppyArgumentsElements());
7804 DCHECK(!object->map()->is_observed());
7805
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007806 Isolate* isolate = object->GetIsolate();
7807 if (object->IsAccessCheckNeeded() &&
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00007808 !isolate->MayAccess(handle(isolate->context()), object)) {
7809 isolate->ReportFailedAccessCheck(object);
7810 RETURN_VALUE_IF_SCHEDULED_EXCEPTION(isolate, Nothing<bool>());
7811 RETURN_FAILURE(isolate, should_throw,
7812 NewTypeError(MessageTemplate::kNoAccess));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007813 }
7814
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00007815 if (attrs == NONE && !object->map()->is_extensible()) return Just(true);
7816
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007817 if (object->IsJSGlobalProxy()) {
7818 PrototypeIterator iter(isolate, object);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00007819 if (iter.IsAtEnd()) return Just(true);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007820 DCHECK(PrototypeIterator::GetCurrent(iter)->IsJSGlobalObject());
Emily Bernierd0a1eb72015-03-24 16:35:39 -04007821 return PreventExtensionsWithTransition<attrs>(
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00007822 PrototypeIterator::GetCurrent<JSObject>(iter), should_throw);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007823 }
7824
7825 Handle<SeededNumberDictionary> new_element_dictionary;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00007826 if (!object->HasFixedTypedArrayElements() &&
Ben Murdoch097c5b22016-05-18 11:27:45 +01007827 !object->HasDictionaryElements() &&
7828 !object->HasSlowStringWrapperElements()) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00007829 int length =
7830 object->IsJSArray()
7831 ? Smi::cast(Handle<JSArray>::cast(object)->length())->value()
7832 : object->elements()->length();
7833 new_element_dictionary =
7834 length == 0 ? isolate->factory()->empty_slow_element_dictionary()
7835 : GetNormalizedElementDictionary(
7836 object, handle(object->elements()));
Emily Bernierd0a1eb72015-03-24 16:35:39 -04007837 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007838
Emily Bernierd0a1eb72015-03-24 16:35:39 -04007839 Handle<Symbol> transition_marker;
7840 if (attrs == NONE) {
7841 transition_marker = isolate->factory()->nonextensible_symbol();
7842 } else if (attrs == SEALED) {
7843 transition_marker = isolate->factory()->sealed_symbol();
7844 } else {
7845 DCHECK(attrs == FROZEN);
7846 transition_marker = isolate->factory()->frozen_symbol();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007847 }
7848
7849 Handle<Map> old_map(object->map(), isolate);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00007850 Map* transition =
7851 TransitionArray::SearchSpecial(*old_map, *transition_marker);
7852 if (transition != NULL) {
7853 Handle<Map> transition_map(transition, isolate);
7854 DCHECK(transition_map->has_dictionary_elements() ||
Ben Murdoch097c5b22016-05-18 11:27:45 +01007855 transition_map->has_fixed_typed_array_elements() ||
7856 transition_map->elements_kind() == SLOW_STRING_WRAPPER_ELEMENTS);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007857 DCHECK(!transition_map->is_extensible());
7858 JSObject::MigrateToMap(object, transition_map);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00007859 } else if (TransitionArray::CanHaveMoreTransitions(old_map)) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -04007860 // Create a new descriptor array with the appropriate property attributes
7861 Handle<Map> new_map = Map::CopyForPreventExtensions(
7862 old_map, attrs, transition_marker, "CopyForPreventExtensions");
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007863 JSObject::MigrateToMap(object, new_map);
7864 } else {
7865 DCHECK(old_map->is_dictionary_map() || !old_map->is_prototype_map());
7866 // Slow path: need to normalize properties for safety
Emily Bernierd0a1eb72015-03-24 16:35:39 -04007867 NormalizeProperties(object, CLEAR_INOBJECT_PROPERTIES, 0,
7868 "SlowPreventExtensions");
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007869
7870 // Create a new map, since other objects with this map may be extensible.
7871 // TODO(adamk): Extend the NormalizedMapCache to handle non-extensible maps.
Emily Bernierd0a1eb72015-03-24 16:35:39 -04007872 Handle<Map> new_map =
7873 Map::Copy(handle(object->map()), "SlowCopyForPreventExtensions");
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007874 new_map->set_is_extensible(false);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00007875 if (!new_element_dictionary.is_null()) {
Ben Murdoch097c5b22016-05-18 11:27:45 +01007876 ElementsKind new_kind =
7877 IsStringWrapperElementsKind(old_map->elements_kind())
7878 ? SLOW_STRING_WRAPPER_ELEMENTS
7879 : DICTIONARY_ELEMENTS;
7880 new_map->set_elements_kind(new_kind);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00007881 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007882 JSObject::MigrateToMap(object, new_map);
7883
Emily Bernierd0a1eb72015-03-24 16:35:39 -04007884 if (attrs != NONE) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00007885 if (object->IsJSGlobalObject()) {
7886 ApplyAttributesToDictionary(object->global_dictionary(), attrs);
7887 } else {
7888 ApplyAttributesToDictionary(object->property_dictionary(), attrs);
7889 }
Emily Bernierd0a1eb72015-03-24 16:35:39 -04007890 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007891 }
7892
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00007893 // Both seal and preventExtensions always go through without modifications to
7894 // typed array elements. Freeze works only if there are no actual elements.
7895 if (object->HasFixedTypedArrayElements()) {
7896 if (attrs == FROZEN &&
7897 JSArrayBufferView::cast(*object)->byte_length()->Number() > 0) {
7898 isolate->Throw(*isolate->factory()->NewTypeError(
7899 MessageTemplate::kCannotFreezeArrayBufferView));
7900 return Nothing<bool>();
7901 }
7902 return Just(true);
7903 }
7904
Ben Murdoch097c5b22016-05-18 11:27:45 +01007905 DCHECK(object->map()->has_dictionary_elements() ||
7906 object->map()->elements_kind() == SLOW_STRING_WRAPPER_ELEMENTS);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007907 if (!new_element_dictionary.is_null()) {
7908 object->set_elements(*new_element_dictionary);
7909 }
7910
7911 if (object->elements() != isolate->heap()->empty_slow_element_dictionary()) {
7912 SeededNumberDictionary* dictionary = object->element_dictionary();
7913 // Make sure we never go back to the fast case
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00007914 object->RequireSlowElements(dictionary);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04007915 if (attrs != NONE) {
7916 ApplyAttributesToDictionary(dictionary, attrs);
7917 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007918 }
7919
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00007920 return Just(true);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04007921}
7922
7923
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007924void JSObject::SetObserved(Handle<JSObject> object) {
7925 DCHECK(!object->IsJSGlobalProxy());
7926 DCHECK(!object->IsJSGlobalObject());
7927 Isolate* isolate = object->GetIsolate();
7928 Handle<Map> new_map;
7929 Handle<Map> old_map(object->map(), isolate);
7930 DCHECK(!old_map->is_observed());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00007931 Map* transition = TransitionArray::SearchSpecial(
7932 *old_map, isolate->heap()->observed_symbol());
7933 if (transition != NULL) {
7934 new_map = handle(transition, isolate);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007935 DCHECK(new_map->is_observed());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00007936 } else if (TransitionArray::CanHaveMoreTransitions(old_map)) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007937 new_map = Map::CopyForObserved(old_map);
7938 } else {
Emily Bernierd0a1eb72015-03-24 16:35:39 -04007939 new_map = Map::Copy(old_map, "SlowObserved");
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007940 new_map->set_is_observed();
7941 }
7942 JSObject::MigrateToMap(object, new_map);
7943}
7944
7945
7946Handle<Object> JSObject::FastPropertyAt(Handle<JSObject> object,
7947 Representation representation,
7948 FieldIndex index) {
7949 Isolate* isolate = object->GetIsolate();
Emily Bernierd0a1eb72015-03-24 16:35:39 -04007950 if (object->IsUnboxedDoubleField(index)) {
7951 double value = object->RawFastDoublePropertyAt(index);
7952 return isolate->factory()->NewHeapNumber(value);
7953 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007954 Handle<Object> raw_value(object->RawFastPropertyAt(index), isolate);
7955 return Object::WrapForRead(isolate, raw_value, representation);
7956}
7957
Ben Murdoch097c5b22016-05-18 11:27:45 +01007958enum class BoilerplateKind { kNormalBoilerplate, kApiBoilerplate };
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007959
Ben Murdoch097c5b22016-05-18 11:27:45 +01007960template <class ContextObject, BoilerplateKind boilerplate_kind>
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007961class JSObjectWalkVisitor {
7962 public:
7963 JSObjectWalkVisitor(ContextObject* site_context, bool copying,
7964 JSObject::DeepCopyHints hints)
7965 : site_context_(site_context),
7966 copying_(copying),
7967 hints_(hints) {}
7968
7969 MUST_USE_RESULT MaybeHandle<JSObject> StructureWalk(Handle<JSObject> object);
7970
7971 protected:
7972 MUST_USE_RESULT inline MaybeHandle<JSObject> VisitElementOrProperty(
7973 Handle<JSObject> object,
7974 Handle<JSObject> value) {
7975 Handle<AllocationSite> current_site = site_context()->EnterNewScope();
7976 MaybeHandle<JSObject> copy_of_value = StructureWalk(value);
7977 site_context()->ExitScope(current_site, value);
7978 return copy_of_value;
7979 }
7980
7981 inline ContextObject* site_context() { return site_context_; }
7982 inline Isolate* isolate() { return site_context()->isolate(); }
7983
7984 inline bool copying() const { return copying_; }
7985
7986 private:
7987 ContextObject* site_context_;
7988 const bool copying_;
7989 const JSObject::DeepCopyHints hints_;
7990};
7991
Ben Murdoch097c5b22016-05-18 11:27:45 +01007992template <class ContextObject, BoilerplateKind boilerplate_kind>
7993MaybeHandle<JSObject> JSObjectWalkVisitor<
7994 ContextObject, boilerplate_kind>::StructureWalk(Handle<JSObject> object) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007995 Isolate* isolate = this->isolate();
7996 bool copying = this->copying();
7997 bool shallow = hints_ == JSObject::kObjectIsShallow;
7998
7999 if (!shallow) {
8000 StackLimitCheck check(isolate);
8001
8002 if (check.HasOverflowed()) {
8003 isolate->StackOverflow();
8004 return MaybeHandle<JSObject>();
8005 }
8006 }
8007
8008 if (object->map()->is_deprecated()) {
8009 JSObject::MigrateInstance(object);
8010 }
8011
8012 Handle<JSObject> copy;
8013 if (copying) {
Ben Murdoch097c5b22016-05-18 11:27:45 +01008014 if (boilerplate_kind == BoilerplateKind::kApiBoilerplate) {
8015 if (object->IsJSFunction()) {
8016#ifdef DEBUG
8017 // Ensure that it is an Api function and template_instantiations_cache
8018 // contains an entry for function's FunctionTemplateInfo.
8019 JSFunction* function = JSFunction::cast(*object);
8020 CHECK(function->shared()->IsApiFunction());
8021 FunctionTemplateInfo* data = function->shared()->get_api_func_data();
8022 auto serial_number = handle(Smi::cast(data->serial_number()), isolate);
8023 CHECK(serial_number->value());
8024 auto cache = isolate->template_instantiations_cache();
8025 Object* element = cache->Lookup(serial_number);
8026 CHECK_EQ(function, element);
8027#endif
8028 return object;
8029 }
8030 } else {
8031 // JSFunction objects are not allowed to be in normal boilerplates at all.
8032 DCHECK(!object->IsJSFunction());
8033 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00008034 Handle<AllocationSite> site_to_pass;
8035 if (site_context()->ShouldCreateMemento(object)) {
8036 site_to_pass = site_context()->current();
8037 }
8038 copy = isolate->factory()->CopyJSObjectWithAllocationSite(
8039 object, site_to_pass);
8040 } else {
8041 copy = object;
8042 }
8043
8044 DCHECK(copying || copy.is_identical_to(object));
8045
8046 ElementsKind kind = copy->GetElementsKind();
8047 if (copying && IsFastSmiOrObjectElementsKind(kind) &&
8048 FixedArray::cast(copy->elements())->map() ==
8049 isolate->heap()->fixed_cow_array_map()) {
8050 isolate->counters()->cow_arrays_created_runtime()->Increment();
8051 }
8052
8053 if (!shallow) {
8054 HandleScope scope(isolate);
8055
8056 // Deep copy own properties.
8057 if (copy->HasFastProperties()) {
8058 Handle<DescriptorArray> descriptors(copy->map()->instance_descriptors());
8059 int limit = copy->map()->NumberOfOwnDescriptors();
8060 for (int i = 0; i < limit; i++) {
8061 PropertyDetails details = descriptors->GetDetails(i);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00008062 if (details.type() != DATA) continue;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00008063 FieldIndex index = FieldIndex::ForDescriptor(copy->map(), i);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04008064 if (object->IsUnboxedDoubleField(index)) {
8065 if (copying) {
8066 double value = object->RawFastDoublePropertyAt(index);
8067 copy->RawFastDoublePropertyAtPut(index, value);
8068 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00008069 } else {
Emily Bernierd0a1eb72015-03-24 16:35:39 -04008070 Handle<Object> value(object->RawFastPropertyAt(index), isolate);
8071 if (value->IsJSObject()) {
8072 ASSIGN_RETURN_ON_EXCEPTION(
8073 isolate, value,
8074 VisitElementOrProperty(copy, Handle<JSObject>::cast(value)),
8075 JSObject);
8076 if (copying) {
8077 copy->FastPropertyAtPut(index, *value);
8078 }
8079 } else {
8080 if (copying) {
8081 Representation representation = details.representation();
8082 value = Object::NewStorageFor(isolate, value, representation);
8083 copy->FastPropertyAtPut(index, *value);
8084 }
8085 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00008086 }
8087 }
8088 } else {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00008089 // Only deep copy fields from the object literal expression.
8090 // In particular, don't try to copy the length attribute of
8091 // an array.
8092 PropertyFilter filter = static_cast<PropertyFilter>(
8093 ONLY_WRITABLE | ONLY_ENUMERABLE | ONLY_CONFIGURABLE);
Ben Murdoch097c5b22016-05-18 11:27:45 +01008094 KeyAccumulator accumulator(isolate, OWN_ONLY, filter);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00008095 accumulator.NextPrototype();
8096 copy->CollectOwnPropertyNames(&accumulator, filter);
8097 Handle<FixedArray> names = accumulator.GetKeys();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00008098 for (int i = 0; i < names->length(); i++) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00008099 DCHECK(names->get(i)->IsName());
8100 Handle<Name> name(Name::cast(names->get(i)));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00008101 Handle<Object> value =
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00008102 Object::GetProperty(copy, name).ToHandleChecked();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00008103 if (value->IsJSObject()) {
8104 Handle<JSObject> result;
8105 ASSIGN_RETURN_ON_EXCEPTION(
8106 isolate, result,
8107 VisitElementOrProperty(copy, Handle<JSObject>::cast(value)),
8108 JSObject);
8109 if (copying) {
8110 // Creating object copy for literals. No strict mode needed.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00008111 JSObject::SetProperty(copy, name, result, SLOPPY).Assert();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00008112 }
8113 }
8114 }
8115 }
8116
8117 // Deep copy own elements.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00008118 switch (kind) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00008119 case FAST_ELEMENTS:
Ben Murdochb8a8cc12014-11-26 15:28:44 +00008120 case FAST_HOLEY_ELEMENTS: {
8121 Handle<FixedArray> elements(FixedArray::cast(copy->elements()));
8122 if (elements->map() == isolate->heap()->fixed_cow_array_map()) {
8123#ifdef DEBUG
8124 for (int i = 0; i < elements->length(); i++) {
8125 DCHECK(!elements->get(i)->IsJSObject());
8126 }
8127#endif
8128 } else {
8129 for (int i = 0; i < elements->length(); i++) {
8130 Handle<Object> value(elements->get(i), isolate);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00008131 if (value->IsJSObject()) {
8132 Handle<JSObject> result;
8133 ASSIGN_RETURN_ON_EXCEPTION(
8134 isolate, result,
8135 VisitElementOrProperty(copy, Handle<JSObject>::cast(value)),
8136 JSObject);
8137 if (copying) {
8138 elements->set(i, *result);
8139 }
8140 }
8141 }
8142 }
8143 break;
8144 }
8145 case DICTIONARY_ELEMENTS: {
8146 Handle<SeededNumberDictionary> element_dictionary(
8147 copy->element_dictionary());
8148 int capacity = element_dictionary->Capacity();
8149 for (int i = 0; i < capacity; i++) {
8150 Object* k = element_dictionary->KeyAt(i);
8151 if (element_dictionary->IsKey(k)) {
8152 Handle<Object> value(element_dictionary->ValueAt(i), isolate);
8153 if (value->IsJSObject()) {
8154 Handle<JSObject> result;
8155 ASSIGN_RETURN_ON_EXCEPTION(
8156 isolate, result,
8157 VisitElementOrProperty(copy, Handle<JSObject>::cast(value)),
8158 JSObject);
8159 if (copying) {
8160 element_dictionary->ValueAtPut(i, *result);
8161 }
8162 }
8163 }
8164 }
8165 break;
8166 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00008167 case FAST_SLOPPY_ARGUMENTS_ELEMENTS:
8168 case SLOW_SLOPPY_ARGUMENTS_ELEMENTS:
Ben Murdochb8a8cc12014-11-26 15:28:44 +00008169 UNIMPLEMENTED();
8170 break;
Ben Murdoch097c5b22016-05-18 11:27:45 +01008171 case FAST_STRING_WRAPPER_ELEMENTS:
8172 case SLOW_STRING_WRAPPER_ELEMENTS:
8173 UNREACHABLE();
8174 break;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00008175
8176#define TYPED_ARRAY_CASE(Type, type, TYPE, ctype, size) \
Ben Murdochb8a8cc12014-11-26 15:28:44 +00008177 case TYPE##_ELEMENTS: \
8178
8179 TYPED_ARRAYS(TYPED_ARRAY_CASE)
8180#undef TYPED_ARRAY_CASE
Ben Murdoch097c5b22016-05-18 11:27:45 +01008181 // Typed elements cannot be created using an object literal.
8182 UNREACHABLE();
8183 break;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00008184
Ben Murdoch097c5b22016-05-18 11:27:45 +01008185 case FAST_SMI_ELEMENTS:
8186 case FAST_HOLEY_SMI_ELEMENTS:
Ben Murdochb8a8cc12014-11-26 15:28:44 +00008187 case FAST_DOUBLE_ELEMENTS:
8188 case FAST_HOLEY_DOUBLE_ELEMENTS:
Ben Murdoch097c5b22016-05-18 11:27:45 +01008189 case NO_ELEMENTS:
Ben Murdochb8a8cc12014-11-26 15:28:44 +00008190 // No contained objects, nothing to do.
8191 break;
8192 }
8193 }
8194
8195 return copy;
8196}
8197
8198
8199MaybeHandle<JSObject> JSObject::DeepWalk(
8200 Handle<JSObject> object,
8201 AllocationSiteCreationContext* site_context) {
Ben Murdoch097c5b22016-05-18 11:27:45 +01008202 JSObjectWalkVisitor<AllocationSiteCreationContext,
8203 BoilerplateKind::kNormalBoilerplate> v(site_context,
8204 false, kNoHints);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00008205 MaybeHandle<JSObject> result = v.StructureWalk(object);
8206 Handle<JSObject> for_assert;
8207 DCHECK(!result.ToHandle(&for_assert) || for_assert.is_identical_to(object));
8208 return result;
8209}
8210
8211
8212MaybeHandle<JSObject> JSObject::DeepCopy(
8213 Handle<JSObject> object,
8214 AllocationSiteUsageContext* site_context,
8215 DeepCopyHints hints) {
Ben Murdoch097c5b22016-05-18 11:27:45 +01008216 JSObjectWalkVisitor<AllocationSiteUsageContext,
8217 BoilerplateKind::kNormalBoilerplate> v(site_context, true,
8218 hints);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00008219 MaybeHandle<JSObject> copy = v.StructureWalk(object);
8220 Handle<JSObject> for_assert;
8221 DCHECK(!copy.ToHandle(&for_assert) || !for_assert.is_identical_to(object));
8222 return copy;
Steve Block8defd9f2010-07-08 12:39:36 +01008223}
8224
Ben Murdoch097c5b22016-05-18 11:27:45 +01008225class DummyContextObject : public AllocationSiteContext {
8226 public:
8227 explicit DummyContextObject(Isolate* isolate)
8228 : AllocationSiteContext(isolate) {}
8229
8230 bool ShouldCreateMemento(Handle<JSObject> object) { return false; }
8231 Handle<AllocationSite> EnterNewScope() { return Handle<AllocationSite>(); }
8232 void ExitScope(Handle<AllocationSite> site, Handle<JSObject> object) {}
8233};
8234
8235MaybeHandle<JSObject> JSObject::DeepCopyApiBoilerplate(
8236 Handle<JSObject> object) {
8237 DummyContextObject dummy_context_object(object->GetIsolate());
8238 JSObjectWalkVisitor<DummyContextObject, BoilerplateKind::kApiBoilerplate> v(
8239 &dummy_context_object, true, kNoHints);
8240 MaybeHandle<JSObject> copy = v.StructureWalk(object);
8241 Handle<JSObject> for_assert;
8242 DCHECK(!copy.ToHandle(&for_assert) || !for_assert.is_identical_to(object));
8243 return copy;
8244}
Steve Block8defd9f2010-07-08 12:39:36 +01008245
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00008246// static
8247MaybeHandle<Object> JSReceiver::ToPrimitive(Handle<JSReceiver> receiver,
8248 ToPrimitiveHint hint) {
8249 Isolate* const isolate = receiver->GetIsolate();
8250 Handle<Object> exotic_to_prim;
8251 ASSIGN_RETURN_ON_EXCEPTION(
8252 isolate, exotic_to_prim,
8253 GetMethod(receiver, isolate->factory()->to_primitive_symbol()), Object);
8254 if (!exotic_to_prim->IsUndefined()) {
8255 Handle<Object> hint_string;
8256 switch (hint) {
8257 case ToPrimitiveHint::kDefault:
8258 hint_string = isolate->factory()->default_string();
8259 break;
8260 case ToPrimitiveHint::kNumber:
8261 hint_string = isolate->factory()->number_string();
8262 break;
8263 case ToPrimitiveHint::kString:
8264 hint_string = isolate->factory()->string_string();
8265 break;
8266 }
8267 Handle<Object> result;
8268 ASSIGN_RETURN_ON_EXCEPTION(
8269 isolate, result,
8270 Execution::Call(isolate, exotic_to_prim, receiver, 1, &hint_string),
8271 Object);
8272 if (result->IsPrimitive()) return result;
8273 THROW_NEW_ERROR(isolate,
8274 NewTypeError(MessageTemplate::kCannotConvertToPrimitive),
8275 Object);
8276 }
8277 return OrdinaryToPrimitive(receiver, (hint == ToPrimitiveHint::kString)
8278 ? OrdinaryToPrimitiveHint::kString
8279 : OrdinaryToPrimitiveHint::kNumber);
8280}
8281
8282
8283// static
8284MaybeHandle<Object> JSReceiver::OrdinaryToPrimitive(
8285 Handle<JSReceiver> receiver, OrdinaryToPrimitiveHint hint) {
8286 Isolate* const isolate = receiver->GetIsolate();
8287 Handle<String> method_names[2];
8288 switch (hint) {
8289 case OrdinaryToPrimitiveHint::kNumber:
8290 method_names[0] = isolate->factory()->valueOf_string();
8291 method_names[1] = isolate->factory()->toString_string();
8292 break;
8293 case OrdinaryToPrimitiveHint::kString:
8294 method_names[0] = isolate->factory()->toString_string();
8295 method_names[1] = isolate->factory()->valueOf_string();
8296 break;
8297 }
8298 for (Handle<String> name : method_names) {
8299 Handle<Object> method;
8300 ASSIGN_RETURN_ON_EXCEPTION(isolate, method,
8301 JSReceiver::GetProperty(receiver, name), Object);
8302 if (method->IsCallable()) {
8303 Handle<Object> result;
8304 ASSIGN_RETURN_ON_EXCEPTION(
8305 isolate, result, Execution::Call(isolate, method, receiver, 0, NULL),
8306 Object);
8307 if (result->IsPrimitive()) return result;
8308 }
8309 }
8310 THROW_NEW_ERROR(isolate,
8311 NewTypeError(MessageTemplate::kCannotConvertToPrimitive),
8312 Object);
8313}
8314
8315
8316// TODO(cbruni/jkummerow): Consider moving this into elements.cc.
8317bool HasEnumerableElements(JSObject* object) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00008318 switch (object->GetElementsKind()) {
8319 case FAST_SMI_ELEMENTS:
8320 case FAST_ELEMENTS:
8321 case FAST_DOUBLE_ELEMENTS: {
8322 int length = object->IsJSArray()
8323 ? Smi::cast(JSArray::cast(object)->length())->value()
8324 : object->elements()->length();
8325 return length > 0;
8326 }
8327 case FAST_HOLEY_SMI_ELEMENTS:
8328 case FAST_HOLEY_ELEMENTS: {
8329 FixedArray* elements = FixedArray::cast(object->elements());
8330 int length = object->IsJSArray()
8331 ? Smi::cast(JSArray::cast(object)->length())->value()
8332 : elements->length();
8333 for (int i = 0; i < length; i++) {
8334 if (!elements->is_the_hole(i)) return true;
8335 }
8336 return false;
8337 }
8338 case FAST_HOLEY_DOUBLE_ELEMENTS: {
8339 int length = object->IsJSArray()
8340 ? Smi::cast(JSArray::cast(object)->length())->value()
8341 : object->elements()->length();
8342 // Zero-length arrays would use the empty FixedArray...
8343 if (length == 0) return false;
8344 // ...so only cast to FixedDoubleArray otherwise.
8345 FixedDoubleArray* elements = FixedDoubleArray::cast(object->elements());
8346 for (int i = 0; i < length; i++) {
8347 if (!elements->is_the_hole(i)) return true;
8348 }
8349 return false;
8350 }
8351#define TYPED_ARRAY_CASE(Type, type, TYPE, ctype, size) \
8352 case TYPE##_ELEMENTS:
8353
8354 TYPED_ARRAYS(TYPED_ARRAY_CASE)
8355#undef TYPED_ARRAY_CASE
8356 {
8357 int length = object->elements()->length();
8358 return length > 0;
8359 }
8360 case DICTIONARY_ELEMENTS: {
8361 SeededNumberDictionary* elements =
8362 SeededNumberDictionary::cast(object->elements());
8363 return elements->NumberOfElementsFilterAttributes(ONLY_ENUMERABLE) > 0;
8364 }
8365 case FAST_SLOPPY_ARGUMENTS_ELEMENTS:
8366 case SLOW_SLOPPY_ARGUMENTS_ELEMENTS:
8367 // We're approximating non-empty arguments objects here.
8368 return true;
Ben Murdoch097c5b22016-05-18 11:27:45 +01008369 case FAST_STRING_WRAPPER_ELEMENTS:
8370 case SLOW_STRING_WRAPPER_ELEMENTS:
8371 if (String::cast(JSValue::cast(object)->value())->length() > 0) {
8372 return true;
8373 }
8374 return object->elements()->length() > 0;
8375 case NO_ELEMENTS:
8376 return false;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00008377 }
8378 UNREACHABLE();
8379 return true;
8380}
8381
8382
Steve Blocka7e24c12009-10-30 11:49:00 +00008383// Tests for the fast common case for property enumeration:
Ben Murdoch3ef787d2012-04-12 10:51:47 +01008384// - This object and all prototypes has an enum cache (which means that
8385// it is no proxy, has no interceptors and needs no access checks).
Steve Blockd0582a62009-12-15 09:54:21 +00008386// - This object has no elements.
8387// - No prototype has enumerable properties/elements.
Ben Murdoch3ef787d2012-04-12 10:51:47 +01008388bool JSReceiver::IsSimpleEnum() {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00008389 for (PrototypeIterator iter(GetIsolate(), this,
8390 PrototypeIterator::START_AT_RECEIVER);
8391 !iter.IsAtEnd(); iter.Advance()) {
8392 if (!iter.GetCurrent()->IsJSObject()) return false;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00008393 JSObject* current = iter.GetCurrent<JSObject>();
8394 int enum_length = current->map()->EnumLength();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00008395 if (enum_length == kInvalidEnumCacheSentinel) return false;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00008396 if (current->IsAccessCheckNeeded()) return false;
8397 DCHECK(!current->HasNamedInterceptor());
8398 DCHECK(!current->HasIndexedInterceptor());
8399 if (HasEnumerableElements(current)) return false;
8400 if (current != this && enum_length != 0) return false;
Steve Blocka7e24c12009-10-30 11:49:00 +00008401 }
8402 return true;
8403}
8404
8405
Ben Murdochb8a8cc12014-11-26 15:28:44 +00008406int Map::NumberOfDescribedProperties(DescriptorFlag which,
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00008407 PropertyFilter filter) {
Steve Blocka7e24c12009-10-30 11:49:00 +00008408 int result = 0;
8409 DescriptorArray* descs = instance_descriptors();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00008410 int limit = which == ALL_DESCRIPTORS
8411 ? descs->number_of_descriptors()
8412 : NumberOfOwnDescriptors();
8413 for (int i = 0; i < limit; i++) {
8414 if ((descs->GetDetails(i).attributes() & filter) == 0 &&
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00008415 !descs->GetKey(i)->FilterKey(filter)) {
Ben Murdoch3ef787d2012-04-12 10:51:47 +01008416 result++;
8417 }
Steve Blocka7e24c12009-10-30 11:49:00 +00008418 }
8419 return result;
8420}
8421
8422
Steve Blocka7e24c12009-10-30 11:49:00 +00008423int Map::NextFreePropertyIndex() {
Emily Bernierd0a1eb72015-03-24 16:35:39 -04008424 int free_index = 0;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00008425 int number_of_own_descriptors = NumberOfOwnDescriptors();
Steve Blocka7e24c12009-10-30 11:49:00 +00008426 DescriptorArray* descs = instance_descriptors();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00008427 for (int i = 0; i < number_of_own_descriptors; i++) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -04008428 PropertyDetails details = descs->GetDetails(i);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00008429 if (details.location() == kField) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -04008430 int candidate = details.field_index() + details.field_width_in_words();
8431 if (candidate > free_index) free_index = candidate;
Steve Blocka7e24c12009-10-30 11:49:00 +00008432 }
8433 }
Emily Bernierd0a1eb72015-03-24 16:35:39 -04008434 return free_index;
Steve Blocka7e24c12009-10-30 11:49:00 +00008435}
8436
8437
Ben Murdochb8a8cc12014-11-26 15:28:44 +00008438static bool ContainsOnlyValidKeys(Handle<FixedArray> array) {
8439 int len = array->length();
8440 for (int i = 0; i < len; i++) {
8441 Object* e = array->get(i);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04008442 if (!(e->IsName() || e->IsNumber())) return false;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00008443 }
8444 return true;
8445}
8446
8447
8448static Handle<FixedArray> ReduceFixedArrayTo(
8449 Handle<FixedArray> array, int length) {
Ben Murdoch097c5b22016-05-18 11:27:45 +01008450 DCHECK_LE(length, array->length());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00008451 if (array->length() == length) return array;
Ben Murdoch097c5b22016-05-18 11:27:45 +01008452 return array->GetIsolate()->factory()->CopyFixedArrayUpTo(array, length);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00008453}
8454
Ben Murdoch097c5b22016-05-18 11:27:45 +01008455bool Map::OnlyHasSimpleProperties() {
8456 // Wrapped string elements aren't explicitly stored in the elements backing
8457 // store, but are loaded indirectly from the underlying string.
8458 return !IsStringWrapperElementsKind(elements_kind()) &&
8459 !is_access_check_needed() && !has_named_interceptor() &&
8460 !has_indexed_interceptor() && !has_hidden_prototype() &&
8461 !is_dictionary_map();
8462}
Ben Murdochb8a8cc12014-11-26 15:28:44 +00008463
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00008464namespace {
8465
8466Handle<FixedArray> GetFastEnumPropertyKeys(Isolate* isolate,
Ben Murdoch097c5b22016-05-18 11:27:45 +01008467 Handle<JSObject> object) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00008468 Handle<Map> map(object->map());
Ben Murdoch097c5b22016-05-18 11:27:45 +01008469 bool cache_enum_length = map->OnlyHasSimpleProperties();
8470
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00008471 Handle<DescriptorArray> descs =
8472 Handle<DescriptorArray>(map->instance_descriptors(), isolate);
8473 int own_property_count = map->EnumLength();
8474 // If the enum length of the given map is set to kInvalidEnumCache, this
8475 // means that the map itself has never used the present enum cache. The
8476 // first step to using the cache is to set the enum length of the map by
8477 // counting the number of own descriptors that are ENUMERABLE_STRINGS.
8478 if (own_property_count == kInvalidEnumCacheSentinel) {
8479 own_property_count =
8480 map->NumberOfDescribedProperties(OWN_DESCRIPTORS, ENUMERABLE_STRINGS);
8481 } else {
8482 DCHECK(
8483 own_property_count ==
8484 map->NumberOfDescribedProperties(OWN_DESCRIPTORS, ENUMERABLE_STRINGS));
8485 }
8486
8487 if (descs->HasEnumCache()) {
8488 Handle<FixedArray> keys(descs->GetEnumCache(), isolate);
8489 // In case the number of properties required in the enum are actually
8490 // present, we can reuse the enum cache. Otherwise, this means that the
8491 // enum cache was generated for a previous (smaller) version of the
8492 // Descriptor Array. In that case we regenerate the enum cache.
8493 if (own_property_count <= keys->length()) {
8494 isolate->counters()->enum_cache_hits()->Increment();
8495 if (cache_enum_length) map->SetEnumLength(own_property_count);
8496 return ReduceFixedArrayTo(keys, own_property_count);
8497 }
8498 }
8499
8500 if (descs->IsEmpty()) {
8501 isolate->counters()->enum_cache_hits()->Increment();
8502 if (cache_enum_length) map->SetEnumLength(0);
8503 return isolate->factory()->empty_fixed_array();
8504 }
8505
8506 isolate->counters()->enum_cache_misses()->Increment();
8507
8508 Handle<FixedArray> storage =
8509 isolate->factory()->NewFixedArray(own_property_count);
8510 Handle<FixedArray> indices =
8511 isolate->factory()->NewFixedArray(own_property_count);
8512
8513 int size = map->NumberOfOwnDescriptors();
8514 int index = 0;
8515
8516 for (int i = 0; i < size; i++) {
8517 PropertyDetails details = descs->GetDetails(i);
8518 Object* key = descs->GetKey(i);
8519 if (details.IsDontEnum() || key->IsSymbol()) continue;
8520 storage->set(index, key);
8521 if (!indices.is_null()) {
8522 if (details.type() != DATA) {
8523 indices = Handle<FixedArray>();
8524 } else {
8525 FieldIndex field_index = FieldIndex::ForDescriptor(*map, i);
8526 int load_by_field_index = field_index.GetLoadByFieldIndex();
8527 indices->set(index, Smi::FromInt(load_by_field_index));
8528 }
8529 }
8530 index++;
8531 }
8532 DCHECK(index == storage->length());
8533
8534 DescriptorArray::SetEnumCache(descs, isolate, storage, indices);
8535 if (cache_enum_length) {
8536 map->SetEnumLength(own_property_count);
8537 }
8538 return storage;
8539}
8540
8541} // namespace
8542
Ben Murdoch097c5b22016-05-18 11:27:45 +01008543Handle<FixedArray> JSObject::GetEnumPropertyKeys(Handle<JSObject> object) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00008544 Isolate* isolate = object->GetIsolate();
8545 if (object->HasFastProperties()) {
Ben Murdoch097c5b22016-05-18 11:27:45 +01008546 return GetFastEnumPropertyKeys(isolate, object);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00008547 } else if (object->IsJSGlobalObject()) {
8548 Handle<GlobalDictionary> dictionary(object->global_dictionary());
8549 int length = dictionary->NumberOfEnumElements();
8550 if (length == 0) {
8551 return Handle<FixedArray>(isolate->heap()->empty_fixed_array());
Steve Blocka7e24c12009-10-30 11:49:00 +00008552 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00008553 Handle<FixedArray> storage = isolate->factory()->NewFixedArray(length);
8554 dictionary->CopyEnumKeysTo(*storage);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00008555 return storage;
8556 } else {
8557 Handle<NameDictionary> dictionary(object->property_dictionary());
8558 int length = dictionary->NumberOfEnumElements();
8559 if (length == 0) {
8560 return Handle<FixedArray>(isolate->heap()->empty_fixed_array());
8561 }
8562 Handle<FixedArray> storage = isolate->factory()->NewFixedArray(length);
8563 dictionary->CopyEnumKeysTo(*storage);
8564 return storage;
Steve Blocka7e24c12009-10-30 11:49:00 +00008565 }
Steve Blocka7e24c12009-10-30 11:49:00 +00008566}
8567
8568
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00008569enum IndexedOrNamed { kIndexed, kNamed };
Steve Blocka7e24c12009-10-30 11:49:00 +00008570
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00008571
8572// Returns |true| on success, |nothing| on exception.
8573template <class Callback, IndexedOrNamed type>
8574static Maybe<bool> GetKeysFromInterceptor(Isolate* isolate,
8575 Handle<JSReceiver> receiver,
8576 Handle<JSObject> object,
8577 PropertyFilter filter,
8578 KeyAccumulator* accumulator) {
8579 if (type == kIndexed) {
8580 if (!object->HasIndexedInterceptor()) return Just(true);
8581 } else {
8582 if (!object->HasNamedInterceptor()) return Just(true);
8583 }
8584 Handle<InterceptorInfo> interceptor(type == kIndexed
8585 ? object->GetIndexedInterceptor()
8586 : object->GetNamedInterceptor(),
8587 isolate);
8588 if ((filter & ONLY_ALL_CAN_READ) && !interceptor->all_can_read()) {
8589 return Just(true);
8590 }
8591 PropertyCallbackArguments args(isolate, interceptor->data(), *receiver,
Ben Murdoch097c5b22016-05-18 11:27:45 +01008592 *object, Object::DONT_THROW);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00008593 v8::Local<v8::Object> result;
8594 if (!interceptor->enumerator()->IsUndefined()) {
8595 Callback enum_fun = v8::ToCData<Callback>(interceptor->enumerator());
8596 const char* log_tag = type == kIndexed ? "interceptor-indexed-enum"
8597 : "interceptor-named-enum";
8598 LOG(isolate, ApiObjectAccess(log_tag, *object));
8599 result = args.Call(enum_fun);
8600 }
8601 RETURN_VALUE_IF_SCHEDULED_EXCEPTION(isolate, Nothing<bool>());
8602 if (result.IsEmpty()) return Just(true);
8603 DCHECK(v8::Utils::OpenHandle(*result)->IsJSArray() ||
8604 (v8::Utils::OpenHandle(*result)->IsJSObject() &&
8605 Handle<JSObject>::cast(v8::Utils::OpenHandle(*result))
8606 ->HasSloppyArgumentsElements()));
8607 // The accumulator takes care of string/symbol filtering.
8608 if (type == kIndexed) {
8609 accumulator->AddElementKeysFromInterceptor(
8610 Handle<JSObject>::cast(v8::Utils::OpenHandle(*result)));
8611 } else {
Ben Murdoch097c5b22016-05-18 11:27:45 +01008612 accumulator->AddKeys(Handle<JSObject>::cast(v8::Utils::OpenHandle(*result)),
8613 DO_NOT_CONVERT);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00008614 }
8615 return Just(true);
8616}
8617
8618
8619// Returns |true| on success, |false| if prototype walking should be stopped,
8620// |nothing| if an exception was thrown.
8621static Maybe<bool> GetKeysFromJSObject(Isolate* isolate,
8622 Handle<JSReceiver> receiver,
8623 Handle<JSObject> object,
8624 PropertyFilter* filter,
Ben Murdoch097c5b22016-05-18 11:27:45 +01008625 KeyCollectionType type,
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00008626 KeyAccumulator* accumulator) {
8627 accumulator->NextPrototype();
8628 // Check access rights if required.
8629 if (object->IsAccessCheckNeeded() &&
8630 !isolate->MayAccess(handle(isolate->context()), object)) {
8631 // The cross-origin spec says that [[Enumerate]] shall return an empty
8632 // iterator when it doesn't have access...
Ben Murdoch097c5b22016-05-18 11:27:45 +01008633 if (type == INCLUDE_PROTOS) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00008634 return Just(false);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00008635 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00008636 // ...whereas [[OwnPropertyKeys]] shall return whitelisted properties.
Ben Murdoch097c5b22016-05-18 11:27:45 +01008637 DCHECK_EQ(OWN_ONLY, type);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00008638 *filter = static_cast<PropertyFilter>(*filter | ONLY_ALL_CAN_READ);
8639 }
Steve Block44f0eee2011-05-26 01:26:41 +01008640
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00008641 JSObject::CollectOwnElementKeys(object, accumulator, *filter);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00008642
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00008643 // Add the element keys from the interceptor.
8644 Maybe<bool> success =
8645 GetKeysFromInterceptor<v8::IndexedPropertyEnumeratorCallback, kIndexed>(
8646 isolate, receiver, object, *filter, accumulator);
8647 MAYBE_RETURN(success, Nothing<bool>());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00008648
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00008649 if (*filter == ENUMERABLE_STRINGS) {
Ben Murdoch097c5b22016-05-18 11:27:45 +01008650 Handle<FixedArray> enum_keys = JSObject::GetEnumPropertyKeys(object);
8651 accumulator->AddKeys(enum_keys, DO_NOT_CONVERT);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00008652 } else {
8653 object->CollectOwnPropertyNames(accumulator, *filter);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01008654 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00008655
8656 // Add the property keys from the interceptor.
8657 success = GetKeysFromInterceptor<v8::GenericNamedPropertyEnumeratorCallback,
8658 kNamed>(isolate, receiver, object, *filter,
8659 accumulator);
8660 MAYBE_RETURN(success, Nothing<bool>());
8661 return Just(true);
Steve Blocka7e24c12009-10-30 11:49:00 +00008662}
8663
8664
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00008665// Helper function for JSReceiver::GetKeys() below. Can be called recursively.
8666// Returns |true| or |nothing|.
8667static Maybe<bool> GetKeys_Internal(Isolate* isolate,
8668 Handle<JSReceiver> receiver,
8669 Handle<JSReceiver> object,
Ben Murdoch097c5b22016-05-18 11:27:45 +01008670 KeyCollectionType type,
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00008671 PropertyFilter filter,
8672 KeyAccumulator* accumulator) {
Ben Murdoch097c5b22016-05-18 11:27:45 +01008673 PrototypeIterator::WhereToEnd end = type == OWN_ONLY
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00008674 ? PrototypeIterator::END_AT_NON_HIDDEN
8675 : PrototypeIterator::END_AT_NULL;
8676 for (PrototypeIterator iter(isolate, object,
Ben Murdoch097c5b22016-05-18 11:27:45 +01008677 PrototypeIterator::START_AT_RECEIVER, end);
8678 !iter.IsAtEnd(); iter.Advance()) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00008679 Handle<JSReceiver> current =
8680 PrototypeIterator::GetCurrent<JSReceiver>(iter);
8681 Maybe<bool> result = Just(false); // Dummy initialization.
8682 if (current->IsJSProxy()) {
Ben Murdoch097c5b22016-05-18 11:27:45 +01008683 result = JSProxy::OwnPropertyKeys(isolate, receiver,
8684 Handle<JSProxy>::cast(current), filter,
8685 accumulator);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00008686 } else {
8687 DCHECK(current->IsJSObject());
8688 result = GetKeysFromJSObject(isolate, receiver,
8689 Handle<JSObject>::cast(current), &filter,
8690 type, accumulator);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01008691 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00008692 MAYBE_RETURN(result, Nothing<bool>());
8693 if (!result.FromJust()) break; // |false| means "stop iterating".
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00008694 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00008695 return Just(true);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00008696}
8697
8698
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00008699// ES6 9.5.12
8700// Returns |true| on success, |nothing| in case of exception.
8701// static
8702Maybe<bool> JSProxy::OwnPropertyKeys(Isolate* isolate,
8703 Handle<JSReceiver> receiver,
8704 Handle<JSProxy> proxy,
8705 PropertyFilter filter,
8706 KeyAccumulator* accumulator) {
8707 STACK_CHECK(Nothing<bool>());
8708 // 1. Let handler be the value of the [[ProxyHandler]] internal slot of O.
8709 Handle<Object> handler(proxy->handler(), isolate);
8710 // 2. If handler is null, throw a TypeError exception.
8711 // 3. Assert: Type(handler) is Object.
8712 if (proxy->IsRevoked()) {
8713 isolate->Throw(*isolate->factory()->NewTypeError(
8714 MessageTemplate::kProxyRevoked, isolate->factory()->ownKeys_string()));
8715 return Nothing<bool>();
8716 }
8717 // 4. Let target be the value of the [[ProxyTarget]] internal slot of O.
8718 Handle<JSReceiver> target(proxy->target(), isolate);
8719 // 5. Let trap be ? GetMethod(handler, "ownKeys").
8720 Handle<Object> trap;
8721 ASSIGN_RETURN_ON_EXCEPTION_VALUE(
8722 isolate, trap, Object::GetMethod(Handle<JSReceiver>::cast(handler),
8723 isolate->factory()->ownKeys_string()),
8724 Nothing<bool>());
8725 // 6. If trap is undefined, then
8726 if (trap->IsUndefined()) {
8727 // 6a. Return target.[[OwnPropertyKeys]]().
8728 return GetKeys_Internal(isolate, receiver, target, OWN_ONLY, filter,
8729 accumulator);
8730 }
8731 // 7. Let trapResultArray be Call(trap, handler, «target»).
8732 Handle<Object> trap_result_array;
8733 Handle<Object> args[] = {target};
8734 ASSIGN_RETURN_ON_EXCEPTION_VALUE(
8735 isolate, trap_result_array,
8736 Execution::Call(isolate, trap, handler, arraysize(args), args),
8737 Nothing<bool>());
8738 // 8. Let trapResult be ? CreateListFromArrayLike(trapResultArray,
8739 // «String, Symbol»).
8740 Handle<FixedArray> trap_result;
8741 ASSIGN_RETURN_ON_EXCEPTION_VALUE(
8742 isolate, trap_result,
8743 Object::CreateListFromArrayLike(isolate, trap_result_array,
8744 ElementTypes::kStringAndSymbol),
8745 Nothing<bool>());
8746 // 9. Let extensibleTarget be ? IsExtensible(target).
8747 Maybe<bool> maybe_extensible = JSReceiver::IsExtensible(target);
8748 MAYBE_RETURN(maybe_extensible, Nothing<bool>());
8749 bool extensible_target = maybe_extensible.FromJust();
8750 // 10. Let targetKeys be ? target.[[OwnPropertyKeys]]().
8751 Handle<FixedArray> target_keys;
8752 ASSIGN_RETURN_ON_EXCEPTION_VALUE(isolate, target_keys,
8753 JSReceiver::OwnPropertyKeys(target),
8754 Nothing<bool>());
8755 // 11. (Assert)
8756 // 12. Let targetConfigurableKeys be an empty List.
8757 // To save memory, we're re-using target_keys and will modify it in-place.
8758 Handle<FixedArray> target_configurable_keys = target_keys;
8759 // 13. Let targetNonconfigurableKeys be an empty List.
8760 Handle<FixedArray> target_nonconfigurable_keys =
8761 isolate->factory()->NewFixedArray(target_keys->length());
8762 int nonconfigurable_keys_length = 0;
8763 // 14. Repeat, for each element key of targetKeys:
8764 for (int i = 0; i < target_keys->length(); ++i) {
8765 // 14a. Let desc be ? target.[[GetOwnProperty]](key).
8766 PropertyDescriptor desc;
8767 Maybe<bool> found = JSReceiver::GetOwnPropertyDescriptor(
8768 isolate, target, handle(target_keys->get(i), isolate), &desc);
8769 MAYBE_RETURN(found, Nothing<bool>());
8770 // 14b. If desc is not undefined and desc.[[Configurable]] is false, then
8771 if (found.FromJust() && !desc.configurable()) {
8772 // 14b i. Append key as an element of targetNonconfigurableKeys.
8773 target_nonconfigurable_keys->set(nonconfigurable_keys_length,
8774 target_keys->get(i));
8775 nonconfigurable_keys_length++;
8776 // The key was moved, null it out in the original list.
8777 target_keys->set(i, Smi::FromInt(0));
8778 } else {
8779 // 14c. Else,
8780 // 14c i. Append key as an element of targetConfigurableKeys.
8781 // (No-op, just keep it in |target_keys|.)
Steve Blocka7e24c12009-10-30 11:49:00 +00008782 }
Ben Murdoch3ef787d2012-04-12 10:51:47 +01008783 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00008784 accumulator->NextPrototype(); // Prepare for accumulating keys.
8785 // 15. If extensibleTarget is true and targetNonconfigurableKeys is empty,
8786 // then:
8787 if (extensible_target && nonconfigurable_keys_length == 0) {
8788 // 15a. Return trapResult.
8789 return accumulator->AddKeysFromProxy(proxy, trap_result);
8790 }
8791 // 16. Let uncheckedResultKeys be a new List which is a copy of trapResult.
8792 Zone set_zone;
8793 const int kPresent = 1;
8794 const int kGone = 0;
8795 IdentityMap<int> unchecked_result_keys(isolate->heap(), &set_zone);
Ben Murdoch097c5b22016-05-18 11:27:45 +01008796 int unchecked_result_keys_size = 0;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00008797 for (int i = 0; i < trap_result->length(); ++i) {
8798 DCHECK(trap_result->get(i)->IsUniqueName());
Ben Murdoch097c5b22016-05-18 11:27:45 +01008799 Object* key = trap_result->get(i);
8800 int* entry = unchecked_result_keys.Get(key);
8801 if (*entry != kPresent) {
8802 *entry = kPresent;
8803 unchecked_result_keys_size++;
8804 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00008805 }
8806 // 17. Repeat, for each key that is an element of targetNonconfigurableKeys:
8807 for (int i = 0; i < nonconfigurable_keys_length; ++i) {
8808 Object* key = target_nonconfigurable_keys->get(i);
8809 // 17a. If key is not an element of uncheckedResultKeys, throw a
8810 // TypeError exception.
8811 int* found = unchecked_result_keys.Find(key);
8812 if (found == nullptr || *found == kGone) {
8813 isolate->Throw(*isolate->factory()->NewTypeError(
8814 MessageTemplate::kProxyOwnKeysMissing, handle(key, isolate)));
8815 return Nothing<bool>();
8816 }
8817 // 17b. Remove key from uncheckedResultKeys.
8818 *found = kGone;
8819 unchecked_result_keys_size--;
8820 }
8821 // 18. If extensibleTarget is true, return trapResult.
8822 if (extensible_target) {
8823 return accumulator->AddKeysFromProxy(proxy, trap_result);
8824 }
8825 // 19. Repeat, for each key that is an element of targetConfigurableKeys:
8826 for (int i = 0; i < target_configurable_keys->length(); ++i) {
8827 Object* key = target_configurable_keys->get(i);
8828 if (key->IsSmi()) continue; // Zapped entry, was nonconfigurable.
8829 // 19a. If key is not an element of uncheckedResultKeys, throw a
8830 // TypeError exception.
8831 int* found = unchecked_result_keys.Find(key);
8832 if (found == nullptr || *found == kGone) {
8833 isolate->Throw(*isolate->factory()->NewTypeError(
8834 MessageTemplate::kProxyOwnKeysMissing, handle(key, isolate)));
8835 return Nothing<bool>();
8836 }
8837 // 19b. Remove key from uncheckedResultKeys.
8838 *found = kGone;
8839 unchecked_result_keys_size--;
8840 }
8841 // 20. If uncheckedResultKeys is not empty, throw a TypeError exception.
8842 if (unchecked_result_keys_size != 0) {
8843 DCHECK_GT(unchecked_result_keys_size, 0);
8844 isolate->Throw(*isolate->factory()->NewTypeError(
8845 MessageTemplate::kProxyOwnKeysNonExtensible));
8846 return Nothing<bool>();
8847 }
8848 // 21. Return trapResult.
8849 return accumulator->AddKeysFromProxy(proxy, trap_result);
8850}
Ben Murdoch3ef787d2012-04-12 10:51:47 +01008851
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00008852
8853MaybeHandle<FixedArray> JSReceiver::GetKeys(Handle<JSReceiver> object,
8854 KeyCollectionType type,
8855 PropertyFilter filter,
8856 GetKeysConversion keys_conversion) {
8857 USE(ContainsOnlyValidKeys);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00008858 Isolate* isolate = object->GetIsolate();
Ben Murdoch097c5b22016-05-18 11:27:45 +01008859 KeyAccumulator accumulator(isolate, type, filter);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00008860 MAYBE_RETURN(
8861 GetKeys_Internal(isolate, object, object, type, filter, &accumulator),
8862 MaybeHandle<FixedArray>());
8863 Handle<FixedArray> keys = accumulator.GetKeys(keys_conversion);
8864 DCHECK(ContainsOnlyValidKeys(keys));
8865 return keys;
Ben Murdoch3ef787d2012-04-12 10:51:47 +01008866}
8867
Ben Murdoch097c5b22016-05-18 11:27:45 +01008868MaybeHandle<FixedArray> GetOwnValuesOrEntries(Isolate* isolate,
8869 Handle<JSReceiver> object,
8870 PropertyFilter filter,
8871 bool get_entries) {
8872 PropertyFilter key_filter =
8873 static_cast<PropertyFilter>(filter & ~ONLY_ENUMERABLE);
8874 KeyAccumulator accumulator(isolate, OWN_ONLY, key_filter);
8875 MAYBE_RETURN(GetKeys_Internal(isolate, object, object, OWN_ONLY, key_filter,
8876 &accumulator),
8877 MaybeHandle<FixedArray>());
8878 Handle<FixedArray> keys = accumulator.GetKeys(CONVERT_TO_STRING);
8879 DCHECK(ContainsOnlyValidKeys(keys));
8880
8881 Handle<FixedArray> values_or_entries =
8882 isolate->factory()->NewFixedArray(keys->length());
8883 int length = 0;
8884
8885 for (int i = 0; i < keys->length(); ++i) {
8886 Handle<Name> key = Handle<Name>::cast(handle(keys->get(i), isolate));
8887
8888 if (filter & ONLY_ENUMERABLE) {
8889 PropertyDescriptor descriptor;
8890 Maybe<bool> did_get_descriptor = JSReceiver::GetOwnPropertyDescriptor(
8891 isolate, object, key, &descriptor);
8892 MAYBE_RETURN(did_get_descriptor, MaybeHandle<FixedArray>());
8893 if (!did_get_descriptor.FromJust() || !descriptor.enumerable()) continue;
8894 }
8895
8896 Handle<Object> value;
8897 ASSIGN_RETURN_ON_EXCEPTION_VALUE(
8898 isolate, value, JSReceiver::GetPropertyOrElement(object, key),
8899 MaybeHandle<FixedArray>());
8900
8901 if (get_entries) {
8902 Handle<FixedArray> entry_storage =
8903 isolate->factory()->NewUninitializedFixedArray(2);
8904 entry_storage->set(0, *key);
8905 entry_storage->set(1, *value);
8906 value = isolate->factory()->NewJSArrayWithElements(entry_storage,
8907 FAST_ELEMENTS, 2);
8908 }
8909
8910 values_or_entries->set(length, *value);
8911 length++;
8912 }
8913 if (length < values_or_entries->length()) values_or_entries->Shrink(length);
8914 return values_or_entries;
8915}
8916
8917MaybeHandle<FixedArray> JSReceiver::GetOwnValues(Handle<JSReceiver> object,
8918 PropertyFilter filter) {
8919 return GetOwnValuesOrEntries(object->GetIsolate(), object, filter, false);
8920}
8921
8922MaybeHandle<FixedArray> JSReceiver::GetOwnEntries(Handle<JSReceiver> object,
8923 PropertyFilter filter) {
8924 return GetOwnValuesOrEntries(object->GetIsolate(), object, filter, true);
8925}
Ben Murdoch3ef787d2012-04-12 10:51:47 +01008926
Ben Murdochb8a8cc12014-11-26 15:28:44 +00008927bool Map::DictionaryElementsInPrototypeChainOnly() {
8928 if (IsDictionaryElementsKind(elements_kind())) {
8929 return false;
8930 }
8931
8932 for (PrototypeIterator iter(this); !iter.IsAtEnd(); iter.Advance()) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00008933 // Be conservative, don't walk into proxies.
8934 if (iter.GetCurrent()->IsJSProxy()) return true;
8935 // String wrappers have non-configurable, non-writable elements.
8936 if (iter.GetCurrent()->IsStringWrapper()) return true;
8937 JSObject* current = iter.GetCurrent<JSObject>();
8938
8939 if (current->HasDictionaryElements() &&
8940 current->element_dictionary()->requires_slow_elements()) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00008941 return true;
8942 }
8943
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00008944 if (current->HasSlowArgumentsElements()) {
8945 FixedArray* parameter_map = FixedArray::cast(current->elements());
8946 Object* arguments = parameter_map->get(1);
8947 if (SeededNumberDictionary::cast(arguments)->requires_slow_elements()) {
8948 return true;
8949 }
Steve Blocka7e24c12009-10-30 11:49:00 +00008950 }
8951 }
8952
Ben Murdochb8a8cc12014-11-26 15:28:44 +00008953 return false;
Leon Clarkef7060e22010-06-03 12:02:55 +01008954}
8955
8956
Ben Murdochb8a8cc12014-11-26 15:28:44 +00008957MaybeHandle<Object> JSObject::DefineAccessor(Handle<JSObject> object,
8958 Handle<Name> name,
8959 Handle<Object> getter,
8960 Handle<Object> setter,
8961 PropertyAttributes attributes) {
8962 Isolate* isolate = object->GetIsolate();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00008963
8964 LookupIterator it = LookupIterator::PropertyOrElement(
8965 isolate, object, name, LookupIterator::HIDDEN_SKIP_INTERCEPTOR);
8966 return DefineAccessor(&it, getter, setter, attributes);
8967}
8968
8969
8970MaybeHandle<Object> JSObject::DefineAccessor(LookupIterator* it,
8971 Handle<Object> getter,
8972 Handle<Object> setter,
8973 PropertyAttributes attributes) {
8974 Isolate* isolate = it->isolate();
8975
8976 if (it->state() == LookupIterator::ACCESS_CHECK) {
8977 if (!it->HasAccess()) {
8978 isolate->ReportFailedAccessCheck(it->GetHolder<JSObject>());
8979 RETURN_EXCEPTION_IF_SCHEDULED_EXCEPTION(isolate, Object);
8980 return isolate->factory()->undefined_value();
8981 }
8982 it->Next();
Steve Blocka7e24c12009-10-30 11:49:00 +00008983 }
8984
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00008985 Handle<JSObject> object = Handle<JSObject>::cast(it->GetReceiver());
8986 // Ignore accessors on typed arrays.
8987 if (it->IsElement() && object->HasFixedTypedArrayElements()) {
8988 return it->factory()->undefined_value();
Steve Blocka7e24c12009-10-30 11:49:00 +00008989 }
8990
Ben Murdochb8a8cc12014-11-26 15:28:44 +00008991 Handle<Object> old_value = isolate->factory()->the_hole_value();
8992 bool is_observed = object->map()->is_observed() &&
Ben Murdoch097c5b22016-05-18 11:27:45 +01008993 (it->IsElement() || !it->name()->IsPrivate());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00008994 bool preexists = false;
8995 if (is_observed) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00008996 CHECK(GetPropertyAttributes(it).IsJust());
8997 preexists = it->IsFound();
8998 if (preexists && (it->state() == LookupIterator::DATA ||
8999 it->GetAccessors()->IsAccessorInfo())) {
9000 old_value = GetProperty(it).ToHandleChecked();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009001 }
9002 }
9003
Ben Murdoch097c5b22016-05-18 11:27:45 +01009004 DCHECK(getter->IsCallable() || getter->IsUndefined() || getter->IsNull() ||
9005 getter->IsFunctionTemplateInfo());
9006 DCHECK(setter->IsCallable() || setter->IsUndefined() || setter->IsNull() ||
9007 getter->IsFunctionTemplateInfo());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00009008 // At least one of the accessors needs to be a new value.
9009 DCHECK(!getter->IsNull() || !setter->IsNull());
9010 if (!getter->IsNull()) {
9011 it->TransitionToAccessorProperty(ACCESSOR_GETTER, getter, attributes);
9012 }
9013 if (!setter->IsNull()) {
9014 it->TransitionToAccessorProperty(ACCESSOR_SETTER, setter, attributes);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009015 }
9016
9017 if (is_observed) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00009018 // Make sure the top context isn't changed.
9019 AssertNoContextChange ncc(isolate);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009020 const char* type = preexists ? "reconfigure" : "add";
Emily Bernierd0a1eb72015-03-24 16:35:39 -04009021 RETURN_ON_EXCEPTION(
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00009022 isolate, EnqueueChangeRecord(object, type, it->GetName(), old_value),
9023 Object);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009024 }
9025
9026 return isolate->factory()->undefined_value();
Steve Blocka7e24c12009-10-30 11:49:00 +00009027}
9028
9029
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009030MaybeHandle<Object> JSObject::SetAccessor(Handle<JSObject> object,
9031 Handle<AccessorInfo> info) {
9032 Isolate* isolate = object->GetIsolate();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00009033 Handle<Name> name(Name::cast(info->name()), isolate);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009034
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00009035 LookupIterator it = LookupIterator::PropertyOrElement(
9036 isolate, object, name, LookupIterator::HIDDEN_SKIP_INTERCEPTOR);
Leon Clarkef7060e22010-06-03 12:02:55 +01009037
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00009038 // Duplicate ACCESS_CHECK outside of GetPropertyAttributes for the case that
9039 // the FailedAccessCheckCallbackFunction doesn't throw an exception.
9040 //
9041 // TODO(verwaest): Force throw an exception if the callback doesn't, so we can
9042 // remove reliance on default return values.
9043 if (it.state() == LookupIterator::ACCESS_CHECK) {
9044 if (!it.HasAccess()) {
9045 isolate->ReportFailedAccessCheck(object);
9046 RETURN_EXCEPTION_IF_SCHEDULED_EXCEPTION(isolate, Object);
9047 return it.factory()->undefined_value();
Leon Clarkef7060e22010-06-03 12:02:55 +01009048 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00009049 it.Next();
Leon Clarkef7060e22010-06-03 12:02:55 +01009050 }
9051
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00009052 // Ignore accessors on typed arrays.
9053 if (it.IsElement() && object->HasFixedTypedArrayElements()) {
9054 return it.factory()->undefined_value();
9055 }
9056
9057 CHECK(GetPropertyAttributes(&it).IsJust());
9058
9059 // ES5 forbids turning a property into an accessor if it's not
9060 // configurable. See 8.6.1 (Table 5).
9061 if (it.IsFound() && !it.IsConfigurable()) {
9062 return it.factory()->undefined_value();
9063 }
9064
9065 it.TransitionToAccessorPair(info, info->property_attributes());
9066
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009067 return object;
Leon Clarkef7060e22010-06-03 12:02:55 +01009068}
9069
9070
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009071MaybeHandle<Object> JSObject::GetAccessor(Handle<JSObject> object,
9072 Handle<Name> name,
9073 AccessorComponent component) {
9074 Isolate* isolate = object->GetIsolate();
Steve Block44f0eee2011-05-26 01:26:41 +01009075
Steve Blocka7e24c12009-10-30 11:49:00 +00009076 // Make sure that the top context does not change when doing callbacks or
9077 // interceptor calls.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009078 AssertNoContextChange ncc(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00009079
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00009080 LookupIterator it = LookupIterator::PropertyOrElement(
9081 isolate, object, name, LookupIterator::PROTOTYPE_CHAIN_SKIP_INTERCEPTOR);
9082
9083 for (; it.IsFound(); it.Next()) {
9084 switch (it.state()) {
9085 case LookupIterator::INTERCEPTOR:
9086 case LookupIterator::NOT_FOUND:
9087 case LookupIterator::TRANSITION:
9088 UNREACHABLE();
9089
9090 case LookupIterator::ACCESS_CHECK:
9091 if (it.HasAccess()) continue;
9092 isolate->ReportFailedAccessCheck(it.GetHolder<JSObject>());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009093 RETURN_EXCEPTION_IF_SCHEDULED_EXCEPTION(isolate, Object);
9094 return isolate->factory()->undefined_value();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009095
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00009096 case LookupIterator::JSPROXY:
9097 return isolate->factory()->undefined_value();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009098
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00009099 case LookupIterator::INTEGER_INDEXED_EXOTIC:
9100 return isolate->factory()->undefined_value();
9101 case LookupIterator::DATA:
9102 continue;
9103 case LookupIterator::ACCESSOR: {
9104 Handle<Object> maybe_pair = it.GetAccessors();
9105 if (maybe_pair->IsAccessorPair()) {
Ben Murdoch097c5b22016-05-18 11:27:45 +01009106 return AccessorPair::GetComponent(
9107 Handle<AccessorPair>::cast(maybe_pair), component);
Steve Blocka7e24c12009-10-30 11:49:00 +00009108 }
9109 }
9110 }
9111 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00009112
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009113 return isolate->factory()->undefined_value();
Steve Blocka7e24c12009-10-30 11:49:00 +00009114}
9115
9116
9117Object* JSObject::SlowReverseLookup(Object* value) {
9118 if (HasFastProperties()) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009119 int number_of_own_descriptors = map()->NumberOfOwnDescriptors();
Steve Blocka7e24c12009-10-30 11:49:00 +00009120 DescriptorArray* descs = map()->instance_descriptors();
Emily Bernierd0a1eb72015-03-24 16:35:39 -04009121 bool value_is_number = value->IsNumber();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009122 for (int i = 0; i < number_of_own_descriptors; i++) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00009123 if (descs->GetType(i) == DATA) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -04009124 FieldIndex field_index = FieldIndex::ForDescriptor(map(), i);
9125 if (IsUnboxedDoubleField(field_index)) {
9126 if (value_is_number) {
9127 double property = RawFastDoublePropertyAt(field_index);
9128 if (property == value->Number()) {
9129 return descs->GetKey(i);
9130 }
9131 }
9132 } else {
9133 Object* property = RawFastPropertyAt(field_index);
9134 if (field_index.is_double()) {
9135 DCHECK(property->IsMutableHeapNumber());
9136 if (value_is_number && property->Number() == value->Number()) {
9137 return descs->GetKey(i);
9138 }
9139 } else if (property == value) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009140 return descs->GetKey(i);
9141 }
Steve Blocka7e24c12009-10-30 11:49:00 +00009142 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00009143 } else if (descs->GetType(i) == DATA_CONSTANT) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009144 if (descs->GetConstant(i) == value) {
Steve Blocka7e24c12009-10-30 11:49:00 +00009145 return descs->GetKey(i);
9146 }
9147 }
9148 }
Ben Murdoch8b112d22011-06-08 16:22:53 +01009149 return GetHeap()->undefined_value();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00009150 } else if (IsJSGlobalObject()) {
9151 return global_dictionary()->SlowReverseLookup(value);
Steve Blocka7e24c12009-10-30 11:49:00 +00009152 } else {
9153 return property_dictionary()->SlowReverseLookup(value);
9154 }
9155}
9156
9157
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009158Handle<Map> Map::RawCopy(Handle<Map> map, int instance_size) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00009159 Isolate* isolate = map->GetIsolate();
9160 Handle<Map> result =
9161 isolate->factory()->NewMap(map->instance_type(), instance_size);
9162 Handle<Object> prototype(map->prototype(), isolate);
9163 Map::SetPrototype(result, prototype);
9164 result->set_constructor_or_backpointer(map->GetConstructor());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009165 result->set_bit_field(map->bit_field());
9166 result->set_bit_field2(map->bit_field2());
9167 int new_bit_field3 = map->bit_field3();
9168 new_bit_field3 = OwnsDescriptors::update(new_bit_field3, true);
9169 new_bit_field3 = NumberOfOwnDescriptorsBits::update(new_bit_field3, 0);
9170 new_bit_field3 = EnumLengthBits::update(new_bit_field3,
9171 kInvalidEnumCacheSentinel);
9172 new_bit_field3 = Deprecated::update(new_bit_field3, false);
9173 if (!map->is_dictionary_map()) {
9174 new_bit_field3 = IsUnstable::update(new_bit_field3, false);
John Reck59135872010-11-02 12:39:01 -07009175 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009176 result->set_bit_field3(new_bit_field3);
Steve Blocka7e24c12009-10-30 11:49:00 +00009177 return result;
9178}
9179
9180
Emily Bernierd0a1eb72015-03-24 16:35:39 -04009181Handle<Map> Map::Normalize(Handle<Map> fast_map, PropertyNormalizationMode mode,
9182 const char* reason) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009183 DCHECK(!fast_map->is_dictionary_map());
9184
9185 Isolate* isolate = fast_map->GetIsolate();
9186 Handle<Object> maybe_cache(isolate->native_context()->normalized_map_cache(),
9187 isolate);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00009188 bool use_cache = !fast_map->is_prototype_map() && !maybe_cache->IsUndefined();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009189 Handle<NormalizedMapCache> cache;
9190 if (use_cache) cache = Handle<NormalizedMapCache>::cast(maybe_cache);
9191
9192 Handle<Map> new_map;
9193 if (use_cache && cache->Get(fast_map, mode).ToHandle(&new_map)) {
9194#ifdef VERIFY_HEAP
9195 if (FLAG_verify_heap) new_map->DictionaryMapVerify();
9196#endif
9197#ifdef ENABLE_SLOW_DCHECKS
9198 if (FLAG_enable_slow_asserts) {
9199 // The cached map should match newly created normalized map bit-by-bit,
9200 // except for the code cache, which can contain some ics which can be
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00009201 // applied to the shared map, dependent code and weak cell cache.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009202 Handle<Map> fresh = Map::CopyNormalized(fast_map, mode);
9203
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00009204 if (new_map->is_prototype_map()) {
9205 // For prototype maps, the PrototypeInfo is not copied.
9206 DCHECK(memcmp(fresh->address(), new_map->address(),
9207 kTransitionsOrPrototypeInfoOffset) == 0);
9208 DCHECK(fresh->raw_transitions() == Smi::FromInt(0));
9209 STATIC_ASSERT(kDescriptorsOffset ==
9210 kTransitionsOrPrototypeInfoOffset + kPointerSize);
9211 DCHECK(memcmp(HeapObject::RawField(*fresh, kDescriptorsOffset),
9212 HeapObject::RawField(*new_map, kDescriptorsOffset),
9213 kCodeCacheOffset - kDescriptorsOffset) == 0);
9214 } else {
9215 DCHECK(memcmp(fresh->address(), new_map->address(),
9216 Map::kCodeCacheOffset) == 0);
9217 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009218 STATIC_ASSERT(Map::kDependentCodeOffset ==
9219 Map::kCodeCacheOffset + kPointerSize);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00009220 STATIC_ASSERT(Map::kWeakCellCacheOffset ==
9221 Map::kDependentCodeOffset + kPointerSize);
9222 int offset = Map::kWeakCellCacheOffset + kPointerSize;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009223 DCHECK(memcmp(fresh->address() + offset,
9224 new_map->address() + offset,
9225 Map::kSize - offset) == 0);
9226 }
9227#endif
9228 } else {
9229 new_map = Map::CopyNormalized(fast_map, mode);
9230 if (use_cache) {
9231 cache->Set(fast_map, new_map);
Ben Murdoch097c5b22016-05-18 11:27:45 +01009232 isolate->counters()->maps_normalized()->Increment();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009233 }
Emily Bernierd0a1eb72015-03-24 16:35:39 -04009234#if TRACE_MAPS
9235 if (FLAG_trace_maps) {
9236 PrintF("[TraceMaps: Normalize from= %p to= %p reason= %s ]\n",
9237 reinterpret_cast<void*>(*fast_map),
9238 reinterpret_cast<void*>(*new_map), reason);
9239 }
9240#endif
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009241 }
9242 fast_map->NotifyLeafMapLayoutChange();
9243 return new_map;
9244}
9245
9246
9247Handle<Map> Map::CopyNormalized(Handle<Map> map,
9248 PropertyNormalizationMode mode) {
9249 int new_instance_size = map->instance_size();
Kristian Monsen80d68ea2010-09-08 11:05:35 +01009250 if (mode == CLEAR_INOBJECT_PROPERTIES) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00009251 new_instance_size -= map->GetInObjectProperties() * kPointerSize;
Kristian Monsen80d68ea2010-09-08 11:05:35 +01009252 }
9253
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009254 Handle<Map> result = RawCopy(map, new_instance_size);
Kristian Monsen80d68ea2010-09-08 11:05:35 +01009255
9256 if (mode != CLEAR_INOBJECT_PROPERTIES) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00009257 result->SetInObjectProperties(map->GetInObjectProperties());
Kristian Monsen80d68ea2010-09-08 11:05:35 +01009258 }
9259
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009260 result->set_dictionary_map(true);
9261 result->set_migration_target(false);
Ben Murdoch097c5b22016-05-18 11:27:45 +01009262 result->set_construction_counter(kNoSlackTracking);
Kristian Monsen80d68ea2010-09-08 11:05:35 +01009263
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009264#ifdef VERIFY_HEAP
9265 if (FLAG_verify_heap) result->DictionaryMapVerify();
Kristian Monsen80d68ea2010-09-08 11:05:35 +01009266#endif
9267
9268 return result;
9269}
9270
9271
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00009272Handle<Map> Map::CopyInitialMap(Handle<Map> map, int instance_size,
9273 int in_object_properties,
9274 int unused_property_fields) {
9275#ifdef DEBUG
9276 Isolate* isolate = map->GetIsolate();
9277 // Strict and strong function maps have Function as a constructor but the
9278 // Function's initial map is a sloppy function map. Same holds for
9279 // GeneratorFunction and its initial map.
9280 Object* constructor = map->GetConstructor();
9281 DCHECK(constructor->IsJSFunction());
9282 DCHECK(*map == JSFunction::cast(constructor)->initial_map() ||
9283 *map == *isolate->strict_function_map() ||
9284 *map == *isolate->strong_function_map() ||
9285 *map == *isolate->strict_generator_function_map() ||
9286 *map == *isolate->strong_generator_function_map());
9287#endif
9288 // Initial maps must always own their descriptors and it's descriptor array
9289 // does not contain descriptors that do not belong to the map.
9290 DCHECK(map->owns_descriptors());
9291 DCHECK_EQ(map->NumberOfOwnDescriptors(),
9292 map->instance_descriptors()->number_of_descriptors());
9293
9294 Handle<Map> result = RawCopy(map, instance_size);
9295
9296 // Please note instance_type and instance_size are set when allocated.
9297 result->SetInObjectProperties(in_object_properties);
9298 result->set_unused_property_fields(unused_property_fields);
9299
9300 int number_of_own_descriptors = map->NumberOfOwnDescriptors();
9301 if (number_of_own_descriptors > 0) {
9302 // The copy will use the same descriptors array.
9303 result->UpdateDescriptors(map->instance_descriptors(),
9304 map->GetLayoutDescriptor());
9305 result->SetNumberOfOwnDescriptors(number_of_own_descriptors);
9306
9307 DCHECK_EQ(result->NumberOfFields(),
9308 in_object_properties - unused_property_fields);
9309 }
9310
9311 return result;
9312}
9313
9314
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009315Handle<Map> Map::CopyDropDescriptors(Handle<Map> map) {
9316 Handle<Map> result = RawCopy(map, map->instance_size());
9317
9318 // Please note instance_type and instance_size are set when allocated.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00009319 if (map->IsJSObjectMap()) {
9320 result->SetInObjectProperties(map->GetInObjectProperties());
9321 result->set_unused_property_fields(map->unused_property_fields());
9322 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009323 result->ClearCodeCache(map->GetHeap());
9324 map->NotifyLeafMapLayoutChange();
9325 return result;
9326}
9327
9328
9329Handle<Map> Map::ShareDescriptor(Handle<Map> map,
9330 Handle<DescriptorArray> descriptors,
9331 Descriptor* descriptor) {
9332 // Sanity check. This path is only to be taken if the map owns its descriptor
9333 // array, implying that its NumberOfOwnDescriptors equals the number of
9334 // descriptors in the descriptor array.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00009335 DCHECK_EQ(map->NumberOfOwnDescriptors(),
9336 map->instance_descriptors()->number_of_descriptors());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009337
9338 Handle<Map> result = CopyDropDescriptors(map);
9339 Handle<Name> name = descriptor->GetKey();
9340
9341 // Ensure there's space for the new descriptor in the shared descriptor array.
9342 if (descriptors->NumberOfSlackDescriptors() == 0) {
9343 int old_size = descriptors->number_of_descriptors();
9344 if (old_size == 0) {
9345 descriptors = DescriptorArray::Allocate(map->GetIsolate(), 0, 1);
9346 } else {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00009347 int slack = SlackForArraySize(old_size, kMaxNumberOfDescriptors);
9348 EnsureDescriptorSlack(map, slack);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009349 descriptors = handle(map->instance_descriptors());
9350 }
John Reck59135872010-11-02 12:39:01 -07009351 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009352
Emily Bernierd0a1eb72015-03-24 16:35:39 -04009353 Handle<LayoutDescriptor> layout_descriptor =
9354 FLAG_unbox_double_fields
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00009355 ? LayoutDescriptor::ShareAppend(map, descriptor->GetDetails())
Emily Bernierd0a1eb72015-03-24 16:35:39 -04009356 : handle(LayoutDescriptor::FastPointerLayout(), map->GetIsolate());
9357
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009358 {
9359 DisallowHeapAllocation no_gc;
9360 descriptors->Append(descriptor);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04009361 result->InitializeDescriptors(*descriptors, *layout_descriptor);
John Reck59135872010-11-02 12:39:01 -07009362 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009363
9364 DCHECK(result->NumberOfOwnDescriptors() == map->NumberOfOwnDescriptors() + 1);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04009365 ConnectTransition(map, result, name, SIMPLE_PROPERTY_TRANSITION);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009366
9367 return result;
9368}
9369
9370
Emily Bernierd0a1eb72015-03-24 16:35:39 -04009371#if TRACE_MAPS
9372
9373// static
9374void Map::TraceTransition(const char* what, Map* from, Map* to, Name* name) {
9375 if (FLAG_trace_maps) {
9376 PrintF("[TraceMaps: %s from= %p to= %p name= ", what,
9377 reinterpret_cast<void*>(from), reinterpret_cast<void*>(to));
9378 name->NameShortPrint();
9379 PrintF(" ]\n");
9380 }
9381}
9382
9383
9384// static
9385void Map::TraceAllTransitions(Map* map) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00009386 Object* transitions = map->raw_transitions();
9387 int num_transitions = TransitionArray::NumberOfTransitions(transitions);
9388 for (int i = -0; i < num_transitions; ++i) {
9389 Map* target = TransitionArray::GetTarget(transitions, i);
9390 Name* key = TransitionArray::GetKey(transitions, i);
9391 Map::TraceTransition("Transition", map, target, key);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04009392 Map::TraceAllTransitions(target);
9393 }
9394}
9395
9396#endif // TRACE_MAPS
9397
9398
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009399void Map::ConnectTransition(Handle<Map> parent, Handle<Map> child,
9400 Handle<Name> name, SimpleTransitionFlag flag) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00009401 if (!parent->GetBackPointer()->IsUndefined()) {
9402 parent->set_owns_descriptors(false);
9403 } else {
9404 // |parent| is initial map and it must keep the ownership, there must be no
9405 // descriptors in the descriptors array that do not belong to the map.
9406 DCHECK(parent->owns_descriptors());
9407 DCHECK_EQ(parent->NumberOfOwnDescriptors(),
9408 parent->instance_descriptors()->number_of_descriptors());
9409 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009410 if (parent->is_prototype_map()) {
9411 DCHECK(child->is_prototype_map());
Emily Bernierd0a1eb72015-03-24 16:35:39 -04009412#if TRACE_MAPS
9413 Map::TraceTransition("NoTransition", *parent, *child, *name);
9414#endif
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009415 } else {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00009416 TransitionArray::Insert(parent, name, child, flag);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04009417#if TRACE_MAPS
9418 Map::TraceTransition("Transition", *parent, *child, *name);
9419#endif
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009420 }
9421}
9422
9423
Emily Bernierd0a1eb72015-03-24 16:35:39 -04009424Handle<Map> Map::CopyReplaceDescriptors(
9425 Handle<Map> map, Handle<DescriptorArray> descriptors,
9426 Handle<LayoutDescriptor> layout_descriptor, TransitionFlag flag,
9427 MaybeHandle<Name> maybe_name, const char* reason,
9428 SimpleTransitionFlag simple_flag) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009429 DCHECK(descriptors->IsSortedNoDuplicates());
9430
9431 Handle<Map> result = CopyDropDescriptors(map);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009432
9433 if (!map->is_prototype_map()) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00009434 if (flag == INSERT_TRANSITION &&
9435 TransitionArray::CanHaveMoreTransitions(map)) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -04009436 result->InitializeDescriptors(*descriptors, *layout_descriptor);
9437
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009438 Handle<Name> name;
9439 CHECK(maybe_name.ToHandle(&name));
9440 ConnectTransition(map, result, name, simple_flag);
9441 } else {
9442 int length = descriptors->number_of_descriptors();
9443 for (int i = 0; i < length; i++) {
9444 descriptors->SetRepresentation(i, Representation::Tagged());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00009445 if (descriptors->GetDetails(i).type() == DATA) {
Ben Murdoch097c5b22016-05-18 11:27:45 +01009446 descriptors->SetValue(i, FieldType::Any());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009447 }
9448 }
Emily Bernierd0a1eb72015-03-24 16:35:39 -04009449 result->InitializeDescriptors(*descriptors,
9450 LayoutDescriptor::FastPointerLayout());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009451 }
Emily Bernierd0a1eb72015-03-24 16:35:39 -04009452 } else {
9453 result->InitializeDescriptors(*descriptors, *layout_descriptor);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009454 }
Emily Bernierd0a1eb72015-03-24 16:35:39 -04009455#if TRACE_MAPS
9456 if (FLAG_trace_maps &&
9457 // Mirror conditions above that did not call ConnectTransition().
9458 (map->is_prototype_map() ||
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00009459 !(flag == INSERT_TRANSITION &&
9460 TransitionArray::CanHaveMoreTransitions(map)))) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -04009461 PrintF("[TraceMaps: ReplaceDescriptors from= %p to= %p reason= %s ]\n",
9462 reinterpret_cast<void*>(*map), reinterpret_cast<void*>(*result),
9463 reason);
9464 }
9465#endif
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009466
9467 return result;
9468}
9469
9470
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00009471// Creates transition tree starting from |split_map| and adding all descriptors
9472// starting from descriptor with index |split_map|.NumberOfOwnDescriptors().
9473// The way how it is done is tricky because of GC and special descriptors
9474// marking logic.
9475Handle<Map> Map::AddMissingTransitions(
9476 Handle<Map> split_map, Handle<DescriptorArray> descriptors,
Emily Bernierd0a1eb72015-03-24 16:35:39 -04009477 Handle<LayoutDescriptor> full_layout_descriptor) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009478 DCHECK(descriptors->IsSortedNoDuplicates());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00009479 int split_nof = split_map->NumberOfOwnDescriptors();
9480 int nof_descriptors = descriptors->number_of_descriptors();
9481 DCHECK_LT(split_nof, nof_descriptors);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009482
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00009483 // Start with creating last map which will own full descriptors array.
9484 // This is necessary to guarantee that GC will mark the whole descriptor
9485 // array if any of the allocations happening below fail.
9486 // Number of unused properties is temporarily incorrect and the layout
9487 // descriptor could unnecessarily be in slow mode but we will fix after
9488 // all the other intermediate maps are created.
9489 Handle<Map> last_map = CopyDropDescriptors(split_map);
9490 last_map->InitializeDescriptors(*descriptors, *full_layout_descriptor);
9491 last_map->set_unused_property_fields(0);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009492
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00009493 // During creation of intermediate maps we violate descriptors sharing
9494 // invariant since the last map is not yet connected to the transition tree
9495 // we create here. But it is safe because GC never trims map's descriptors
9496 // if there are no dead transitions from that map and this is exactly the
9497 // case for all the intermediate maps we create here.
9498 Handle<Map> map = split_map;
9499 for (int i = split_nof; i < nof_descriptors - 1; ++i) {
9500 Handle<Map> new_map = CopyDropDescriptors(map);
9501 InstallDescriptors(map, new_map, i, descriptors, full_layout_descriptor);
9502 map = new_map;
9503 }
9504 map->NotifyLeafMapLayoutChange();
9505 InstallDescriptors(map, last_map, nof_descriptors - 1, descriptors,
9506 full_layout_descriptor);
9507 return last_map;
9508}
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009509
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00009510
9511// Since this method is used to rewrite an existing transition tree, it can
9512// always insert transitions without checking.
9513void Map::InstallDescriptors(Handle<Map> parent, Handle<Map> child,
9514 int new_descriptor,
9515 Handle<DescriptorArray> descriptors,
9516 Handle<LayoutDescriptor> full_layout_descriptor) {
9517 DCHECK(descriptors->IsSortedNoDuplicates());
9518
9519 child->set_instance_descriptors(*descriptors);
9520 child->SetNumberOfOwnDescriptors(new_descriptor + 1);
9521
9522 int unused_property_fields = parent->unused_property_fields();
Emily Bernierd0a1eb72015-03-24 16:35:39 -04009523 PropertyDetails details = descriptors->GetDetails(new_descriptor);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00009524 if (details.location() == kField) {
9525 unused_property_fields = parent->unused_property_fields() - 1;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009526 if (unused_property_fields < 0) {
9527 unused_property_fields += JSObject::kFieldsAdded;
9528 }
9529 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00009530 child->set_unused_property_fields(unused_property_fields);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009531
Emily Bernierd0a1eb72015-03-24 16:35:39 -04009532 if (FLAG_unbox_double_fields) {
9533 Handle<LayoutDescriptor> layout_descriptor =
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00009534 LayoutDescriptor::AppendIfFastOrUseFull(parent, details,
Emily Bernierd0a1eb72015-03-24 16:35:39 -04009535 full_layout_descriptor);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00009536 child->set_layout_descriptor(*layout_descriptor);
9537#ifdef VERIFY_HEAP
9538 // TODO(ishell): remove these checks from VERIFY_HEAP mode.
9539 if (FLAG_verify_heap) {
9540 CHECK(child->layout_descriptor()->IsConsistentWithMap(*child));
9541 }
9542#else
9543 SLOW_DCHECK(child->layout_descriptor()->IsConsistentWithMap(*child));
9544#endif
9545 child->set_visitor_id(Heap::GetStaticVisitorIdForMap(*child));
Emily Bernierd0a1eb72015-03-24 16:35:39 -04009546 }
9547
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009548 Handle<Name> name = handle(descriptors->GetKey(new_descriptor));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00009549 ConnectTransition(parent, child, name, SIMPLE_PROPERTY_TRANSITION);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009550}
9551
9552
9553Handle<Map> Map::CopyAsElementsKind(Handle<Map> map, ElementsKind kind,
9554 TransitionFlag flag) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00009555 Map* maybe_elements_transition_map = NULL;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009556 if (flag == INSERT_TRANSITION) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00009557 maybe_elements_transition_map = map->ElementsTransitionMap();
9558 DCHECK(maybe_elements_transition_map == NULL ||
9559 (maybe_elements_transition_map->elements_kind() ==
9560 DICTIONARY_ELEMENTS &&
9561 kind == DICTIONARY_ELEMENTS));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009562 DCHECK(!IsFastElementsKind(kind) ||
9563 IsMoreGeneralElementsKindTransition(map->elements_kind(), kind));
9564 DCHECK(kind != map->elements_kind());
9565 }
9566
Emily Bernierd0a1eb72015-03-24 16:35:39 -04009567 bool insert_transition = flag == INSERT_TRANSITION &&
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00009568 TransitionArray::CanHaveMoreTransitions(map) &&
9569 maybe_elements_transition_map == NULL;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009570
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00009571 if (insert_transition) {
9572 Handle<Map> new_map = CopyForTransition(map, "CopyAsElementsKind");
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009573 new_map->set_elements_kind(kind);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00009574
9575 Isolate* isolate = map->GetIsolate();
9576 Handle<Name> name = isolate->factory()->elements_transition_symbol();
9577 ConnectTransition(map, new_map, name, SPECIAL_TRANSITION);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009578 return new_map;
9579 }
9580
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009581 // Create a new free-floating map only if we are not allowed to store it.
Emily Bernierd0a1eb72015-03-24 16:35:39 -04009582 Handle<Map> new_map = Copy(map, "CopyAsElementsKind");
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009583 new_map->set_elements_kind(kind);
Steve Block8defd9f2010-07-08 12:39:36 +01009584 return new_map;
Steve Blocka7e24c12009-10-30 11:49:00 +00009585}
9586
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009587
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00009588Handle<Map> Map::AsLanguageMode(Handle<Map> initial_map,
9589 LanguageMode language_mode, FunctionKind kind) {
9590 DCHECK_EQ(JS_FUNCTION_TYPE, initial_map->instance_type());
9591 // Initial map for sloppy mode function is stored in the function
9592 // constructor. Initial maps for strict and strong modes are cached as
9593 // special transitions using |strict_function_transition_symbol| and
9594 // |strong_function_transition_symbol| respectively as a key.
9595 if (language_mode == SLOPPY) return initial_map;
9596 Isolate* isolate = initial_map->GetIsolate();
9597 Factory* factory = isolate->factory();
9598 Handle<Symbol> transition_symbol;
9599
9600 int map_index = Context::FunctionMapIndex(language_mode, kind);
9601 Handle<Map> function_map(
9602 Map::cast(isolate->native_context()->get(map_index)));
9603
9604 STATIC_ASSERT(LANGUAGE_END == 3);
9605 switch (language_mode) {
9606 case STRICT:
9607 transition_symbol = factory->strict_function_transition_symbol();
9608 break;
9609 case STRONG:
9610 transition_symbol = factory->strong_function_transition_symbol();
9611 break;
9612 default:
9613 UNREACHABLE();
9614 break;
9615 }
9616 Map* maybe_transition =
9617 TransitionArray::SearchSpecial(*initial_map, *transition_symbol);
9618 if (maybe_transition != NULL) {
9619 return handle(maybe_transition, isolate);
9620 }
9621 initial_map->NotifyLeafMapLayoutChange();
9622
9623 // Create new map taking descriptors from the |function_map| and all
9624 // the other details from the |initial_map|.
9625 Handle<Map> map =
9626 Map::CopyInitialMap(function_map, initial_map->instance_size(),
9627 initial_map->GetInObjectProperties(),
9628 initial_map->unused_property_fields());
9629 map->SetConstructor(initial_map->GetConstructor());
9630 map->set_prototype(initial_map->prototype());
9631
9632 if (TransitionArray::CanHaveMoreTransitions(initial_map)) {
9633 Map::ConnectTransition(initial_map, map, transition_symbol,
9634 SPECIAL_TRANSITION);
9635 }
9636 return map;
9637}
9638
9639
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009640Handle<Map> Map::CopyForObserved(Handle<Map> map) {
9641 DCHECK(!map->is_observed());
9642
Ben Murdoch3ef787d2012-04-12 10:51:47 +01009643 Isolate* isolate = map->GetIsolate();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009644
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00009645 bool insert_transition =
9646 TransitionArray::CanHaveMoreTransitions(map) && !map->is_prototype_map();
9647
9648 if (insert_transition) {
9649 Handle<Map> new_map = CopyForTransition(map, "CopyForObserved");
9650 new_map->set_is_observed();
9651
9652 Handle<Name> name = isolate->factory()->observed_symbol();
9653 ConnectTransition(map, new_map, name, SPECIAL_TRANSITION);
9654 return new_map;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009655 }
9656
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00009657 // Create a new free-floating map only if we are not allowed to store it.
9658 Handle<Map> new_map = Map::Copy(map, "CopyForObserved");
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009659 new_map->set_is_observed();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00009660 return new_map;
9661}
9662
9663
9664Handle<Map> Map::CopyForTransition(Handle<Map> map, const char* reason) {
9665 DCHECK(!map->is_prototype_map());
9666 Handle<Map> new_map = CopyDropDescriptors(map);
9667
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009668 if (map->owns_descriptors()) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00009669 // In case the map owned its own descriptors, share the descriptors and
9670 // transfer ownership to the new map.
Emily Bernierd0a1eb72015-03-24 16:35:39 -04009671 // The properties did not change, so reuse descriptors.
9672 new_map->InitializeDescriptors(map->instance_descriptors(),
9673 map->GetLayoutDescriptor());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00009674 } else {
9675 // In case the map did not own its own descriptors, a split is forced by
9676 // copying the map; creating a new descriptor array cell.
9677 Handle<DescriptorArray> descriptors(map->instance_descriptors());
9678 int number_of_own_descriptors = map->NumberOfOwnDescriptors();
9679 Handle<DescriptorArray> new_descriptors =
9680 DescriptorArray::CopyUpTo(descriptors, number_of_own_descriptors);
9681 Handle<LayoutDescriptor> new_layout_descriptor(map->GetLayoutDescriptor(),
9682 map->GetIsolate());
9683 new_map->InitializeDescriptors(*new_descriptors, *new_layout_descriptor);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009684 }
9685
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00009686#if TRACE_MAPS
9687 if (FLAG_trace_maps) {
9688 PrintF("[TraceMaps: CopyForTransition from= %p to= %p reason= %s ]\n",
9689 reinterpret_cast<void*>(*map), reinterpret_cast<void*>(*new_map),
9690 reason);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04009691 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00009692#endif
9693
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009694 return new_map;
Ben Murdoch3ef787d2012-04-12 10:51:47 +01009695}
Steve Blocka7e24c12009-10-30 11:49:00 +00009696
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009697
Emily Bernierd0a1eb72015-03-24 16:35:39 -04009698Handle<Map> Map::Copy(Handle<Map> map, const char* reason) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009699 Handle<DescriptorArray> descriptors(map->instance_descriptors());
9700 int number_of_own_descriptors = map->NumberOfOwnDescriptors();
9701 Handle<DescriptorArray> new_descriptors =
9702 DescriptorArray::CopyUpTo(descriptors, number_of_own_descriptors);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04009703 Handle<LayoutDescriptor> new_layout_descriptor(map->GetLayoutDescriptor(),
9704 map->GetIsolate());
9705 return CopyReplaceDescriptors(map, new_descriptors, new_layout_descriptor,
9706 OMIT_TRANSITION, MaybeHandle<Name>(), reason,
9707 SPECIAL_TRANSITION);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009708}
9709
9710
9711Handle<Map> Map::Create(Isolate* isolate, int inobject_properties) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -04009712 Handle<Map> copy =
9713 Copy(handle(isolate->object_function()->initial_map()), "MapCreate");
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009714
9715 // Check that we do not overflow the instance size when adding the extra
9716 // inobject properties. If the instance size overflows, we allocate as many
9717 // properties as we can as inobject properties.
9718 int max_extra_properties =
9719 (JSObject::kMaxInstanceSize - JSObject::kHeaderSize) >> kPointerSizeLog2;
9720
9721 if (inobject_properties > max_extra_properties) {
9722 inobject_properties = max_extra_properties;
9723 }
9724
9725 int new_instance_size =
9726 JSObject::kHeaderSize + kPointerSize * inobject_properties;
9727
9728 // Adjust the map with the extra inobject properties.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00009729 copy->SetInObjectProperties(inobject_properties);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009730 copy->set_unused_property_fields(inobject_properties);
9731 copy->set_instance_size(new_instance_size);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00009732 copy->set_visitor_id(Heap::GetStaticVisitorIdForMap(*copy));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009733 return copy;
9734}
9735
9736
Emily Bernierd0a1eb72015-03-24 16:35:39 -04009737Handle<Map> Map::CopyForPreventExtensions(Handle<Map> map,
9738 PropertyAttributes attrs_to_add,
9739 Handle<Symbol> transition_marker,
9740 const char* reason) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009741 int num_descriptors = map->NumberOfOwnDescriptors();
9742 Isolate* isolate = map->GetIsolate();
9743 Handle<DescriptorArray> new_desc = DescriptorArray::CopyUpToAddAttributes(
Emily Bernierd0a1eb72015-03-24 16:35:39 -04009744 handle(map->instance_descriptors(), isolate), num_descriptors,
9745 attrs_to_add);
9746 Handle<LayoutDescriptor> new_layout_descriptor(map->GetLayoutDescriptor(),
9747 isolate);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009748 Handle<Map> new_map = CopyReplaceDescriptors(
Emily Bernierd0a1eb72015-03-24 16:35:39 -04009749 map, new_desc, new_layout_descriptor, INSERT_TRANSITION,
9750 transition_marker, reason, SPECIAL_TRANSITION);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009751 new_map->set_is_extensible(false);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00009752 if (!IsFixedTypedArrayElementsKind(map->elements_kind())) {
Ben Murdoch097c5b22016-05-18 11:27:45 +01009753 ElementsKind new_kind = IsStringWrapperElementsKind(map->elements_kind())
9754 ? SLOW_STRING_WRAPPER_ELEMENTS
9755 : DICTIONARY_ELEMENTS;
9756 new_map->set_elements_kind(new_kind);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00009757 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009758 return new_map;
9759}
9760
Ben Murdoch097c5b22016-05-18 11:27:45 +01009761FieldType* DescriptorArray::GetFieldType(int descriptor_number) {
9762 DCHECK(GetDetails(descriptor_number).location() == kField);
9763 Object* value = GetValue(descriptor_number);
9764 if (value->IsWeakCell()) {
9765 if (WeakCell::cast(value)->cleared()) return FieldType::None();
9766 value = WeakCell::cast(value)->value();
9767 }
9768 return FieldType::cast(value);
9769}
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009770
Ben Murdoch097c5b22016-05-18 11:27:45 +01009771namespace {
9772
9773bool CanHoldValue(DescriptorArray* descriptors, int descriptor, Object* value) {
9774 PropertyDetails details = descriptors->GetDetails(descriptor);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009775 switch (details.type()) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00009776 case DATA:
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009777 return value->FitsRepresentation(details.representation()) &&
Ben Murdoch097c5b22016-05-18 11:27:45 +01009778 descriptors->GetFieldType(descriptor)->NowContains(value);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009779
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00009780 case DATA_CONSTANT:
Ben Murdoch097c5b22016-05-18 11:27:45 +01009781 DCHECK(descriptors->GetConstant(descriptor) != value ||
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009782 value->FitsRepresentation(details.representation()));
Ben Murdoch097c5b22016-05-18 11:27:45 +01009783 return descriptors->GetConstant(descriptor) == value;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009784
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00009785 case ACCESSOR:
9786 case ACCESSOR_CONSTANT:
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009787 return false;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009788 }
9789
9790 UNREACHABLE();
9791 return false;
9792}
9793
Ben Murdoch097c5b22016-05-18 11:27:45 +01009794Handle<Map> UpdateDescriptorForValue(Handle<Map> map, int descriptor,
9795 Handle<Object> value) {
9796 if (CanHoldValue(map->instance_descriptors(), descriptor, *value)) return map;
9797
9798 Isolate* isolate = map->GetIsolate();
9799 PropertyAttributes attributes =
9800 map->instance_descriptors()->GetDetails(descriptor).attributes();
9801 Representation representation = value->OptimalRepresentation();
9802 Handle<FieldType> type = value->OptimalType(isolate, representation);
9803
9804 return Map::ReconfigureProperty(map, descriptor, kData, attributes,
9805 representation, type, FORCE_FIELD);
9806}
9807
9808} // namespace
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009809
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00009810// static
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009811Handle<Map> Map::PrepareForDataProperty(Handle<Map> map, int descriptor,
9812 Handle<Object> value) {
9813 // Dictionaries can store any property value.
Ben Murdoch097c5b22016-05-18 11:27:45 +01009814 DCHECK(!map->is_dictionary_map());
9815 // Update to the newest map before storing the property.
9816 return UpdateDescriptorForValue(Update(map), descriptor, value);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009817}
9818
9819
9820Handle<Map> Map::TransitionToDataProperty(Handle<Map> map, Handle<Name> name,
9821 Handle<Object> value,
9822 PropertyAttributes attributes,
9823 StoreFromKeyed store_mode) {
Ben Murdoch097c5b22016-05-18 11:27:45 +01009824 DCHECK(name->IsUniqueName());
9825 DCHECK(!map->is_dictionary_map());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009826
9827 // Migrate to the newest map before storing the property.
9828 map = Update(map);
9829
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00009830 Map* maybe_transition =
9831 TransitionArray::SearchTransition(*map, kData, *name, attributes);
9832 if (maybe_transition != NULL) {
9833 Handle<Map> transition(maybe_transition);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009834 int descriptor = transition->LastAdded();
9835
Emily Bernierd0a1eb72015-03-24 16:35:39 -04009836 DCHECK_EQ(attributes, transition->instance_descriptors()
9837 ->GetDetails(descriptor)
9838 .attributes());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009839
Ben Murdoch097c5b22016-05-18 11:27:45 +01009840 return UpdateDescriptorForValue(transition, descriptor, value);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009841 }
9842
9843 TransitionFlag flag = INSERT_TRANSITION;
9844 MaybeHandle<Map> maybe_map;
9845 if (value->IsJSFunction()) {
9846 maybe_map = Map::CopyWithConstant(map, name, value, attributes, flag);
9847 } else if (!map->TooManyFastProperties(store_mode)) {
9848 Isolate* isolate = name->GetIsolate();
9849 Representation representation = value->OptimalRepresentation();
Ben Murdoch097c5b22016-05-18 11:27:45 +01009850 Handle<FieldType> type = value->OptimalType(isolate, representation);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009851 maybe_map =
9852 Map::CopyWithField(map, name, type, attributes, representation, flag);
9853 }
9854
9855 Handle<Map> result;
9856 if (!maybe_map.ToHandle(&result)) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -04009857#if TRACE_MAPS
9858 if (FLAG_trace_maps) {
9859 Vector<char> name_buffer = Vector<char>::New(100);
9860 name->NameShortPrint(name_buffer);
9861 Vector<char> buffer = Vector<char>::New(128);
9862 SNPrintF(buffer, "TooManyFastProperties %s", name_buffer.start());
9863 return Map::Normalize(map, CLEAR_INOBJECT_PROPERTIES, buffer.start());
9864 }
9865#endif
9866 return Map::Normalize(map, CLEAR_INOBJECT_PROPERTIES,
9867 "TooManyFastProperties");
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009868 }
9869
9870 return result;
9871}
9872
9873
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00009874Handle<Map> Map::ReconfigureExistingProperty(Handle<Map> map, int descriptor,
9875 PropertyKind kind,
9876 PropertyAttributes attributes) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009877 // Dictionaries have to be reconfigured in-place.
9878 DCHECK(!map->is_dictionary_map());
9879
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00009880 if (!map->GetBackPointer()->IsMap()) {
9881 // There is no benefit from reconstructing transition tree for maps without
9882 // back pointers.
9883 return CopyGeneralizeAllRepresentations(
9884 map, descriptor, FORCE_FIELD, kind, attributes,
9885 "GenAll_AttributesMismatchProtoMap");
9886 }
9887
9888 if (FLAG_trace_generalization) {
9889 map->PrintReconfiguration(stdout, descriptor, kind, attributes);
9890 }
9891
9892 Isolate* isolate = map->GetIsolate();
9893 Handle<Map> new_map = ReconfigureProperty(
9894 map, descriptor, kind, attributes, Representation::None(),
Ben Murdoch097c5b22016-05-18 11:27:45 +01009895 FieldType::None(isolate), FORCE_FIELD);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00009896 return new_map;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009897}
9898
9899
9900Handle<Map> Map::TransitionToAccessorProperty(Handle<Map> map,
9901 Handle<Name> name,
9902 AccessorComponent component,
9903 Handle<Object> accessor,
9904 PropertyAttributes attributes) {
Ben Murdoch097c5b22016-05-18 11:27:45 +01009905 DCHECK(name->IsUniqueName());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009906 Isolate* isolate = name->GetIsolate();
9907
9908 // Dictionary maps can always have additional data properties.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00009909 if (map->is_dictionary_map()) return map;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009910
9911 // Migrate to the newest map before transitioning to the new property.
9912 map = Update(map);
9913
9914 PropertyNormalizationMode mode = map->is_prototype_map()
9915 ? KEEP_INOBJECT_PROPERTIES
9916 : CLEAR_INOBJECT_PROPERTIES;
9917
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00009918 Map* maybe_transition =
9919 TransitionArray::SearchTransition(*map, kAccessor, *name, attributes);
9920 if (maybe_transition != NULL) {
9921 Handle<Map> transition(maybe_transition, isolate);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009922 DescriptorArray* descriptors = transition->instance_descriptors();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009923 int descriptor = transition->LastAdded();
Emily Bernierd0a1eb72015-03-24 16:35:39 -04009924 DCHECK(descriptors->GetKey(descriptor)->Equals(*name));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009925
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00009926 DCHECK_EQ(kAccessor, descriptors->GetDetails(descriptor).kind());
Emily Bernierd0a1eb72015-03-24 16:35:39 -04009927 DCHECK_EQ(attributes, descriptors->GetDetails(descriptor).attributes());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009928
9929 Handle<Object> maybe_pair(descriptors->GetValue(descriptor), isolate);
9930 if (!maybe_pair->IsAccessorPair()) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -04009931 return Map::Normalize(map, mode, "TransitionToAccessorFromNonPair");
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009932 }
9933
9934 Handle<AccessorPair> pair = Handle<AccessorPair>::cast(maybe_pair);
9935 if (pair->get(component) != *accessor) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -04009936 return Map::Normalize(map, mode, "TransitionToDifferentAccessor");
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009937 }
9938
9939 return transition;
9940 }
9941
9942 Handle<AccessorPair> pair;
9943 DescriptorArray* old_descriptors = map->instance_descriptors();
Ben Murdoch097c5b22016-05-18 11:27:45 +01009944 int descriptor = old_descriptors->SearchWithCache(isolate, *name, *map);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009945 if (descriptor != DescriptorArray::kNotFound) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -04009946 if (descriptor != map->LastAdded()) {
9947 return Map::Normalize(map, mode, "AccessorsOverwritingNonLast");
9948 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009949 PropertyDetails old_details = old_descriptors->GetDetails(descriptor);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00009950 if (old_details.type() != ACCESSOR_CONSTANT) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -04009951 return Map::Normalize(map, mode, "AccessorsOverwritingNonAccessors");
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009952 }
9953
9954 if (old_details.attributes() != attributes) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -04009955 return Map::Normalize(map, mode, "AccessorsWithAttributes");
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009956 }
9957
9958 Handle<Object> maybe_pair(old_descriptors->GetValue(descriptor), isolate);
9959 if (!maybe_pair->IsAccessorPair()) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -04009960 return Map::Normalize(map, mode, "AccessorsOverwritingNonPair");
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009961 }
9962
9963 Object* current = Handle<AccessorPair>::cast(maybe_pair)->get(component);
9964 if (current == *accessor) return map;
9965
9966 if (!current->IsTheHole()) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -04009967 return Map::Normalize(map, mode, "AccessorsOverwritingAccessors");
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009968 }
9969
9970 pair = AccessorPair::Copy(Handle<AccessorPair>::cast(maybe_pair));
9971 } else if (map->NumberOfOwnDescriptors() >= kMaxNumberOfDescriptors ||
9972 map->TooManyFastProperties(CERTAINLY_NOT_STORE_FROM_KEYED)) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -04009973 return Map::Normalize(map, CLEAR_INOBJECT_PROPERTIES, "TooManyAccessors");
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009974 } else {
9975 pair = isolate->factory()->NewAccessorPair();
9976 }
9977
9978 pair->set(component, *accessor);
9979 TransitionFlag flag = INSERT_TRANSITION;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00009980 AccessorConstantDescriptor new_desc(name, pair, attributes);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009981 return Map::CopyInsertDescriptor(map, &new_desc, flag);
9982}
9983
9984
9985Handle<Map> Map::CopyAddDescriptor(Handle<Map> map,
9986 Descriptor* descriptor,
9987 TransitionFlag flag) {
9988 Handle<DescriptorArray> descriptors(map->instance_descriptors());
9989
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00009990 // Share descriptors only if map owns descriptors and it not an initial map.
9991 if (flag == INSERT_TRANSITION && map->owns_descriptors() &&
9992 !map->GetBackPointer()->IsUndefined() &&
9993 TransitionArray::CanHaveMoreTransitions(map)) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009994 return ShareDescriptor(map, descriptors, descriptor);
9995 }
9996
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00009997 int nof = map->NumberOfOwnDescriptors();
9998 Handle<DescriptorArray> new_descriptors =
9999 DescriptorArray::CopyUpTo(descriptors, nof, 1);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010000 new_descriptors->Append(descriptor);
10001
Emily Bernierd0a1eb72015-03-24 16:35:39 -040010002 Handle<LayoutDescriptor> new_layout_descriptor =
10003 FLAG_unbox_double_fields
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000010004 ? LayoutDescriptor::New(map, new_descriptors, nof + 1)
Emily Bernierd0a1eb72015-03-24 16:35:39 -040010005 : handle(LayoutDescriptor::FastPointerLayout(), map->GetIsolate());
10006
10007 return CopyReplaceDescriptors(map, new_descriptors, new_layout_descriptor,
10008 flag, descriptor->GetKey(), "CopyAddDescriptor",
10009 SIMPLE_PROPERTY_TRANSITION);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010010}
10011
10012
10013Handle<Map> Map::CopyInsertDescriptor(Handle<Map> map,
10014 Descriptor* descriptor,
10015 TransitionFlag flag) {
10016 Handle<DescriptorArray> old_descriptors(map->instance_descriptors());
10017
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010018 // We replace the key if it is already present.
Ben Murdoch097c5b22016-05-18 11:27:45 +010010019 int index = old_descriptors->SearchWithCache(map->GetIsolate(),
10020 *descriptor->GetKey(), *map);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010021 if (index != DescriptorArray::kNotFound) {
10022 return CopyReplaceDescriptor(map, old_descriptors, descriptor, index, flag);
10023 }
10024 return CopyAddDescriptor(map, descriptor, flag);
10025}
10026
10027
10028Handle<DescriptorArray> DescriptorArray::CopyUpTo(
10029 Handle<DescriptorArray> desc,
10030 int enumeration_index,
10031 int slack) {
10032 return DescriptorArray::CopyUpToAddAttributes(
10033 desc, enumeration_index, NONE, slack);
10034}
10035
10036
10037Handle<DescriptorArray> DescriptorArray::CopyUpToAddAttributes(
10038 Handle<DescriptorArray> desc,
10039 int enumeration_index,
10040 PropertyAttributes attributes,
10041 int slack) {
10042 if (enumeration_index + slack == 0) {
10043 return desc->GetIsolate()->factory()->empty_descriptor_array();
10044 }
10045
10046 int size = enumeration_index;
10047
10048 Handle<DescriptorArray> descriptors =
10049 DescriptorArray::Allocate(desc->GetIsolate(), size, slack);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010050
10051 if (attributes != NONE) {
10052 for (int i = 0; i < size; ++i) {
10053 Object* value = desc->GetValue(i);
10054 Name* key = desc->GetKey(i);
10055 PropertyDetails details = desc->GetDetails(i);
10056 // Bulk attribute changes never affect private properties.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000010057 if (!key->IsPrivate()) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010058 int mask = DONT_DELETE | DONT_ENUM;
10059 // READ_ONLY is an invalid attribute for JS setters/getters.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000010060 if (details.type() != ACCESSOR_CONSTANT || !value->IsAccessorPair()) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010061 mask |= READ_ONLY;
10062 }
10063 details = details.CopyAddAttributes(
10064 static_cast<PropertyAttributes>(attributes & mask));
10065 }
10066 Descriptor inner_desc(
10067 handle(key), handle(value, desc->GetIsolate()), details);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000010068 descriptors->SetDescriptor(i, &inner_desc);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010069 }
10070 } else {
10071 for (int i = 0; i < size; ++i) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000010072 descriptors->CopyFrom(i, *desc);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010073 }
10074 }
10075
10076 if (desc->number_of_descriptors() != enumeration_index) descriptors->Sort();
10077
10078 return descriptors;
10079}
10080
10081
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000010082bool DescriptorArray::IsEqualUpTo(DescriptorArray* desc, int nof_descriptors) {
10083 for (int i = 0; i < nof_descriptors; i++) {
10084 if (GetKey(i) != desc->GetKey(i) || GetValue(i) != desc->GetValue(i)) {
10085 return false;
10086 }
10087 PropertyDetails details = GetDetails(i);
10088 PropertyDetails other_details = desc->GetDetails(i);
10089 if (details.type() != other_details.type() ||
10090 !details.representation().Equals(other_details.representation())) {
10091 return false;
10092 }
10093 }
10094 return true;
10095}
10096
10097
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010098Handle<Map> Map::CopyReplaceDescriptor(Handle<Map> map,
10099 Handle<DescriptorArray> descriptors,
10100 Descriptor* descriptor,
10101 int insertion_index,
10102 TransitionFlag flag) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010103 Handle<Name> key = descriptor->GetKey();
10104 DCHECK(*key == descriptors->GetKey(insertion_index));
10105
10106 Handle<DescriptorArray> new_descriptors = DescriptorArray::CopyUpTo(
10107 descriptors, map->NumberOfOwnDescriptors());
10108
10109 new_descriptors->Replace(insertion_index, descriptor);
Emily Bernierd0a1eb72015-03-24 16:35:39 -040010110 Handle<LayoutDescriptor> new_layout_descriptor = LayoutDescriptor::New(
10111 map, new_descriptors, new_descriptors->number_of_descriptors());
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010112
10113 SimpleTransitionFlag simple_flag =
10114 (insertion_index == descriptors->number_of_descriptors() - 1)
Emily Bernierd0a1eb72015-03-24 16:35:39 -040010115 ? SIMPLE_PROPERTY_TRANSITION
10116 : PROPERTY_TRANSITION;
10117 return CopyReplaceDescriptors(map, new_descriptors, new_layout_descriptor,
10118 flag, key, "CopyReplaceDescriptor",
10119 simple_flag);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010120}
10121
10122
10123void Map::UpdateCodeCache(Handle<Map> map,
10124 Handle<Name> name,
10125 Handle<Code> code) {
10126 Isolate* isolate = map->GetIsolate();
10127 HandleScope scope(isolate);
10128 // Allocate the code cache if not present.
10129 if (map->code_cache()->IsFixedArray()) {
10130 Handle<Object> result = isolate->factory()->NewCodeCache();
10131 map->set_code_cache(*result);
Steve Block6ded16b2010-05-10 14:33:55 +010010132 }
Steve Blocka7e24c12009-10-30 11:49:00 +000010133
Steve Block6ded16b2010-05-10 14:33:55 +010010134 // Update the code cache.
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010135 Handle<CodeCache> code_cache(CodeCache::cast(map->code_cache()), isolate);
10136 CodeCache::Update(code_cache, name, code);
Steve Block6ded16b2010-05-10 14:33:55 +010010137}
10138
10139
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010140Object* Map::FindInCodeCache(Name* name, Code::Flags flags) {
Steve Block6ded16b2010-05-10 14:33:55 +010010141 // Do a lookup if a code cache exists.
10142 if (!code_cache()->IsFixedArray()) {
10143 return CodeCache::cast(code_cache())->Lookup(name, flags);
10144 } else {
Steve Block44f0eee2011-05-26 01:26:41 +010010145 return GetHeap()->undefined_value();
Steve Block6ded16b2010-05-10 14:33:55 +010010146 }
10147}
10148
10149
10150int Map::IndexInCodeCache(Object* name, Code* code) {
10151 // Get the internal index if a code cache exists.
10152 if (!code_cache()->IsFixedArray()) {
10153 return CodeCache::cast(code_cache())->GetIndex(name, code);
10154 }
10155 return -1;
10156}
10157
10158
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010159void Map::RemoveFromCodeCache(Name* name, Code* code, int index) {
Steve Block6ded16b2010-05-10 14:33:55 +010010160 // No GC is supposed to happen between a call to IndexInCodeCache and
10161 // RemoveFromCodeCache so the code cache must be there.
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010162 DCHECK(!code_cache()->IsFixedArray());
Steve Block6ded16b2010-05-10 14:33:55 +010010163 CodeCache::cast(code_cache())->RemoveByIndex(name, code, index);
10164}
10165
10166
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010167void CodeCache::Update(
10168 Handle<CodeCache> code_cache, Handle<Name> name, Handle<Code> code) {
Steve Block6ded16b2010-05-10 14:33:55 +010010169 // The number of monomorphic stubs for normal load/store/call IC's can grow to
10170 // a large number and therefore they need to go into a hash table. They are
10171 // used to load global properties from cells.
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010172 if (code->type() == Code::NORMAL) {
Steve Block6ded16b2010-05-10 14:33:55 +010010173 // Make sure that a hash table is allocated for the normal load code cache.
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010174 if (code_cache->normal_type_cache()->IsUndefined()) {
10175 Handle<Object> result =
10176 CodeCacheHashTable::New(code_cache->GetIsolate(),
10177 CodeCacheHashTable::kInitialSize);
10178 code_cache->set_normal_type_cache(*result);
Steve Block6ded16b2010-05-10 14:33:55 +010010179 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010180 UpdateNormalTypeCache(code_cache, name, code);
Steve Block6ded16b2010-05-10 14:33:55 +010010181 } else {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010182 DCHECK(code_cache->default_cache()->IsFixedArray());
10183 UpdateDefaultCache(code_cache, name, code);
Steve Block6ded16b2010-05-10 14:33:55 +010010184 }
10185}
10186
10187
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010188void CodeCache::UpdateDefaultCache(
10189 Handle<CodeCache> code_cache, Handle<Name> name, Handle<Code> code) {
Steve Block6ded16b2010-05-10 14:33:55 +010010190 // When updating the default code cache we disregard the type encoded in the
Steve Blocka7e24c12009-10-30 11:49:00 +000010191 // flags. This allows call constant stubs to overwrite call field
10192 // stubs, etc.
10193 Code::Flags flags = Code::RemoveTypeFromFlags(code->flags());
10194
10195 // First check whether we can update existing code cache without
10196 // extending it.
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010197 Handle<FixedArray> cache = handle(code_cache->default_cache());
Steve Blocka7e24c12009-10-30 11:49:00 +000010198 int length = cache->length();
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010199 {
10200 DisallowHeapAllocation no_alloc;
10201 int deleted_index = -1;
10202 for (int i = 0; i < length; i += kCodeCacheEntrySize) {
10203 Object* key = cache->get(i);
10204 if (key->IsNull()) {
10205 if (deleted_index < 0) deleted_index = i;
10206 continue;
10207 }
10208 if (key->IsUndefined()) {
10209 if (deleted_index >= 0) i = deleted_index;
10210 cache->set(i + kCodeCacheEntryNameOffset, *name);
10211 cache->set(i + kCodeCacheEntryCodeOffset, *code);
10212 return;
10213 }
10214 if (name->Equals(Name::cast(key))) {
10215 Code::Flags found =
10216 Code::cast(cache->get(i + kCodeCacheEntryCodeOffset))->flags();
10217 if (Code::RemoveTypeFromFlags(found) == flags) {
10218 cache->set(i + kCodeCacheEntryCodeOffset, *code);
10219 return;
10220 }
Steve Blocka7e24c12009-10-30 11:49:00 +000010221 }
10222 }
Steve Blocka7e24c12009-10-30 11:49:00 +000010223
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010224 // Reached the end of the code cache. If there were deleted
10225 // elements, reuse the space for the first of them.
10226 if (deleted_index >= 0) {
10227 cache->set(deleted_index + kCodeCacheEntryNameOffset, *name);
10228 cache->set(deleted_index + kCodeCacheEntryCodeOffset, *code);
10229 return;
10230 }
Steve Blocka7e24c12009-10-30 11:49:00 +000010231 }
10232
Steve Block6ded16b2010-05-10 14:33:55 +010010233 // Extend the code cache with some new entries (at least one). Must be a
10234 // multiple of the entry size.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000010235 Isolate* isolate = cache->GetIsolate();
10236 int new_length = length + (length >> 1) + kCodeCacheEntrySize;
Steve Block6ded16b2010-05-10 14:33:55 +010010237 new_length = new_length - new_length % kCodeCacheEntrySize;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010238 DCHECK((new_length % kCodeCacheEntrySize) == 0);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000010239 cache = isolate->factory()->CopyFixedArrayAndGrow(cache, new_length - length);
Steve Blocka7e24c12009-10-30 11:49:00 +000010240
10241 // Add the (name, code) pair to the new cache.
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010242 cache->set(length + kCodeCacheEntryNameOffset, *name);
10243 cache->set(length + kCodeCacheEntryCodeOffset, *code);
10244 code_cache->set_default_cache(*cache);
Steve Blocka7e24c12009-10-30 11:49:00 +000010245}
10246
10247
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010248void CodeCache::UpdateNormalTypeCache(
10249 Handle<CodeCache> code_cache, Handle<Name> name, Handle<Code> code) {
Steve Block6ded16b2010-05-10 14:33:55 +010010250 // Adding a new entry can cause a new cache to be allocated.
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010251 Handle<CodeCacheHashTable> cache(
10252 CodeCacheHashTable::cast(code_cache->normal_type_cache()));
10253 Handle<Object> new_cache = CodeCacheHashTable::Put(cache, name, code);
10254 code_cache->set_normal_type_cache(*new_cache);
Steve Block6ded16b2010-05-10 14:33:55 +010010255}
10256
10257
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010258Object* CodeCache::Lookup(Name* name, Code::Flags flags) {
10259 Object* result = LookupDefaultCache(name, Code::RemoveTypeFromFlags(flags));
10260 if (result->IsCode()) {
10261 if (Code::cast(result)->flags() == flags) return result;
10262 return GetHeap()->undefined_value();
Steve Block6ded16b2010-05-10 14:33:55 +010010263 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010264 return LookupNormalTypeCache(name, flags);
Steve Block6ded16b2010-05-10 14:33:55 +010010265}
10266
10267
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010268Object* CodeCache::LookupDefaultCache(Name* name, Code::Flags flags) {
Steve Block6ded16b2010-05-10 14:33:55 +010010269 FixedArray* cache = default_cache();
Steve Blocka7e24c12009-10-30 11:49:00 +000010270 int length = cache->length();
Steve Block6ded16b2010-05-10 14:33:55 +010010271 for (int i = 0; i < length; i += kCodeCacheEntrySize) {
10272 Object* key = cache->get(i + kCodeCacheEntryNameOffset);
Steve Blocka7e24c12009-10-30 11:49:00 +000010273 // Skip deleted elements.
10274 if (key->IsNull()) continue;
10275 if (key->IsUndefined()) return key;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010276 if (name->Equals(Name::cast(key))) {
Steve Block6ded16b2010-05-10 14:33:55 +010010277 Code* code = Code::cast(cache->get(i + kCodeCacheEntryCodeOffset));
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010278 if (Code::RemoveTypeFromFlags(code->flags()) == flags) {
Steve Block6ded16b2010-05-10 14:33:55 +010010279 return code;
10280 }
Steve Blocka7e24c12009-10-30 11:49:00 +000010281 }
10282 }
Ben Murdoch8b112d22011-06-08 16:22:53 +010010283 return GetHeap()->undefined_value();
Steve Blocka7e24c12009-10-30 11:49:00 +000010284}
10285
10286
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010287Object* CodeCache::LookupNormalTypeCache(Name* name, Code::Flags flags) {
Steve Block6ded16b2010-05-10 14:33:55 +010010288 if (!normal_type_cache()->IsUndefined()) {
10289 CodeCacheHashTable* cache = CodeCacheHashTable::cast(normal_type_cache());
10290 return cache->Lookup(name, flags);
10291 } else {
Steve Block44f0eee2011-05-26 01:26:41 +010010292 return GetHeap()->undefined_value();
Steve Block6ded16b2010-05-10 14:33:55 +010010293 }
10294}
10295
10296
10297int CodeCache::GetIndex(Object* name, Code* code) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010298 if (code->type() == Code::NORMAL) {
Steve Block6ded16b2010-05-10 14:33:55 +010010299 if (normal_type_cache()->IsUndefined()) return -1;
10300 CodeCacheHashTable* cache = CodeCacheHashTable::cast(normal_type_cache());
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010301 return cache->GetIndex(Name::cast(name), code->flags());
Steve Block6ded16b2010-05-10 14:33:55 +010010302 }
10303
10304 FixedArray* array = default_cache();
Steve Blocka7e24c12009-10-30 11:49:00 +000010305 int len = array->length();
Steve Block6ded16b2010-05-10 14:33:55 +010010306 for (int i = 0; i < len; i += kCodeCacheEntrySize) {
10307 if (array->get(i + kCodeCacheEntryCodeOffset) == code) return i + 1;
Steve Blocka7e24c12009-10-30 11:49:00 +000010308 }
10309 return -1;
10310}
10311
10312
Steve Block6ded16b2010-05-10 14:33:55 +010010313void CodeCache::RemoveByIndex(Object* name, Code* code, int index) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010314 if (code->type() == Code::NORMAL) {
10315 DCHECK(!normal_type_cache()->IsUndefined());
Steve Block6ded16b2010-05-10 14:33:55 +010010316 CodeCacheHashTable* cache = CodeCacheHashTable::cast(normal_type_cache());
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010317 DCHECK(cache->GetIndex(Name::cast(name), code->flags()) == index);
Steve Block6ded16b2010-05-10 14:33:55 +010010318 cache->RemoveByIndex(index);
10319 } else {
10320 FixedArray* array = default_cache();
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010321 DCHECK(array->length() >= index && array->get(index)->IsCode());
Steve Block6ded16b2010-05-10 14:33:55 +010010322 // Use null instead of undefined for deleted elements to distinguish
10323 // deleted elements from unused elements. This distinction is used
10324 // when looking up in the cache and when updating the cache.
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010325 DCHECK_EQ(1, kCodeCacheEntryCodeOffset - kCodeCacheEntryNameOffset);
Steve Block6ded16b2010-05-10 14:33:55 +010010326 array->set_null(index - 1); // Name.
10327 array->set_null(index); // Code.
10328 }
10329}
10330
10331
10332// The key in the code cache hash table consists of the property name and the
10333// code object. The actual match is on the name and the code flags. If a key
10334// is created using the flags and not a code object it can only be used for
10335// lookup not to create a new entry.
10336class CodeCacheHashTableKey : public HashTableKey {
10337 public:
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010338 CodeCacheHashTableKey(Handle<Name> name, Code::Flags flags)
10339 : name_(name), flags_(flags), code_() { }
Steve Block6ded16b2010-05-10 14:33:55 +010010340
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010341 CodeCacheHashTableKey(Handle<Name> name, Handle<Code> code)
10342 : name_(name), flags_(code->flags()), code_(code) { }
Steve Block6ded16b2010-05-10 14:33:55 +010010343
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000010344 bool IsMatch(Object* other) override {
Steve Block6ded16b2010-05-10 14:33:55 +010010345 if (!other->IsFixedArray()) return false;
10346 FixedArray* pair = FixedArray::cast(other);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010347 Name* name = Name::cast(pair->get(0));
Steve Block6ded16b2010-05-10 14:33:55 +010010348 Code::Flags flags = Code::cast(pair->get(1))->flags();
10349 if (flags != flags_) {
10350 return false;
10351 }
10352 return name_->Equals(name);
10353 }
10354
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010355 static uint32_t NameFlagsHashHelper(Name* name, Code::Flags flags) {
Steve Block6ded16b2010-05-10 14:33:55 +010010356 return name->Hash() ^ flags;
10357 }
10358
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000010359 uint32_t Hash() override { return NameFlagsHashHelper(*name_, flags_); }
Steve Block6ded16b2010-05-10 14:33:55 +010010360
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000010361 uint32_t HashForObject(Object* obj) override {
Steve Block6ded16b2010-05-10 14:33:55 +010010362 FixedArray* pair = FixedArray::cast(obj);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010363 Name* name = Name::cast(pair->get(0));
Steve Block6ded16b2010-05-10 14:33:55 +010010364 Code* code = Code::cast(pair->get(1));
10365 return NameFlagsHashHelper(name, code->flags());
10366 }
10367
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000010368 MUST_USE_RESULT Handle<Object> AsHandle(Isolate* isolate) override {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010369 Handle<Code> code = code_.ToHandleChecked();
10370 Handle<FixedArray> pair = isolate->factory()->NewFixedArray(2);
10371 pair->set(0, *name_);
10372 pair->set(1, *code);
Steve Block6ded16b2010-05-10 14:33:55 +010010373 return pair;
10374 }
10375
10376 private:
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010377 Handle<Name> name_;
Steve Block6ded16b2010-05-10 14:33:55 +010010378 Code::Flags flags_;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000010379 // TODO(jkummerow): We should be able to get by without this.
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010380 MaybeHandle<Code> code_;
Steve Block6ded16b2010-05-10 14:33:55 +010010381};
10382
10383
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010384Object* CodeCacheHashTable::Lookup(Name* name, Code::Flags flags) {
10385 DisallowHeapAllocation no_alloc;
10386 CodeCacheHashTableKey key(handle(name), flags);
Steve Block6ded16b2010-05-10 14:33:55 +010010387 int entry = FindEntry(&key);
Steve Block44f0eee2011-05-26 01:26:41 +010010388 if (entry == kNotFound) return GetHeap()->undefined_value();
Steve Block6ded16b2010-05-10 14:33:55 +010010389 return get(EntryToIndex(entry) + 1);
10390}
10391
10392
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010393Handle<CodeCacheHashTable> CodeCacheHashTable::Put(
10394 Handle<CodeCacheHashTable> cache, Handle<Name> name, Handle<Code> code) {
Steve Block6ded16b2010-05-10 14:33:55 +010010395 CodeCacheHashTableKey key(name, code);
Steve Block6ded16b2010-05-10 14:33:55 +010010396
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010397 Handle<CodeCacheHashTable> new_cache = EnsureCapacity(cache, 1, &key);
Steve Block6ded16b2010-05-10 14:33:55 +010010398
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010399 int entry = new_cache->FindInsertionEntry(key.Hash());
10400 Handle<Object> k = key.AsHandle(cache->GetIsolate());
Steve Block6ded16b2010-05-10 14:33:55 +010010401
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010402 new_cache->set(EntryToIndex(entry), *k);
10403 new_cache->set(EntryToIndex(entry) + 1, *code);
10404 new_cache->ElementAdded();
10405 return new_cache;
Steve Block6ded16b2010-05-10 14:33:55 +010010406}
10407
10408
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010409int CodeCacheHashTable::GetIndex(Name* name, Code::Flags flags) {
10410 DisallowHeapAllocation no_alloc;
10411 CodeCacheHashTableKey key(handle(name), flags);
Steve Block6ded16b2010-05-10 14:33:55 +010010412 int entry = FindEntry(&key);
10413 return (entry == kNotFound) ? -1 : entry;
10414}
10415
10416
10417void CodeCacheHashTable::RemoveByIndex(int index) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010418 DCHECK(index >= 0);
Steve Block44f0eee2011-05-26 01:26:41 +010010419 Heap* heap = GetHeap();
Ben Murdoch3ef787d2012-04-12 10:51:47 +010010420 set(EntryToIndex(index), heap->the_hole_value());
10421 set(EntryToIndex(index) + 1, heap->the_hole_value());
Steve Block6ded16b2010-05-10 14:33:55 +010010422 ElementRemoved();
Steve Blocka7e24c12009-10-30 11:49:00 +000010423}
10424
10425
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010426void PolymorphicCodeCache::Update(Handle<PolymorphicCodeCache> code_cache,
Ben Murdoch3ef787d2012-04-12 10:51:47 +010010427 MapHandleList* maps,
10428 Code::Flags flags,
10429 Handle<Code> code) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010430 Isolate* isolate = code_cache->GetIsolate();
10431 if (code_cache->cache()->IsUndefined()) {
10432 Handle<PolymorphicCodeCacheHashTable> result =
10433 PolymorphicCodeCacheHashTable::New(
10434 isolate,
10435 PolymorphicCodeCacheHashTable::kInitialSize);
10436 code_cache->set_cache(*result);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000010437 } else {
10438 // This entry shouldn't be contained in the cache yet.
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010439 DCHECK(PolymorphicCodeCacheHashTable::cast(code_cache->cache())
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000010440 ->Lookup(maps, flags)->IsUndefined());
10441 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010442 Handle<PolymorphicCodeCacheHashTable> hash_table =
10443 handle(PolymorphicCodeCacheHashTable::cast(code_cache->cache()));
10444 Handle<PolymorphicCodeCacheHashTable> new_cache =
10445 PolymorphicCodeCacheHashTable::Put(hash_table, maps, flags, code);
10446 code_cache->set_cache(*new_cache);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000010447}
10448
10449
Ben Murdoch3ef787d2012-04-12 10:51:47 +010010450Handle<Object> PolymorphicCodeCache::Lookup(MapHandleList* maps,
10451 Code::Flags flags) {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000010452 if (!cache()->IsUndefined()) {
10453 PolymorphicCodeCacheHashTable* hash_table =
10454 PolymorphicCodeCacheHashTable::cast(cache());
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010455 return Handle<Object>(hash_table->Lookup(maps, flags), GetIsolate());
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000010456 } else {
Ben Murdoch3ef787d2012-04-12 10:51:47 +010010457 return GetIsolate()->factory()->undefined_value();
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000010458 }
10459}
10460
10461
10462// Despite their name, object of this class are not stored in the actual
10463// hash table; instead they're temporarily used for lookups. It is therefore
10464// safe to have a weak (non-owning) pointer to a MapList as a member field.
10465class PolymorphicCodeCacheHashTableKey : public HashTableKey {
10466 public:
10467 // Callers must ensure that |maps| outlives the newly constructed object.
Ben Murdoch3ef787d2012-04-12 10:51:47 +010010468 PolymorphicCodeCacheHashTableKey(MapHandleList* maps, int code_flags)
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000010469 : maps_(maps),
10470 code_flags_(code_flags) {}
10471
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000010472 bool IsMatch(Object* other) override {
Ben Murdoch3ef787d2012-04-12 10:51:47 +010010473 MapHandleList other_maps(kDefaultListAllocationSize);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000010474 int other_flags;
10475 FromObject(other, &other_flags, &other_maps);
10476 if (code_flags_ != other_flags) return false;
10477 if (maps_->length() != other_maps.length()) return false;
10478 // Compare just the hashes first because it's faster.
10479 int this_hash = MapsHashHelper(maps_, code_flags_);
10480 int other_hash = MapsHashHelper(&other_maps, other_flags);
10481 if (this_hash != other_hash) return false;
10482
10483 // Full comparison: for each map in maps_, look for an equivalent map in
10484 // other_maps. This implementation is slow, but probably good enough for
10485 // now because the lists are short (<= 4 elements currently).
10486 for (int i = 0; i < maps_->length(); ++i) {
10487 bool match_found = false;
10488 for (int j = 0; j < other_maps.length(); ++j) {
Ben Murdoch3ef787d2012-04-12 10:51:47 +010010489 if (*(maps_->at(i)) == *(other_maps.at(j))) {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000010490 match_found = true;
10491 break;
10492 }
10493 }
10494 if (!match_found) return false;
10495 }
10496 return true;
10497 }
10498
Ben Murdoch3ef787d2012-04-12 10:51:47 +010010499 static uint32_t MapsHashHelper(MapHandleList* maps, int code_flags) {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000010500 uint32_t hash = code_flags;
10501 for (int i = 0; i < maps->length(); ++i) {
10502 hash ^= maps->at(i)->Hash();
10503 }
10504 return hash;
10505 }
10506
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000010507 uint32_t Hash() override { return MapsHashHelper(maps_, code_flags_); }
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000010508
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000010509 uint32_t HashForObject(Object* obj) override {
Ben Murdoch3ef787d2012-04-12 10:51:47 +010010510 MapHandleList other_maps(kDefaultListAllocationSize);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000010511 int other_flags;
10512 FromObject(obj, &other_flags, &other_maps);
10513 return MapsHashHelper(&other_maps, other_flags);
10514 }
10515
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000010516 MUST_USE_RESULT Handle<Object> AsHandle(Isolate* isolate) override {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000010517 // The maps in |maps_| must be copied to a newly allocated FixedArray,
10518 // both because the referenced MapList is short-lived, and because C++
10519 // objects can't be stored in the heap anyway.
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010520 Handle<FixedArray> list =
10521 isolate->factory()->NewUninitializedFixedArray(maps_->length() + 1);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000010522 list->set(0, Smi::FromInt(code_flags_));
10523 for (int i = 0; i < maps_->length(); ++i) {
Ben Murdoch3ef787d2012-04-12 10:51:47 +010010524 list->set(i + 1, *maps_->at(i));
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000010525 }
10526 return list;
10527 }
10528
10529 private:
Ben Murdoch3ef787d2012-04-12 10:51:47 +010010530 static MapHandleList* FromObject(Object* obj,
10531 int* code_flags,
10532 MapHandleList* maps) {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000010533 FixedArray* list = FixedArray::cast(obj);
10534 maps->Rewind(0);
10535 *code_flags = Smi::cast(list->get(0))->value();
10536 for (int i = 1; i < list->length(); ++i) {
Ben Murdoch3ef787d2012-04-12 10:51:47 +010010537 maps->Add(Handle<Map>(Map::cast(list->get(i))));
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000010538 }
10539 return maps;
10540 }
10541
Ben Murdoch3ef787d2012-04-12 10:51:47 +010010542 MapHandleList* maps_; // weak.
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000010543 int code_flags_;
10544 static const int kDefaultListAllocationSize = kMaxKeyedPolymorphism + 1;
10545};
10546
10547
Ben Murdoch3ef787d2012-04-12 10:51:47 +010010548Object* PolymorphicCodeCacheHashTable::Lookup(MapHandleList* maps,
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010549 int code_kind) {
10550 DisallowHeapAllocation no_alloc;
10551 PolymorphicCodeCacheHashTableKey key(maps, code_kind);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000010552 int entry = FindEntry(&key);
10553 if (entry == kNotFound) return GetHeap()->undefined_value();
10554 return get(EntryToIndex(entry) + 1);
10555}
10556
10557
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010558Handle<PolymorphicCodeCacheHashTable> PolymorphicCodeCacheHashTable::Put(
10559 Handle<PolymorphicCodeCacheHashTable> hash_table,
10560 MapHandleList* maps,
10561 int code_kind,
10562 Handle<Code> code) {
10563 PolymorphicCodeCacheHashTableKey key(maps, code_kind);
10564 Handle<PolymorphicCodeCacheHashTable> cache =
10565 EnsureCapacity(hash_table, 1, &key);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000010566 int entry = cache->FindInsertionEntry(key.Hash());
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010567
10568 Handle<Object> obj = key.AsHandle(hash_table->GetIsolate());
10569 cache->set(EntryToIndex(entry), *obj);
10570 cache->set(EntryToIndex(entry) + 1, *code);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000010571 cache->ElementAdded();
10572 return cache;
10573}
10574
10575
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010576void FixedArray::Shrink(int new_length) {
10577 DCHECK(0 <= new_length && new_length <= length());
10578 if (new_length < length()) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000010579 GetHeap()->RightTrimFixedArray<Heap::CONCURRENT_TO_SWEEPER>(
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010580 this, length() - new_length);
10581 }
10582}
10583
10584
Steve Blocka7e24c12009-10-30 11:49:00 +000010585void FixedArray::CopyTo(int pos, FixedArray* dest, int dest_pos, int len) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010586 DisallowHeapAllocation no_gc;
Leon Clarke4515c472010-02-03 11:58:03 +000010587 WriteBarrierMode mode = dest->GetWriteBarrierMode(no_gc);
Steve Blocka7e24c12009-10-30 11:49:00 +000010588 for (int index = 0; index < len; index++) {
10589 dest->set(dest_pos+index, get(pos+index), mode);
10590 }
10591}
10592
10593
10594#ifdef DEBUG
10595bool FixedArray::IsEqualTo(FixedArray* other) {
10596 if (length() != other->length()) return false;
10597 for (int i = 0 ; i < length(); ++i) {
10598 if (get(i) != other->get(i)) return false;
10599 }
10600 return true;
10601}
10602#endif
10603
10604
Emily Bernierd0a1eb72015-03-24 16:35:39 -040010605// static
10606void WeakFixedArray::Set(Handle<WeakFixedArray> array, int index,
10607 Handle<HeapObject> value) {
10608 DCHECK(array->IsEmptySlot(index)); // Don't overwrite anything.
10609 Handle<WeakCell> cell =
10610 value->IsMap() ? Map::WeakCellForMap(Handle<Map>::cast(value))
10611 : array->GetIsolate()->factory()->NewWeakCell(value);
10612 Handle<FixedArray>::cast(array)->set(index + kFirstIndex, *cell);
10613 if (FLAG_trace_weak_arrays) {
10614 PrintF("[WeakFixedArray: storing at index %d ]\n", index);
10615 }
10616 array->set_last_used_index(index);
10617}
10618
10619
10620// static
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000010621Handle<WeakFixedArray> WeakFixedArray::Add(Handle<Object> maybe_array,
10622 Handle<HeapObject> value,
10623 int* assigned_index) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -040010624 Handle<WeakFixedArray> array =
10625 (maybe_array.is_null() || !maybe_array->IsWeakFixedArray())
10626 ? Allocate(value->GetIsolate(), 1, Handle<WeakFixedArray>::null())
10627 : Handle<WeakFixedArray>::cast(maybe_array);
Emily Bernierd0a1eb72015-03-24 16:35:39 -040010628 // Try to store the new entry if there's room. Optimize for consecutive
10629 // accesses.
10630 int first_index = array->last_used_index();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000010631 int length = array->Length();
10632 if (length > 0) {
10633 for (int i = first_index;;) {
10634 if (array->IsEmptySlot((i))) {
10635 WeakFixedArray::Set(array, i, value);
10636 if (assigned_index != NULL) *assigned_index = i;
10637 return array;
10638 }
10639 if (FLAG_trace_weak_arrays) {
10640 PrintF("[WeakFixedArray: searching for free slot]\n");
10641 }
10642 i = (i + 1) % length;
10643 if (i == first_index) break;
Emily Bernierd0a1eb72015-03-24 16:35:39 -040010644 }
Emily Bernierd0a1eb72015-03-24 16:35:39 -040010645 }
10646
10647 // No usable slot found, grow the array.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000010648 int new_length = length == 0 ? 1 : length + (length >> 1) + 4;
Emily Bernierd0a1eb72015-03-24 16:35:39 -040010649 Handle<WeakFixedArray> new_array =
10650 Allocate(array->GetIsolate(), new_length, array);
10651 if (FLAG_trace_weak_arrays) {
10652 PrintF("[WeakFixedArray: growing to size %d ]\n", new_length);
10653 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000010654 WeakFixedArray::Set(new_array, length, value);
10655 if (assigned_index != NULL) *assigned_index = length;
Emily Bernierd0a1eb72015-03-24 16:35:39 -040010656 return new_array;
10657}
10658
10659
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000010660template <class CompactionCallback>
10661void WeakFixedArray::Compact() {
10662 FixedArray* array = FixedArray::cast(this);
10663 int new_length = kFirstIndex;
10664 for (int i = kFirstIndex; i < array->length(); i++) {
10665 Object* element = array->get(i);
10666 if (element->IsSmi()) continue;
10667 if (WeakCell::cast(element)->cleared()) continue;
10668 Object* value = WeakCell::cast(element)->value();
10669 CompactionCallback::Callback(value, i - kFirstIndex,
10670 new_length - kFirstIndex);
10671 array->set(new_length++, element);
10672 }
10673 array->Shrink(new_length);
10674 set_last_used_index(0);
10675}
10676
10677
10678void WeakFixedArray::Iterator::Reset(Object* maybe_array) {
10679 if (maybe_array->IsWeakFixedArray()) {
10680 list_ = WeakFixedArray::cast(maybe_array);
10681 index_ = 0;
10682#ifdef DEBUG
10683 last_used_index_ = list_->last_used_index();
10684#endif // DEBUG
10685 }
10686}
10687
10688
10689void JSObject::PrototypeRegistryCompactionCallback::Callback(Object* value,
10690 int old_index,
10691 int new_index) {
10692 DCHECK(value->IsMap() && Map::cast(value)->is_prototype_map());
10693 Map* map = Map::cast(value);
10694 DCHECK(map->prototype_info()->IsPrototypeInfo());
10695 PrototypeInfo* proto_info = PrototypeInfo::cast(map->prototype_info());
10696 DCHECK_EQ(old_index, proto_info->registry_slot());
10697 proto_info->set_registry_slot(new_index);
10698}
10699
10700
10701template void WeakFixedArray::Compact<WeakFixedArray::NullCallback>();
10702template void
10703WeakFixedArray::Compact<JSObject::PrototypeRegistryCompactionCallback>();
10704
10705
10706bool WeakFixedArray::Remove(Handle<HeapObject> value) {
10707 if (Length() == 0) return false;
Emily Bernierd0a1eb72015-03-24 16:35:39 -040010708 // Optimize for the most recently added element to be removed again.
10709 int first_index = last_used_index();
10710 for (int i = first_index;;) {
10711 if (Get(i) == *value) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000010712 Clear(i);
10713 // Users of WeakFixedArray should make sure that there are no duplicates.
10714 return true;
Emily Bernierd0a1eb72015-03-24 16:35:39 -040010715 }
10716 i = (i + 1) % Length();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000010717 if (i == first_index) return false;
Emily Bernierd0a1eb72015-03-24 16:35:39 -040010718 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000010719 UNREACHABLE();
Emily Bernierd0a1eb72015-03-24 16:35:39 -040010720}
10721
10722
10723// static
10724Handle<WeakFixedArray> WeakFixedArray::Allocate(
10725 Isolate* isolate, int size, Handle<WeakFixedArray> initialize_from) {
10726 DCHECK(0 <= size);
10727 Handle<FixedArray> result =
10728 isolate->factory()->NewUninitializedFixedArray(size + kFirstIndex);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000010729 int index = 0;
10730 if (!initialize_from.is_null()) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -040010731 DCHECK(initialize_from->Length() <= size);
10732 Handle<FixedArray> raw_source = Handle<FixedArray>::cast(initialize_from);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000010733 // Copy the entries without compacting, since the PrototypeInfo relies on
10734 // the index of the entries not to change.
10735 while (index < raw_source->length()) {
10736 result->set(index, raw_source->get(index));
10737 index++;
Emily Bernierd0a1eb72015-03-24 16:35:39 -040010738 }
10739 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000010740 while (index < result->length()) {
10741 result->set(index, Smi::FromInt(0));
10742 index++;
10743 }
10744 return Handle<WeakFixedArray>::cast(result);
10745}
10746
10747
10748Handle<ArrayList> ArrayList::Add(Handle<ArrayList> array, Handle<Object> obj,
10749 AddMode mode) {
10750 int length = array->Length();
10751 array = EnsureSpace(array, length + 1);
10752 if (mode == kReloadLengthAfterAllocation) {
10753 DCHECK(array->Length() <= length);
10754 length = array->Length();
10755 }
10756 array->Set(length, *obj);
10757 array->SetLength(length + 1);
10758 return array;
10759}
10760
10761
10762Handle<ArrayList> ArrayList::Add(Handle<ArrayList> array, Handle<Object> obj1,
10763 Handle<Object> obj2, AddMode mode) {
10764 int length = array->Length();
10765 array = EnsureSpace(array, length + 2);
10766 if (mode == kReloadLengthAfterAllocation) {
10767 length = array->Length();
10768 }
10769 array->Set(length, *obj1);
10770 array->Set(length + 1, *obj2);
10771 array->SetLength(length + 2);
10772 return array;
10773}
10774
10775
10776bool ArrayList::IsFull() {
10777 int capacity = length();
10778 return kFirstIndex + Length() == capacity;
10779}
10780
10781
10782Handle<ArrayList> ArrayList::EnsureSpace(Handle<ArrayList> array, int length) {
10783 int capacity = array->length();
10784 bool empty = (capacity == 0);
10785 if (capacity < kFirstIndex + length) {
10786 Isolate* isolate = array->GetIsolate();
10787 int new_capacity = kFirstIndex + length;
10788 new_capacity = new_capacity + Max(new_capacity / 2, 2);
10789 int grow_by = new_capacity - capacity;
10790 array = Handle<ArrayList>::cast(
10791 isolate->factory()->CopyFixedArrayAndGrow(array, grow_by));
10792 if (empty) array->SetLength(0);
10793 }
10794 return array;
Emily Bernierd0a1eb72015-03-24 16:35:39 -040010795}
10796
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010797Handle<DescriptorArray> DescriptorArray::Allocate(Isolate* isolate,
10798 int number_of_descriptors,
Ben Murdoch097c5b22016-05-18 11:27:45 +010010799 int slack,
10800 PretenureFlag pretenure) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010801 DCHECK(0 <= number_of_descriptors);
10802 Factory* factory = isolate->factory();
Steve Blocka7e24c12009-10-30 11:49:00 +000010803 // Do not use DescriptorArray::cast on incomplete object.
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010804 int size = number_of_descriptors + slack;
10805 if (size == 0) return factory->empty_descriptor_array();
10806 // Allocate the array of keys.
Ben Murdoch097c5b22016-05-18 11:27:45 +010010807 Handle<FixedArray> result =
10808 factory->NewFixedArray(LengthFor(size), pretenure);
Steve Blocka7e24c12009-10-30 11:49:00 +000010809
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010810 result->set(kDescriptorLengthIndex, Smi::FromInt(number_of_descriptors));
10811 result->set(kEnumCacheIndex, Smi::FromInt(0));
10812 return Handle<DescriptorArray>::cast(result);
10813}
10814
10815
10816void DescriptorArray::ClearEnumCache() {
10817 set(kEnumCacheIndex, Smi::FromInt(0));
10818}
10819
10820
10821void DescriptorArray::Replace(int index, Descriptor* descriptor) {
10822 descriptor->SetSortedKeyIndex(GetSortedKeyIndex(index));
10823 Set(index, descriptor);
Steve Blocka7e24c12009-10-30 11:49:00 +000010824}
10825
10826
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000010827// static
10828void DescriptorArray::SetEnumCache(Handle<DescriptorArray> descriptors,
10829 Isolate* isolate,
10830 Handle<FixedArray> new_cache,
10831 Handle<FixedArray> new_index_cache) {
10832 DCHECK(!descriptors->IsEmpty());
10833 FixedArray* bridge_storage;
10834 bool needs_new_enum_cache = !descriptors->HasEnumCache();
10835 if (needs_new_enum_cache) {
10836 bridge_storage = *isolate->factory()->NewFixedArray(
10837 DescriptorArray::kEnumCacheBridgeLength);
10838 } else {
10839 bridge_storage = FixedArray::cast(descriptors->get(kEnumCacheIndex));
10840 }
10841 bridge_storage->set(kEnumCacheBridgeCacheIndex, *new_cache);
10842 bridge_storage->set(kEnumCacheBridgeIndicesCacheIndex,
10843 new_index_cache.is_null() ? Object::cast(Smi::FromInt(0))
10844 : *new_index_cache);
10845 if (needs_new_enum_cache) {
10846 descriptors->set(kEnumCacheIndex, bridge_storage);
10847 }
Steve Blocka7e24c12009-10-30 11:49:00 +000010848}
10849
10850
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000010851void DescriptorArray::CopyFrom(int index, DescriptorArray* src) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010852 Object* value = src->GetValue(index);
10853 PropertyDetails details = src->GetDetails(index);
10854 Descriptor desc(handle(src->GetKey(index)),
10855 handle(value, src->GetIsolate()),
10856 details);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000010857 SetDescriptor(index, &desc);
Ben Murdoch3ef787d2012-04-12 10:51:47 +010010858}
10859
10860
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010861void DescriptorArray::Sort() {
Steve Blocka7e24c12009-10-30 11:49:00 +000010862 // In-place heap sort.
10863 int len = number_of_descriptors();
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010864 // Reset sorting since the descriptor array might contain invalid pointers.
10865 for (int i = 0; i < len; ++i) SetSortedKey(i, i);
Steve Blocka7e24c12009-10-30 11:49:00 +000010866 // Bottom-up max-heap construction.
Steve Block6ded16b2010-05-10 14:33:55 +010010867 // Index of the last node with children
10868 const int max_parent_index = (len / 2) - 1;
10869 for (int i = max_parent_index; i >= 0; --i) {
10870 int parent_index = i;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010871 const uint32_t parent_hash = GetSortedKey(i)->Hash();
Steve Block6ded16b2010-05-10 14:33:55 +010010872 while (parent_index <= max_parent_index) {
10873 int child_index = 2 * parent_index + 1;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010874 uint32_t child_hash = GetSortedKey(child_index)->Hash();
Steve Block6ded16b2010-05-10 14:33:55 +010010875 if (child_index + 1 < len) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010876 uint32_t right_child_hash = GetSortedKey(child_index + 1)->Hash();
Steve Block6ded16b2010-05-10 14:33:55 +010010877 if (right_child_hash > child_hash) {
10878 child_index++;
10879 child_hash = right_child_hash;
10880 }
Steve Blocka7e24c12009-10-30 11:49:00 +000010881 }
Steve Block6ded16b2010-05-10 14:33:55 +010010882 if (child_hash <= parent_hash) break;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010883 SwapSortedKeys(parent_index, child_index);
Steve Block6ded16b2010-05-10 14:33:55 +010010884 // Now element at child_index could be < its children.
10885 parent_index = child_index; // parent_hash remains correct.
Steve Blocka7e24c12009-10-30 11:49:00 +000010886 }
10887 }
10888
10889 // Extract elements and create sorted array.
10890 for (int i = len - 1; i > 0; --i) {
10891 // Put max element at the back of the array.
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010892 SwapSortedKeys(0, i);
Ben Murdoch3ef787d2012-04-12 10:51:47 +010010893 // Shift down the new top element.
Steve Blocka7e24c12009-10-30 11:49:00 +000010894 int parent_index = 0;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010895 const uint32_t parent_hash = GetSortedKey(parent_index)->Hash();
Steve Block6ded16b2010-05-10 14:33:55 +010010896 const int max_parent_index = (i / 2) - 1;
10897 while (parent_index <= max_parent_index) {
10898 int child_index = parent_index * 2 + 1;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010899 uint32_t child_hash = GetSortedKey(child_index)->Hash();
Steve Block6ded16b2010-05-10 14:33:55 +010010900 if (child_index + 1 < i) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010901 uint32_t right_child_hash = GetSortedKey(child_index + 1)->Hash();
Steve Block6ded16b2010-05-10 14:33:55 +010010902 if (right_child_hash > child_hash) {
10903 child_index++;
10904 child_hash = right_child_hash;
10905 }
Steve Blocka7e24c12009-10-30 11:49:00 +000010906 }
Steve Block6ded16b2010-05-10 14:33:55 +010010907 if (child_hash <= parent_hash) break;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010908 SwapSortedKeys(parent_index, child_index);
Steve Block6ded16b2010-05-10 14:33:55 +010010909 parent_index = child_index;
Steve Blocka7e24c12009-10-30 11:49:00 +000010910 }
10911 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010912 DCHECK(IsSortedNoDuplicates());
Kristian Monsen0d5e1162010-09-30 15:31:59 +010010913}
Steve Blocka7e24c12009-10-30 11:49:00 +000010914
Kristian Monsen0d5e1162010-09-30 15:31:59 +010010915
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010916Handle<AccessorPair> AccessorPair::Copy(Handle<AccessorPair> pair) {
10917 Handle<AccessorPair> copy = pair->GetIsolate()->factory()->NewAccessorPair();
10918 copy->set_getter(pair->getter());
10919 copy->set_setter(pair->setter());
Ben Murdoch3ef787d2012-04-12 10:51:47 +010010920 return copy;
10921}
10922
Ben Murdoch097c5b22016-05-18 11:27:45 +010010923Handle<Object> AccessorPair::GetComponent(Handle<AccessorPair> accessor_pair,
10924 AccessorComponent component) {
10925 Object* accessor = accessor_pair->get(component);
10926 if (accessor->IsFunctionTemplateInfo()) {
10927 return ApiNatives::InstantiateFunction(
10928 handle(FunctionTemplateInfo::cast(accessor)))
10929 .ToHandleChecked();
10930 }
10931 Isolate* isolate = accessor_pair->GetIsolate();
10932 if (accessor->IsTheHole()) {
10933 return isolate->factory()->undefined_value();
10934 }
10935 return handle(accessor, isolate);
Ben Murdoch3ef787d2012-04-12 10:51:47 +010010936}
10937
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010938Handle<DeoptimizationInputData> DeoptimizationInputData::New(
10939 Isolate* isolate, int deopt_entry_count, PretenureFlag pretenure) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010940 return Handle<DeoptimizationInputData>::cast(
10941 isolate->factory()->NewFixedArray(LengthFor(deopt_entry_count),
10942 pretenure));
Ben Murdochb0fe1622011-05-05 13:52:32 +010010943}
10944
10945
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010946Handle<DeoptimizationOutputData> DeoptimizationOutputData::New(
10947 Isolate* isolate,
10948 int number_of_deopt_points,
10949 PretenureFlag pretenure) {
10950 Handle<FixedArray> result;
10951 if (number_of_deopt_points == 0) {
10952 result = isolate->factory()->empty_fixed_array();
10953 } else {
10954 result = isolate->factory()->NewFixedArray(
10955 LengthOfFixedArray(number_of_deopt_points), pretenure);
10956 }
10957 return Handle<DeoptimizationOutputData>::cast(result);
Ben Murdochb0fe1622011-05-05 13:52:32 +010010958}
10959
10960
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000010961// static
10962Handle<LiteralsArray> LiteralsArray::New(Isolate* isolate,
10963 Handle<TypeFeedbackVector> vector,
10964 int number_of_literals,
10965 PretenureFlag pretenure) {
10966 Handle<FixedArray> literals = isolate->factory()->NewFixedArray(
10967 number_of_literals + kFirstLiteralIndex, pretenure);
10968 Handle<LiteralsArray> casted_literals = Handle<LiteralsArray>::cast(literals);
10969 casted_literals->set_feedback_vector(*vector);
10970 return casted_literals;
10971}
10972
Ben Murdoch097c5b22016-05-18 11:27:45 +010010973int HandlerTable::LookupRange(int pc_offset, int* data_out,
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000010974 CatchPrediction* prediction_out) {
Ben Murdoch097c5b22016-05-18 11:27:45 +010010975 int innermost_handler = -1;
10976#ifdef DEBUG
10977 // Assuming that ranges are well nested, we don't need to track the innermost
10978 // offsets. This is just to verify that the table is actually well nested.
10979 int innermost_start = std::numeric_limits<int>::min();
10980 int innermost_end = std::numeric_limits<int>::max();
10981#endif
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000010982 for (int i = 0; i < length(); i += kRangeEntrySize) {
10983 int start_offset = Smi::cast(get(i + kRangeStartIndex))->value();
10984 int end_offset = Smi::cast(get(i + kRangeEndIndex))->value();
10985 int handler_field = Smi::cast(get(i + kRangeHandlerIndex))->value();
10986 int handler_offset = HandlerOffsetField::decode(handler_field);
10987 CatchPrediction prediction = HandlerPredictionField::decode(handler_field);
Ben Murdoch097c5b22016-05-18 11:27:45 +010010988 int handler_data = Smi::cast(get(i + kRangeDataIndex))->value();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000010989 if (pc_offset > start_offset && pc_offset <= end_offset) {
Ben Murdoch097c5b22016-05-18 11:27:45 +010010990 DCHECK_GE(start_offset, innermost_start);
10991 DCHECK_LT(end_offset, innermost_end);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000010992 innermost_handler = handler_offset;
Ben Murdoch097c5b22016-05-18 11:27:45 +010010993#ifdef DEBUG
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000010994 innermost_start = start_offset;
Ben Murdoch097c5b22016-05-18 11:27:45 +010010995 innermost_end = end_offset;
10996#endif
10997 if (data_out) *data_out = handler_data;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000010998 if (prediction_out) *prediction_out = prediction;
10999 }
11000 }
11001 return innermost_handler;
11002}
11003
11004
11005// TODO(turbofan): Make sure table is sorted and use binary search.
11006int HandlerTable::LookupReturn(int pc_offset, CatchPrediction* prediction_out) {
11007 for (int i = 0; i < length(); i += kReturnEntrySize) {
11008 int return_offset = Smi::cast(get(i + kReturnOffsetIndex))->value();
11009 int handler_field = Smi::cast(get(i + kReturnHandlerIndex))->value();
11010 if (pc_offset == return_offset) {
11011 if (prediction_out) {
11012 *prediction_out = HandlerPredictionField::decode(handler_field);
11013 }
11014 return HandlerOffsetField::decode(handler_field);
11015 }
11016 }
11017 return -1;
11018}
11019
11020
Steve Blocka7e24c12009-10-30 11:49:00 +000011021#ifdef DEBUG
11022bool DescriptorArray::IsEqualTo(DescriptorArray* other) {
11023 if (IsEmpty()) return other->IsEmpty();
11024 if (other->IsEmpty()) return false;
11025 if (length() != other->length()) return false;
11026 for (int i = 0; i < length(); ++i) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011027 if (get(i) != other->get(i)) return false;
Steve Blocka7e24c12009-10-30 11:49:00 +000011028 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011029 return true;
Steve Blocka7e24c12009-10-30 11:49:00 +000011030}
11031#endif
11032
11033
Steve Blocka7e24c12009-10-30 11:49:00 +000011034bool String::LooksValid() {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011035 if (!GetIsolate()->heap()->Contains(this)) return false;
Steve Blocka7e24c12009-10-30 11:49:00 +000011036 return true;
11037}
11038
11039
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000011040// static
11041MaybeHandle<String> Name::ToFunctionName(Handle<Name> name) {
11042 if (name->IsString()) return Handle<String>::cast(name);
11043 // ES6 section 9.2.11 SetFunctionName, step 4.
11044 Isolate* const isolate = name->GetIsolate();
11045 Handle<Object> description(Handle<Symbol>::cast(name)->name(), isolate);
11046 if (description->IsUndefined()) return isolate->factory()->empty_string();
11047 IncrementalStringBuilder builder(isolate);
11048 builder.AppendCharacter('[');
11049 builder.AppendString(Handle<String>::cast(description));
11050 builder.AppendCharacter(']');
11051 return builder.Finish();
11052}
11053
11054
11055namespace {
11056
11057bool AreDigits(const uint8_t* s, int from, int to) {
11058 for (int i = from; i < to; i++) {
11059 if (s[i] < '0' || s[i] > '9') return false;
11060 }
11061
11062 return true;
11063}
11064
11065
11066int ParseDecimalInteger(const uint8_t* s, int from, int to) {
11067 DCHECK(to - from < 10); // Overflow is not possible.
11068 DCHECK(from < to);
11069 int d = s[from] - '0';
11070
11071 for (int i = from + 1; i < to; i++) {
11072 d = 10 * d + (s[i] - '0');
11073 }
11074
11075 return d;
11076}
11077
11078} // namespace
11079
11080
11081// static
11082Handle<Object> String::ToNumber(Handle<String> subject) {
11083 Isolate* const isolate = subject->GetIsolate();
11084
11085 // Flatten {subject} string first.
11086 subject = String::Flatten(subject);
11087
11088 // Fast array index case.
11089 uint32_t index;
11090 if (subject->AsArrayIndex(&index)) {
11091 return isolate->factory()->NewNumberFromUint(index);
11092 }
11093
11094 // Fast case: short integer or some sorts of junk values.
11095 if (subject->IsSeqOneByteString()) {
11096 int len = subject->length();
11097 if (len == 0) return handle(Smi::FromInt(0), isolate);
11098
11099 DisallowHeapAllocation no_gc;
11100 uint8_t const* data = Handle<SeqOneByteString>::cast(subject)->GetChars();
11101 bool minus = (data[0] == '-');
11102 int start_pos = (minus ? 1 : 0);
11103
11104 if (start_pos == len) {
11105 return isolate->factory()->nan_value();
11106 } else if (data[start_pos] > '9') {
11107 // Fast check for a junk value. A valid string may start from a
11108 // whitespace, a sign ('+' or '-'), the decimal point, a decimal digit
11109 // or the 'I' character ('Infinity'). All of that have codes not greater
11110 // than '9' except 'I' and &nbsp;.
11111 if (data[start_pos] != 'I' && data[start_pos] != 0xa0) {
11112 return isolate->factory()->nan_value();
11113 }
11114 } else if (len - start_pos < 10 && AreDigits(data, start_pos, len)) {
11115 // The maximal/minimal smi has 10 digits. If the string has less digits
11116 // we know it will fit into the smi-data type.
11117 int d = ParseDecimalInteger(data, start_pos, len);
11118 if (minus) {
11119 if (d == 0) return isolate->factory()->minus_zero_value();
11120 d = -d;
11121 } else if (!subject->HasHashCode() && len <= String::kMaxArrayIndexSize &&
11122 (len == 1 || data[0] != '0')) {
11123 // String hash is not calculated yet but all the data are present.
11124 // Update the hash field to speed up sequential convertions.
11125 uint32_t hash = StringHasher::MakeArrayIndexHash(d, len);
11126#ifdef DEBUG
11127 subject->Hash(); // Force hash calculation.
11128 DCHECK_EQ(static_cast<int>(subject->hash_field()),
11129 static_cast<int>(hash));
11130#endif
11131 subject->set_hash_field(hash);
11132 }
11133 return handle(Smi::FromInt(d), isolate);
11134 }
11135 }
11136
11137 // Slower case.
11138 int flags = ALLOW_HEX | ALLOW_OCTAL | ALLOW_BINARY;
11139 return isolate->factory()->NewNumber(
11140 StringToDouble(isolate->unicode_cache(), subject, flags));
11141}
11142
11143
Ben Murdoch69a99ed2011-11-30 16:03:39 +000011144String::FlatContent String::GetFlatContent() {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011145 DCHECK(!AllowHeapAllocation::IsAllowed());
Steve Blocka7e24c12009-10-30 11:49:00 +000011146 int length = this->length();
Ben Murdoch69a99ed2011-11-30 16:03:39 +000011147 StringShape shape(this);
Steve Blocka7e24c12009-10-30 11:49:00 +000011148 String* string = this;
Steve Blocka7e24c12009-10-30 11:49:00 +000011149 int offset = 0;
Ben Murdoch69a99ed2011-11-30 16:03:39 +000011150 if (shape.representation_tag() == kConsStringTag) {
Steve Blocka7e24c12009-10-30 11:49:00 +000011151 ConsString* cons = ConsString::cast(string);
Ben Murdoch69a99ed2011-11-30 16:03:39 +000011152 if (cons->second()->length() != 0) {
11153 return FlatContent();
11154 }
Steve Blocka7e24c12009-10-30 11:49:00 +000011155 string = cons->first();
Ben Murdoch69a99ed2011-11-30 16:03:39 +000011156 shape = StringShape(string);
Steve Blocka7e24c12009-10-30 11:49:00 +000011157 }
Ben Murdoch69a99ed2011-11-30 16:03:39 +000011158 if (shape.representation_tag() == kSlicedStringTag) {
11159 SlicedString* slice = SlicedString::cast(string);
11160 offset = slice->offset();
11161 string = slice->parent();
11162 shape = StringShape(string);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011163 DCHECK(shape.representation_tag() != kConsStringTag &&
Ben Murdoch69a99ed2011-11-30 16:03:39 +000011164 shape.representation_tag() != kSlicedStringTag);
Steve Blocka7e24c12009-10-30 11:49:00 +000011165 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011166 if (shape.encoding_tag() == kOneByteStringTag) {
11167 const uint8_t* start;
Ben Murdoch69a99ed2011-11-30 16:03:39 +000011168 if (shape.representation_tag() == kSeqStringTag) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011169 start = SeqOneByteString::cast(string)->GetChars();
Ben Murdoch69a99ed2011-11-30 16:03:39 +000011170 } else {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011171 start = ExternalOneByteString::cast(string)->GetChars();
Ben Murdoch69a99ed2011-11-30 16:03:39 +000011172 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011173 return FlatContent(start + offset, length);
Ben Murdoch69a99ed2011-11-30 16:03:39 +000011174 } else {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011175 DCHECK(shape.encoding_tag() == kTwoByteStringTag);
Ben Murdoch69a99ed2011-11-30 16:03:39 +000011176 const uc16* start;
11177 if (shape.representation_tag() == kSeqStringTag) {
11178 start = SeqTwoByteString::cast(string)->GetChars();
11179 } else {
Ben Murdoch3ef787d2012-04-12 10:51:47 +010011180 start = ExternalTwoByteString::cast(string)->GetChars();
Ben Murdoch69a99ed2011-11-30 16:03:39 +000011181 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011182 return FlatContent(start + offset, length);
Ben Murdoch69a99ed2011-11-30 16:03:39 +000011183 }
Steve Blocka7e24c12009-10-30 11:49:00 +000011184}
11185
11186
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000011187base::SmartArrayPointer<char> String::ToCString(AllowNullsFlag allow_nulls,
11188 RobustnessFlag robust_flag,
11189 int offset, int length,
11190 int* length_return) {
Steve Blocka7e24c12009-10-30 11:49:00 +000011191 if (robust_flag == ROBUST_STRING_TRAVERSAL && !LooksValid()) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000011192 return base::SmartArrayPointer<char>(NULL);
Steve Blocka7e24c12009-10-30 11:49:00 +000011193 }
Steve Blocka7e24c12009-10-30 11:49:00 +000011194 // Negative length means the to the end of the string.
11195 if (length < 0) length = kMaxInt - offset;
11196
11197 // Compute the size of the UTF-8 string. Start at the specified offset.
Emily Bernierd0a1eb72015-03-24 16:35:39 -040011198 StringCharacterStream stream(this, offset);
Steve Blocka7e24c12009-10-30 11:49:00 +000011199 int character_position = offset;
11200 int utf8_bytes = 0;
Ben Murdoch3ef787d2012-04-12 10:51:47 +010011201 int last = unibrow::Utf16::kNoPreviousCharacter;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011202 while (stream.HasMore() && character_position++ < offset + length) {
11203 uint16_t character = stream.GetNext();
Ben Murdoch3ef787d2012-04-12 10:51:47 +010011204 utf8_bytes += unibrow::Utf8::Length(character, last);
11205 last = character;
Steve Blocka7e24c12009-10-30 11:49:00 +000011206 }
11207
11208 if (length_return) {
11209 *length_return = utf8_bytes;
11210 }
11211
11212 char* result = NewArray<char>(utf8_bytes + 1);
11213
11214 // Convert the UTF-16 string to a UTF-8 buffer. Start at the specified offset.
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011215 stream.Reset(this, offset);
Steve Blocka7e24c12009-10-30 11:49:00 +000011216 character_position = offset;
11217 int utf8_byte_position = 0;
Ben Murdoch3ef787d2012-04-12 10:51:47 +010011218 last = unibrow::Utf16::kNoPreviousCharacter;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011219 while (stream.HasMore() && character_position++ < offset + length) {
11220 uint16_t character = stream.GetNext();
Ben Murdoch3ef787d2012-04-12 10:51:47 +010011221 if (allow_nulls == DISALLOW_NULLS && character == 0) {
11222 character = ' ';
Steve Blocka7e24c12009-10-30 11:49:00 +000011223 }
Ben Murdoch3ef787d2012-04-12 10:51:47 +010011224 utf8_byte_position +=
11225 unibrow::Utf8::Encode(result + utf8_byte_position, character, last);
11226 last = character;
Steve Blocka7e24c12009-10-30 11:49:00 +000011227 }
11228 result[utf8_byte_position] = 0;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000011229 return base::SmartArrayPointer<char>(result);
Steve Blocka7e24c12009-10-30 11:49:00 +000011230}
11231
11232
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000011233base::SmartArrayPointer<char> String::ToCString(AllowNullsFlag allow_nulls,
11234 RobustnessFlag robust_flag,
11235 int* length_return) {
Steve Blocka7e24c12009-10-30 11:49:00 +000011236 return ToCString(allow_nulls, robust_flag, 0, -1, length_return);
11237}
11238
11239
Steve Blocka7e24c12009-10-30 11:49:00 +000011240const uc16* String::GetTwoByteData(unsigned start) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011241 DCHECK(!IsOneByteRepresentationUnderneath());
Steve Blocka7e24c12009-10-30 11:49:00 +000011242 switch (StringShape(this).representation_tag()) {
11243 case kSeqStringTag:
11244 return SeqTwoByteString::cast(this)->SeqTwoByteStringGetData(start);
11245 case kExternalStringTag:
11246 return ExternalTwoByteString::cast(this)->
11247 ExternalTwoByteStringGetData(start);
Ben Murdoch69a99ed2011-11-30 16:03:39 +000011248 case kSlicedStringTag: {
11249 SlicedString* slice = SlicedString::cast(this);
11250 return slice->parent()->GetTwoByteData(start + slice->offset());
11251 }
Steve Blocka7e24c12009-10-30 11:49:00 +000011252 case kConsStringTag:
11253 UNREACHABLE();
11254 return NULL;
11255 }
11256 UNREACHABLE();
11257 return NULL;
11258}
11259
11260
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000011261base::SmartArrayPointer<uc16> String::ToWideCString(
11262 RobustnessFlag robust_flag) {
Steve Blocka7e24c12009-10-30 11:49:00 +000011263 if (robust_flag == ROBUST_STRING_TRAVERSAL && !LooksValid()) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000011264 return base::SmartArrayPointer<uc16>();
Steve Blocka7e24c12009-10-30 11:49:00 +000011265 }
Emily Bernierd0a1eb72015-03-24 16:35:39 -040011266 StringCharacterStream stream(this);
Steve Blocka7e24c12009-10-30 11:49:00 +000011267
11268 uc16* result = NewArray<uc16>(length() + 1);
11269
11270 int i = 0;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011271 while (stream.HasMore()) {
11272 uint16_t character = stream.GetNext();
Steve Blocka7e24c12009-10-30 11:49:00 +000011273 result[i++] = character;
11274 }
11275 result[i] = 0;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000011276 return base::SmartArrayPointer<uc16>(result);
Steve Blocka7e24c12009-10-30 11:49:00 +000011277}
11278
11279
11280const uc16* SeqTwoByteString::SeqTwoByteStringGetData(unsigned start) {
11281 return reinterpret_cast<uc16*>(
11282 reinterpret_cast<char*>(this) - kHeapObjectTag + kHeaderSize) + start;
11283}
11284
11285
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011286void Relocatable::PostGarbageCollectionProcessing(Isolate* isolate) {
Steve Block44f0eee2011-05-26 01:26:41 +010011287 Relocatable* current = isolate->relocatable_top();
Steve Blocka7e24c12009-10-30 11:49:00 +000011288 while (current != NULL) {
11289 current->PostGarbageCollection();
11290 current = current->prev_;
11291 }
11292}
11293
11294
11295// Reserve space for statics needing saving and restoring.
11296int Relocatable::ArchiveSpacePerThread() {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011297 return sizeof(Relocatable*); // NOLINT
Steve Blocka7e24c12009-10-30 11:49:00 +000011298}
11299
11300
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011301// Archive statics that are thread-local.
Ben Murdoch257744e2011-11-30 15:57:28 +000011302char* Relocatable::ArchiveState(Isolate* isolate, char* to) {
Steve Block44f0eee2011-05-26 01:26:41 +010011303 *reinterpret_cast<Relocatable**>(to) = isolate->relocatable_top();
11304 isolate->set_relocatable_top(NULL);
Steve Blocka7e24c12009-10-30 11:49:00 +000011305 return to + ArchiveSpacePerThread();
11306}
11307
11308
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011309// Restore statics that are thread-local.
Ben Murdoch257744e2011-11-30 15:57:28 +000011310char* Relocatable::RestoreState(Isolate* isolate, char* from) {
Steve Block44f0eee2011-05-26 01:26:41 +010011311 isolate->set_relocatable_top(*reinterpret_cast<Relocatable**>(from));
Steve Blocka7e24c12009-10-30 11:49:00 +000011312 return from + ArchiveSpacePerThread();
11313}
11314
11315
11316char* Relocatable::Iterate(ObjectVisitor* v, char* thread_storage) {
11317 Relocatable* top = *reinterpret_cast<Relocatable**>(thread_storage);
11318 Iterate(v, top);
11319 return thread_storage + ArchiveSpacePerThread();
11320}
11321
11322
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011323void Relocatable::Iterate(Isolate* isolate, ObjectVisitor* v) {
Steve Block44f0eee2011-05-26 01:26:41 +010011324 Iterate(v, isolate->relocatable_top());
Steve Blocka7e24c12009-10-30 11:49:00 +000011325}
11326
11327
11328void Relocatable::Iterate(ObjectVisitor* v, Relocatable* top) {
11329 Relocatable* current = top;
11330 while (current != NULL) {
11331 current->IterateInstance(v);
11332 current = current->prev_;
11333 }
11334}
11335
11336
Steve Block44f0eee2011-05-26 01:26:41 +010011337FlatStringReader::FlatStringReader(Isolate* isolate, Handle<String> str)
11338 : Relocatable(isolate),
11339 str_(str.location()),
Steve Blocka7e24c12009-10-30 11:49:00 +000011340 length_(str->length()) {
11341 PostGarbageCollection();
11342}
11343
11344
Steve Block44f0eee2011-05-26 01:26:41 +010011345FlatStringReader::FlatStringReader(Isolate* isolate, Vector<const char> input)
11346 : Relocatable(isolate),
11347 str_(0),
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011348 is_one_byte_(true),
Steve Blocka7e24c12009-10-30 11:49:00 +000011349 length_(input.length()),
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011350 start_(input.start()) {}
Steve Blocka7e24c12009-10-30 11:49:00 +000011351
11352
11353void FlatStringReader::PostGarbageCollection() {
11354 if (str_ == NULL) return;
11355 Handle<String> str(str_);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011356 DCHECK(str->IsFlat());
11357 DisallowHeapAllocation no_gc;
11358 // This does not actually prevent the vector from being relocated later.
Ben Murdoch69a99ed2011-11-30 16:03:39 +000011359 String::FlatContent content = str->GetFlatContent();
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011360 DCHECK(content.IsFlat());
11361 is_one_byte_ = content.IsOneByte();
11362 if (is_one_byte_) {
11363 start_ = content.ToOneByteVector().start();
Steve Blocka7e24c12009-10-30 11:49:00 +000011364 } else {
Ben Murdoch69a99ed2011-11-30 16:03:39 +000011365 start_ = content.ToUC16Vector().start();
Steve Blocka7e24c12009-10-30 11:49:00 +000011366 }
11367}
11368
11369
Emily Bernierd0a1eb72015-03-24 16:35:39 -040011370void ConsStringIterator::Initialize(ConsString* cons_string, int offset) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011371 DCHECK(cons_string != NULL);
11372 root_ = cons_string;
11373 consumed_ = offset;
11374 // Force stack blown condition to trigger restart.
11375 depth_ = 1;
11376 maximum_depth_ = kStackSize + depth_;
11377 DCHECK(StackBlown());
Steve Blocka7e24c12009-10-30 11:49:00 +000011378}
11379
11380
Emily Bernierd0a1eb72015-03-24 16:35:39 -040011381String* ConsStringIterator::Continue(int* offset_out) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011382 DCHECK(depth_ != 0);
11383 DCHECK_EQ(0, *offset_out);
11384 bool blew_stack = StackBlown();
11385 String* string = NULL;
11386 // Get the next leaf if there is one.
11387 if (!blew_stack) string = NextLeaf(&blew_stack);
11388 // Restart search from root.
11389 if (blew_stack) {
11390 DCHECK(string == NULL);
11391 string = Search(offset_out);
Steve Blocka7e24c12009-10-30 11:49:00 +000011392 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011393 // Ensure future calls return null immediately.
11394 if (string == NULL) Reset(NULL);
11395 return string;
Steve Blocka7e24c12009-10-30 11:49:00 +000011396}
11397
11398
Emily Bernierd0a1eb72015-03-24 16:35:39 -040011399String* ConsStringIterator::Search(int* offset_out) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011400 ConsString* cons_string = root_;
11401 // Reset the stack, pushing the root string.
11402 depth_ = 1;
11403 maximum_depth_ = 1;
11404 frames_[0] = cons_string;
11405 const int consumed = consumed_;
11406 int offset = 0;
Steve Blocka7e24c12009-10-30 11:49:00 +000011407 while (true) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011408 // Loop until the string is found which contains the target offset.
11409 String* string = cons_string->first();
11410 int length = string->length();
11411 int32_t type;
11412 if (consumed < offset + length) {
11413 // Target offset is in the left branch.
11414 // Keep going if we're still in a ConString.
11415 type = string->map()->instance_type();
11416 if ((type & kStringRepresentationMask) == kConsStringTag) {
11417 cons_string = ConsString::cast(string);
11418 PushLeft(cons_string);
Steve Blocka7e24c12009-10-30 11:49:00 +000011419 continue;
Steve Blocka7e24c12009-10-30 11:49:00 +000011420 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011421 // Tell the stack we're done descending.
11422 AdjustMaximumDepth();
Steve Blocka7e24c12009-10-30 11:49:00 +000011423 } else {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011424 // Descend right.
11425 // Update progress through the string.
11426 offset += length;
11427 // Keep going if we're still in a ConString.
11428 string = cons_string->second();
11429 type = string->map()->instance_type();
11430 if ((type & kStringRepresentationMask) == kConsStringTag) {
11431 cons_string = ConsString::cast(string);
11432 PushRight(cons_string);
11433 continue;
Steve Blocka7e24c12009-10-30 11:49:00 +000011434 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011435 // Need this to be updated for the current string.
11436 length = string->length();
11437 // Account for the possibility of an empty right leaf.
11438 // This happens only if we have asked for an offset outside the string.
11439 if (length == 0) {
11440 // Reset so future operations will return null immediately.
11441 Reset(NULL);
11442 return NULL;
11443 }
11444 // Tell the stack we're done descending.
11445 AdjustMaximumDepth();
11446 // Pop stack so next iteration is in correct place.
11447 Pop();
11448 }
11449 DCHECK(length != 0);
11450 // Adjust return values and exit.
11451 consumed_ = offset + length;
11452 *offset_out = consumed - offset;
11453 return string;
11454 }
11455 UNREACHABLE();
11456 return NULL;
11457}
11458
11459
Emily Bernierd0a1eb72015-03-24 16:35:39 -040011460String* ConsStringIterator::NextLeaf(bool* blew_stack) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011461 while (true) {
11462 // Tree traversal complete.
11463 if (depth_ == 0) {
11464 *blew_stack = false;
11465 return NULL;
11466 }
11467 // We've lost track of higher nodes.
11468 if (StackBlown()) {
11469 *blew_stack = true;
11470 return NULL;
11471 }
11472 // Go right.
11473 ConsString* cons_string = frames_[OffsetForDepth(depth_ - 1)];
11474 String* string = cons_string->second();
11475 int32_t type = string->map()->instance_type();
11476 if ((type & kStringRepresentationMask) != kConsStringTag) {
11477 // Pop stack so next iteration is in correct place.
11478 Pop();
11479 int length = string->length();
11480 // Could be a flattened ConsString.
11481 if (length == 0) continue;
11482 consumed_ += length;
11483 return string;
11484 }
11485 cons_string = ConsString::cast(string);
11486 PushRight(cons_string);
11487 // Need to traverse all the way left.
11488 while (true) {
11489 // Continue left.
11490 string = cons_string->first();
11491 type = string->map()->instance_type();
11492 if ((type & kStringRepresentationMask) != kConsStringTag) {
11493 AdjustMaximumDepth();
11494 int length = string->length();
11495 DCHECK(length != 0);
11496 consumed_ += length;
11497 return string;
11498 }
11499 cons_string = ConsString::cast(string);
11500 PushLeft(cons_string);
Steve Blocka7e24c12009-10-30 11:49:00 +000011501 }
11502 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011503 UNREACHABLE();
11504 return NULL;
Steve Blocka7e24c12009-10-30 11:49:00 +000011505}
11506
11507
Steve Blocka7e24c12009-10-30 11:49:00 +000011508uint16_t ConsString::ConsStringGet(int index) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011509 DCHECK(index >= 0 && index < this->length());
Steve Blocka7e24c12009-10-30 11:49:00 +000011510
11511 // Check for a flattened cons string
11512 if (second()->length() == 0) {
11513 String* left = first();
11514 return left->Get(index);
11515 }
11516
11517 String* string = String::cast(this);
11518
11519 while (true) {
11520 if (StringShape(string).IsCons()) {
11521 ConsString* cons_string = ConsString::cast(string);
11522 String* left = cons_string->first();
11523 if (left->length() > index) {
11524 string = left;
11525 } else {
11526 index -= left->length();
11527 string = cons_string->second();
11528 }
11529 } else {
11530 return string->Get(index);
11531 }
11532 }
11533
11534 UNREACHABLE();
11535 return 0;
11536}
11537
11538
Ben Murdoch69a99ed2011-11-30 16:03:39 +000011539uint16_t SlicedString::SlicedStringGet(int index) {
11540 return parent()->Get(offset() + index);
11541}
11542
11543
Steve Blocka7e24c12009-10-30 11:49:00 +000011544template <typename sinkchar>
11545void String::WriteToFlat(String* src,
11546 sinkchar* sink,
11547 int f,
11548 int t) {
11549 String* source = src;
11550 int from = f;
11551 int to = t;
11552 while (true) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011553 DCHECK(0 <= from && from <= to && to <= source->length());
Steve Blocka7e24c12009-10-30 11:49:00 +000011554 switch (StringShape(source).full_representation_tag()) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011555 case kOneByteStringTag | kExternalStringTag: {
11556 CopyChars(sink, ExternalOneByteString::cast(source)->GetChars() + from,
Steve Blocka7e24c12009-10-30 11:49:00 +000011557 to - from);
11558 return;
11559 }
11560 case kTwoByteStringTag | kExternalStringTag: {
11561 const uc16* data =
Ben Murdoch3ef787d2012-04-12 10:51:47 +010011562 ExternalTwoByteString::cast(source)->GetChars();
Steve Blocka7e24c12009-10-30 11:49:00 +000011563 CopyChars(sink,
11564 data + from,
11565 to - from);
11566 return;
11567 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011568 case kOneByteStringTag | kSeqStringTag: {
Steve Blocka7e24c12009-10-30 11:49:00 +000011569 CopyChars(sink,
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011570 SeqOneByteString::cast(source)->GetChars() + from,
Steve Blocka7e24c12009-10-30 11:49:00 +000011571 to - from);
11572 return;
11573 }
11574 case kTwoByteStringTag | kSeqStringTag: {
11575 CopyChars(sink,
11576 SeqTwoByteString::cast(source)->GetChars() + from,
11577 to - from);
11578 return;
11579 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011580 case kOneByteStringTag | kConsStringTag:
Steve Blocka7e24c12009-10-30 11:49:00 +000011581 case kTwoByteStringTag | kConsStringTag: {
11582 ConsString* cons_string = ConsString::cast(source);
11583 String* first = cons_string->first();
11584 int boundary = first->length();
11585 if (to - boundary >= boundary - from) {
11586 // Right hand side is longer. Recurse over left.
11587 if (from < boundary) {
11588 WriteToFlat(first, sink, from, boundary);
11589 sink += boundary - from;
11590 from = 0;
11591 } else {
11592 from -= boundary;
11593 }
11594 to -= boundary;
11595 source = cons_string->second();
11596 } else {
11597 // Left hand side is longer. Recurse over right.
11598 if (to > boundary) {
11599 String* second = cons_string->second();
Ben Murdoch3ef787d2012-04-12 10:51:47 +010011600 // When repeatedly appending to a string, we get a cons string that
11601 // is unbalanced to the left, a list, essentially. We inline the
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011602 // common case of sequential one-byte right child.
Ben Murdoch3ef787d2012-04-12 10:51:47 +010011603 if (to - boundary == 1) {
11604 sink[boundary - from] = static_cast<sinkchar>(second->Get(0));
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011605 } else if (second->IsSeqOneByteString()) {
Ben Murdoch3ef787d2012-04-12 10:51:47 +010011606 CopyChars(sink + boundary - from,
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011607 SeqOneByteString::cast(second)->GetChars(),
Steve Blocka7e24c12009-10-30 11:49:00 +000011608 to - boundary);
Ben Murdoch3ef787d2012-04-12 10:51:47 +010011609 } else {
11610 WriteToFlat(second,
11611 sink + boundary - from,
11612 0,
11613 to - boundary);
11614 }
Steve Blocka7e24c12009-10-30 11:49:00 +000011615 to = boundary;
11616 }
11617 source = first;
11618 }
11619 break;
11620 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011621 case kOneByteStringTag | kSlicedStringTag:
Ben Murdoch69a99ed2011-11-30 16:03:39 +000011622 case kTwoByteStringTag | kSlicedStringTag: {
11623 SlicedString* slice = SlicedString::cast(source);
11624 unsigned offset = slice->offset();
11625 WriteToFlat(slice->parent(), sink, from + offset, to + offset);
11626 return;
11627 }
Steve Blocka7e24c12009-10-30 11:49:00 +000011628 }
11629 }
11630}
11631
11632
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011633
11634template <typename SourceChar>
11635static void CalculateLineEndsImpl(Isolate* isolate,
11636 List<int>* line_ends,
11637 Vector<const SourceChar> src,
11638 bool include_ending_line) {
11639 const int src_len = src.length();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000011640 UnicodeCache* cache = isolate->unicode_cache();
11641 for (int i = 0; i < src_len - 1; i++) {
11642 SourceChar current = src[i];
11643 SourceChar next = src[i + 1];
11644 if (cache->IsLineTerminatorSequence(current, next)) line_ends->Add(i);
11645 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011646
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000011647 if (src_len > 0 && cache->IsLineTerminatorSequence(src[src_len - 1], 0)) {
11648 line_ends->Add(src_len - 1);
11649 }
11650 if (include_ending_line) {
11651 // Include one character beyond the end of script. The rewriter uses that
11652 // position for the implicit return statement.
11653 line_ends->Add(src_len);
Steve Blocka7e24c12009-10-30 11:49:00 +000011654 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011655}
11656
11657
11658Handle<FixedArray> String::CalculateLineEnds(Handle<String> src,
11659 bool include_ending_line) {
11660 src = Flatten(src);
11661 // Rough estimate of line count based on a roughly estimated average
11662 // length of (unpacked) code.
11663 int line_count_estimate = src->length() >> 4;
11664 List<int> line_ends(line_count_estimate);
11665 Isolate* isolate = src->GetIsolate();
11666 { DisallowHeapAllocation no_allocation; // ensure vectors stay valid.
11667 // Dispatch on type of strings.
11668 String::FlatContent content = src->GetFlatContent();
11669 DCHECK(content.IsFlat());
11670 if (content.IsOneByte()) {
11671 CalculateLineEndsImpl(isolate,
11672 &line_ends,
11673 content.ToOneByteVector(),
11674 include_ending_line);
11675 } else {
11676 CalculateLineEndsImpl(isolate,
11677 &line_ends,
11678 content.ToUC16Vector(),
11679 include_ending_line);
11680 }
11681 }
11682 int line_count = line_ends.length();
11683 Handle<FixedArray> array = isolate->factory()->NewFixedArray(line_count);
11684 for (int i = 0; i < line_count; i++) {
11685 array->set(i, Smi::FromInt(line_ends[i]));
11686 }
11687 return array;
Steve Blocka7e24c12009-10-30 11:49:00 +000011688}
11689
11690
11691// Compares the contents of two strings by reading and comparing
11692// int-sized blocks of characters.
11693template <typename Char>
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011694static inline bool CompareRawStringContents(const Char* const a,
11695 const Char* const b,
11696 int length) {
11697 return CompareChars(a, b, length) == 0;
11698}
11699
11700
11701template<typename Chars1, typename Chars2>
11702class RawStringComparator : public AllStatic {
11703 public:
11704 static inline bool compare(const Chars1* a, const Chars2* b, int len) {
11705 DCHECK(sizeof(Chars1) != sizeof(Chars2));
11706 for (int i = 0; i < len; i++) {
11707 if (a[i] != b[i]) {
Steve Blocka7e24c12009-10-30 11:49:00 +000011708 return false;
11709 }
11710 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011711 return true;
Steve Blocka7e24c12009-10-30 11:49:00 +000011712 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011713};
Steve Blocka7e24c12009-10-30 11:49:00 +000011714
11715
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011716template<>
11717class RawStringComparator<uint16_t, uint16_t> {
11718 public:
11719 static inline bool compare(const uint16_t* a, const uint16_t* b, int len) {
11720 return CompareRawStringContents(a, b, len);
Steve Blocka7e24c12009-10-30 11:49:00 +000011721 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011722};
11723
11724
11725template<>
11726class RawStringComparator<uint8_t, uint8_t> {
11727 public:
11728 static inline bool compare(const uint8_t* a, const uint8_t* b, int len) {
11729 return CompareRawStringContents(a, b, len);
11730 }
11731};
11732
11733
11734class StringComparator {
11735 class State {
11736 public:
Emily Bernierd0a1eb72015-03-24 16:35:39 -040011737 State() : is_one_byte_(true), length_(0), buffer8_(NULL) {}
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011738
Emily Bernierd0a1eb72015-03-24 16:35:39 -040011739 void Init(String* string) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011740 ConsString* cons_string = String::VisitFlat(this, string);
Emily Bernierd0a1eb72015-03-24 16:35:39 -040011741 iter_.Reset(cons_string);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011742 if (cons_string != NULL) {
11743 int offset;
Emily Bernierd0a1eb72015-03-24 16:35:39 -040011744 string = iter_.Next(&offset);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011745 String::VisitFlat(this, string, offset);
11746 }
11747 }
11748
11749 inline void VisitOneByteString(const uint8_t* chars, int length) {
11750 is_one_byte_ = true;
11751 buffer8_ = chars;
11752 length_ = length;
11753 }
11754
11755 inline void VisitTwoByteString(const uint16_t* chars, int length) {
11756 is_one_byte_ = false;
11757 buffer16_ = chars;
11758 length_ = length;
11759 }
11760
11761 void Advance(int consumed) {
11762 DCHECK(consumed <= length_);
11763 // Still in buffer.
11764 if (length_ != consumed) {
11765 if (is_one_byte_) {
11766 buffer8_ += consumed;
11767 } else {
11768 buffer16_ += consumed;
11769 }
11770 length_ -= consumed;
11771 return;
11772 }
11773 // Advance state.
11774 int offset;
Emily Bernierd0a1eb72015-03-24 16:35:39 -040011775 String* next = iter_.Next(&offset);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011776 DCHECK_EQ(0, offset);
11777 DCHECK(next != NULL);
11778 String::VisitFlat(this, next);
11779 }
11780
Emily Bernierd0a1eb72015-03-24 16:35:39 -040011781 ConsStringIterator iter_;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011782 bool is_one_byte_;
11783 int length_;
11784 union {
11785 const uint8_t* buffer8_;
11786 const uint16_t* buffer16_;
11787 };
11788
11789 private:
Emily Bernierd0a1eb72015-03-24 16:35:39 -040011790 DISALLOW_COPY_AND_ASSIGN(State);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011791 };
11792
11793 public:
Emily Bernierd0a1eb72015-03-24 16:35:39 -040011794 inline StringComparator() {}
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011795
11796 template<typename Chars1, typename Chars2>
11797 static inline bool Equals(State* state_1, State* state_2, int to_check) {
11798 const Chars1* a = reinterpret_cast<const Chars1*>(state_1->buffer8_);
11799 const Chars2* b = reinterpret_cast<const Chars2*>(state_2->buffer8_);
11800 return RawStringComparator<Chars1, Chars2>::compare(a, b, to_check);
11801 }
11802
11803 bool Equals(String* string_1, String* string_2) {
11804 int length = string_1->length();
11805 state_1_.Init(string_1);
11806 state_2_.Init(string_2);
11807 while (true) {
11808 int to_check = Min(state_1_.length_, state_2_.length_);
11809 DCHECK(to_check > 0 && to_check <= length);
11810 bool is_equal;
11811 if (state_1_.is_one_byte_) {
11812 if (state_2_.is_one_byte_) {
11813 is_equal = Equals<uint8_t, uint8_t>(&state_1_, &state_2_, to_check);
11814 } else {
11815 is_equal = Equals<uint8_t, uint16_t>(&state_1_, &state_2_, to_check);
11816 }
11817 } else {
11818 if (state_2_.is_one_byte_) {
11819 is_equal = Equals<uint16_t, uint8_t>(&state_1_, &state_2_, to_check);
11820 } else {
11821 is_equal = Equals<uint16_t, uint16_t>(&state_1_, &state_2_, to_check);
11822 }
11823 }
11824 // Looping done.
11825 if (!is_equal) return false;
11826 length -= to_check;
11827 // Exit condition. Strings are equal.
11828 if (length == 0) return true;
11829 state_1_.Advance(to_check);
11830 state_2_.Advance(to_check);
11831 }
11832 }
11833
11834 private:
11835 State state_1_;
11836 State state_2_;
Emily Bernierd0a1eb72015-03-24 16:35:39 -040011837
11838 DISALLOW_COPY_AND_ASSIGN(StringComparator);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011839};
Steve Blocka7e24c12009-10-30 11:49:00 +000011840
11841
Steve Blocka7e24c12009-10-30 11:49:00 +000011842bool String::SlowEquals(String* other) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011843 DisallowHeapAllocation no_gc;
Steve Blocka7e24c12009-10-30 11:49:00 +000011844 // Fast check: negative check with lengths.
11845 int len = length();
11846 if (len != other->length()) return false;
11847 if (len == 0) return true;
11848
11849 // Fast check: if hash code is computed for both strings
11850 // a fast negative check can be performed.
11851 if (HasHashCode() && other->HasHashCode()) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011852#ifdef ENABLE_SLOW_DCHECKS
Ben Murdochc7cc0282012-03-05 14:35:55 +000011853 if (FLAG_enable_slow_asserts) {
11854 if (Hash() != other->Hash()) {
11855 bool found_difference = false;
11856 for (int i = 0; i < len; i++) {
11857 if (Get(i) != other->Get(i)) {
11858 found_difference = true;
11859 break;
11860 }
11861 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011862 DCHECK(found_difference);
Ben Murdochc7cc0282012-03-05 14:35:55 +000011863 }
11864 }
11865#endif
Steve Blocka7e24c12009-10-30 11:49:00 +000011866 if (Hash() != other->Hash()) return false;
11867 }
11868
Leon Clarkef7060e22010-06-03 12:02:55 +010011869 // We know the strings are both non-empty. Compare the first chars
11870 // before we try to flatten the strings.
11871 if (this->Get(0) != other->Get(0)) return false;
11872
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011873 if (IsSeqOneByteString() && other->IsSeqOneByteString()) {
11874 const uint8_t* str1 = SeqOneByteString::cast(this)->GetChars();
11875 const uint8_t* str2 = SeqOneByteString::cast(other)->GetChars();
11876 return CompareRawStringContents(str1, str2, len);
Steve Blocka7e24c12009-10-30 11:49:00 +000011877 }
11878
Emily Bernierd0a1eb72015-03-24 16:35:39 -040011879 StringComparator comparator;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011880 return comparator.Equals(this, other);
11881}
11882
11883
11884bool String::SlowEquals(Handle<String> one, Handle<String> two) {
11885 // Fast check: negative check with lengths.
11886 int one_length = one->length();
11887 if (one_length != two->length()) return false;
11888 if (one_length == 0) return true;
11889
11890 // Fast check: if hash code is computed for both strings
11891 // a fast negative check can be performed.
11892 if (one->HasHashCode() && two->HasHashCode()) {
11893#ifdef ENABLE_SLOW_DCHECKS
11894 if (FLAG_enable_slow_asserts) {
11895 if (one->Hash() != two->Hash()) {
11896 bool found_difference = false;
11897 for (int i = 0; i < one_length; i++) {
11898 if (one->Get(i) != two->Get(i)) {
11899 found_difference = true;
11900 break;
11901 }
Steve Blocka7e24c12009-10-30 11:49:00 +000011902 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011903 DCHECK(found_difference);
Steve Blocka7e24c12009-10-30 11:49:00 +000011904 }
11905 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011906#endif
11907 if (one->Hash() != two->Hash()) return false;
11908 }
11909
11910 // We know the strings are both non-empty. Compare the first chars
11911 // before we try to flatten the strings.
11912 if (one->Get(0) != two->Get(0)) return false;
11913
11914 one = String::Flatten(one);
11915 two = String::Flatten(two);
11916
11917 DisallowHeapAllocation no_gc;
11918 String::FlatContent flat1 = one->GetFlatContent();
11919 String::FlatContent flat2 = two->GetFlatContent();
11920
11921 if (flat1.IsOneByte() && flat2.IsOneByte()) {
11922 return CompareRawStringContents(flat1.ToOneByteVector().start(),
11923 flat2.ToOneByteVector().start(),
11924 one_length);
Steve Blocka7e24c12009-10-30 11:49:00 +000011925 } else {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011926 for (int i = 0; i < one_length; i++) {
11927 if (flat1.Get(i) != flat2.Get(i)) return false;
11928 }
11929 return true;
Steve Blocka7e24c12009-10-30 11:49:00 +000011930 }
11931}
11932
11933
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000011934// static
11935ComparisonResult String::Compare(Handle<String> x, Handle<String> y) {
11936 // A few fast case tests before we flatten.
11937 if (x.is_identical_to(y)) {
11938 return ComparisonResult::kEqual;
11939 } else if (y->length() == 0) {
11940 return x->length() == 0 ? ComparisonResult::kEqual
11941 : ComparisonResult::kGreaterThan;
11942 } else if (x->length() == 0) {
11943 return ComparisonResult::kLessThan;
Steve Blocka7e24c12009-10-30 11:49:00 +000011944 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000011945
11946 int const d = x->Get(0) - y->Get(0);
11947 if (d < 0) {
11948 return ComparisonResult::kLessThan;
11949 } else if (d > 0) {
11950 return ComparisonResult::kGreaterThan;
11951 }
11952
11953 // Slow case.
11954 x = String::Flatten(x);
11955 y = String::Flatten(y);
11956
11957 DisallowHeapAllocation no_gc;
11958 ComparisonResult result = ComparisonResult::kEqual;
11959 int prefix_length = x->length();
11960 if (y->length() < prefix_length) {
11961 prefix_length = y->length();
11962 result = ComparisonResult::kGreaterThan;
11963 } else if (y->length() > prefix_length) {
11964 result = ComparisonResult::kLessThan;
11965 }
11966 int r;
11967 String::FlatContent x_content = x->GetFlatContent();
11968 String::FlatContent y_content = y->GetFlatContent();
11969 if (x_content.IsOneByte()) {
11970 Vector<const uint8_t> x_chars = x_content.ToOneByteVector();
11971 if (y_content.IsOneByte()) {
11972 Vector<const uint8_t> y_chars = y_content.ToOneByteVector();
11973 r = CompareChars(x_chars.start(), y_chars.start(), prefix_length);
11974 } else {
11975 Vector<const uc16> y_chars = y_content.ToUC16Vector();
11976 r = CompareChars(x_chars.start(), y_chars.start(), prefix_length);
11977 }
11978 } else {
11979 Vector<const uc16> x_chars = x_content.ToUC16Vector();
11980 if (y_content.IsOneByte()) {
11981 Vector<const uint8_t> y_chars = y_content.ToOneByteVector();
11982 r = CompareChars(x_chars.start(), y_chars.start(), prefix_length);
11983 } else {
11984 Vector<const uc16> y_chars = y_content.ToUC16Vector();
11985 r = CompareChars(x_chars.start(), y_chars.start(), prefix_length);
11986 }
11987 }
11988 if (r < 0) {
11989 result = ComparisonResult::kLessThan;
11990 } else if (r > 0) {
11991 result = ComparisonResult::kGreaterThan;
11992 }
11993 return result;
Steve Blocka7e24c12009-10-30 11:49:00 +000011994}
11995
11996
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011997bool String::IsUtf8EqualTo(Vector<const char> str, bool allow_prefix_match) {
Steve Blocka7e24c12009-10-30 11:49:00 +000011998 int slen = length();
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011999 // Can't check exact length equality, but we can check bounds.
12000 int str_len = str.length();
12001 if (!allow_prefix_match &&
12002 (str_len < slen ||
12003 str_len > slen*static_cast<int>(unibrow::Utf8::kMaxEncodedSize))) {
12004 return false;
12005 }
Steve Blocka7e24c12009-10-30 11:49:00 +000012006 int i;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000012007 size_t remaining_in_str = static_cast<size_t>(str_len);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012008 const uint8_t* utf8_data = reinterpret_cast<const uint8_t*>(str.start());
12009 for (i = 0; i < slen && remaining_in_str > 0; i++) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000012010 size_t cursor = 0;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012011 uint32_t r = unibrow::Utf8::ValueOf(utf8_data, remaining_in_str, &cursor);
12012 DCHECK(cursor > 0 && cursor <= remaining_in_str);
Ben Murdoch3ef787d2012-04-12 10:51:47 +010012013 if (r > unibrow::Utf16::kMaxNonSurrogateCharCode) {
12014 if (i > slen - 1) return false;
12015 if (Get(i++) != unibrow::Utf16::LeadSurrogate(r)) return false;
12016 if (Get(i) != unibrow::Utf16::TrailSurrogate(r)) return false;
12017 } else {
12018 if (Get(i) != r) return false;
12019 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012020 utf8_data += cursor;
12021 remaining_in_str -= cursor;
Steve Blocka7e24c12009-10-30 11:49:00 +000012022 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012023 return (allow_prefix_match || i == slen) && remaining_in_str == 0;
Steve Blocka7e24c12009-10-30 11:49:00 +000012024}
12025
12026
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012027bool String::IsOneByteEqualTo(Vector<const uint8_t> str) {
Steve Block9fac8402011-05-12 15:51:54 +010012028 int slen = length();
12029 if (str.length() != slen) return false;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012030 DisallowHeapAllocation no_gc;
Ben Murdoch69a99ed2011-11-30 16:03:39 +000012031 FlatContent content = GetFlatContent();
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012032 if (content.IsOneByte()) {
12033 return CompareChars(content.ToOneByteVector().start(),
Ben Murdoch69a99ed2011-11-30 16:03:39 +000012034 str.start(), slen) == 0;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000012035 }
12036 for (int i = 0; i < slen; i++) {
12037 if (Get(i) != static_cast<uint16_t>(str[i])) return false;
Steve Block9fac8402011-05-12 15:51:54 +010012038 }
12039 return true;
12040}
12041
12042
12043bool String::IsTwoByteEqualTo(Vector<const uc16> str) {
12044 int slen = length();
12045 if (str.length() != slen) return false;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012046 DisallowHeapAllocation no_gc;
Ben Murdoch69a99ed2011-11-30 16:03:39 +000012047 FlatContent content = GetFlatContent();
12048 if (content.IsTwoByte()) {
12049 return CompareChars(content.ToUC16Vector().start(), str.start(), slen) == 0;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000012050 }
Steve Block9fac8402011-05-12 15:51:54 +010012051 for (int i = 0; i < slen; i++) {
12052 if (Get(i) != str[i]) return false;
12053 }
12054 return true;
12055}
12056
12057
Steve Blocka7e24c12009-10-30 11:49:00 +000012058uint32_t String::ComputeAndSetHash() {
12059 // Should only be called if hash code has not yet been computed.
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012060 DCHECK(!HasHashCode());
Steve Blocka7e24c12009-10-30 11:49:00 +000012061
12062 // Store the hash code in the object.
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012063 uint32_t field = IteratingStringHasher::Hash(this, GetHeap()->HashSeed());
Steve Blockd0582a62009-12-15 09:54:21 +000012064 set_hash_field(field);
Steve Blocka7e24c12009-10-30 11:49:00 +000012065
12066 // Check the hash code is there.
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012067 DCHECK(HasHashCode());
Steve Blocka7e24c12009-10-30 11:49:00 +000012068 uint32_t result = field >> kHashShift;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012069 DCHECK(result != 0); // Ensure that the hash value of 0 is never computed.
Steve Blocka7e24c12009-10-30 11:49:00 +000012070 return result;
12071}
12072
12073
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012074bool String::ComputeArrayIndex(uint32_t* index) {
12075 int length = this->length();
Steve Blocka7e24c12009-10-30 11:49:00 +000012076 if (length == 0 || length > kMaxArrayIndexSize) return false;
Emily Bernierd0a1eb72015-03-24 16:35:39 -040012077 StringCharacterStream stream(this);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012078 return StringToArrayIndex(&stream, index);
Steve Blocka7e24c12009-10-30 11:49:00 +000012079}
12080
12081
12082bool String::SlowAsArrayIndex(uint32_t* index) {
12083 if (length() <= kMaxCachedArrayIndexLength) {
12084 Hash(); // force computation of hash code
Steve Blockd0582a62009-12-15 09:54:21 +000012085 uint32_t field = hash_field();
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +010012086 if ((field & kIsNotArrayIndexMask) != 0) return false;
Steve Blockd0582a62009-12-15 09:54:21 +000012087 // Isolate the array index form the full hash field.
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012088 *index = ArrayIndexValueBits::decode(field);
Steve Blocka7e24c12009-10-30 11:49:00 +000012089 return true;
12090 } else {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012091 return ComputeArrayIndex(index);
Steve Blocka7e24c12009-10-30 11:49:00 +000012092 }
12093}
12094
12095
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012096Handle<String> SeqString::Truncate(Handle<SeqString> string, int new_length) {
12097 int new_size, old_size;
12098 int old_length = string->length();
12099 if (old_length <= new_length) return string;
12100
12101 if (string->IsSeqOneByteString()) {
12102 old_size = SeqOneByteString::SizeFor(old_length);
12103 new_size = SeqOneByteString::SizeFor(new_length);
12104 } else {
12105 DCHECK(string->IsSeqTwoByteString());
12106 old_size = SeqTwoByteString::SizeFor(old_length);
12107 new_size = SeqTwoByteString::SizeFor(new_length);
12108 }
12109
12110 int delta = old_size - new_size;
12111
12112 Address start_of_string = string->address();
12113 DCHECK_OBJECT_ALIGNED(start_of_string);
12114 DCHECK_OBJECT_ALIGNED(start_of_string + new_size);
12115
12116 Heap* heap = string->GetHeap();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000012117 // Sizes are pointer size aligned, so that we can use filler objects
12118 // that are a multiple of pointer size.
12119 heap->CreateFillerObjectAt(start_of_string + new_size, delta);
12120 heap->AdjustLiveBytes(*string, -delta, Heap::CONCURRENT_TO_SWEEPER);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012121
12122 // We are storing the new length using release store after creating a filler
12123 // for the left-over space to avoid races with the sweeper thread.
12124 string->synchronized_set_length(new_length);
12125
12126 if (new_length == 0) return heap->isolate()->factory()->empty_string();
12127 return string;
12128}
12129
12130
Iain Merrick9ac36c92010-09-13 15:29:50 +010012131uint32_t StringHasher::MakeArrayIndexHash(uint32_t value, int length) {
Kristian Monsen80d68ea2010-09-08 11:05:35 +010012132 // For array indexes mix the length into the hash as an array index could
12133 // be zero.
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012134 DCHECK(length > 0);
12135 DCHECK(length <= String::kMaxArrayIndexSize);
12136 DCHECK(TenToThe(String::kMaxCachedArrayIndexLength) <
Kristian Monsen80d68ea2010-09-08 11:05:35 +010012137 (1 << String::kArrayIndexValueBits));
Iain Merrick9ac36c92010-09-13 15:29:50 +010012138
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012139 value <<= String::ArrayIndexValueBits::kShift;
12140 value |= length << String::ArrayIndexLengthBits::kShift;
Iain Merrick9ac36c92010-09-13 15:29:50 +010012141
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012142 DCHECK((value & String::kIsNotArrayIndexMask) == 0);
12143 DCHECK((length > String::kMaxCachedArrayIndexLength) ||
Iain Merrick9ac36c92010-09-13 15:29:50 +010012144 (value & String::kContainsCachedArrayIndexMask) == 0);
Kristian Monsen80d68ea2010-09-08 11:05:35 +010012145 return value;
Steve Blocka7e24c12009-10-30 11:49:00 +000012146}
12147
12148
12149uint32_t StringHasher::GetHashField() {
Steve Blockd0582a62009-12-15 09:54:21 +000012150 if (length_ <= String::kMaxHashCalcLength) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012151 if (is_array_index_) {
12152 return MakeArrayIndexHash(array_index_, length_);
Steve Blocka7e24c12009-10-30 11:49:00 +000012153 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012154 return (GetHashCore(raw_running_hash_) << String::kHashShift) |
12155 String::kIsNotArrayIndexMask;
Steve Blocka7e24c12009-10-30 11:49:00 +000012156 } else {
Kristian Monsen80d68ea2010-09-08 11:05:35 +010012157 return (length_ << String::kHashShift) | String::kIsNotArrayIndexMask;
Steve Blocka7e24c12009-10-30 11:49:00 +000012158 }
12159}
12160
12161
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012162uint32_t StringHasher::ComputeUtf8Hash(Vector<const char> chars,
12163 uint32_t seed,
12164 int* utf16_length_out) {
12165 int vector_length = chars.length();
12166 // Handle some edge cases
12167 if (vector_length <= 1) {
12168 DCHECK(vector_length == 0 ||
12169 static_cast<uint8_t>(chars.start()[0]) <=
12170 unibrow::Utf8::kMaxOneByteChar);
12171 *utf16_length_out = vector_length;
12172 return HashSequentialString(chars.start(), vector_length, seed);
Steve Blocka7e24c12009-10-30 11:49:00 +000012173 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012174 // Start with a fake length which won't affect computation.
12175 // It will be updated later.
12176 StringHasher hasher(String::kMaxArrayIndexSize, seed);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000012177 size_t remaining = static_cast<size_t>(vector_length);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012178 const uint8_t* stream = reinterpret_cast<const uint8_t*>(chars.start());
12179 int utf16_length = 0;
12180 bool is_index = true;
12181 DCHECK(hasher.is_array_index_);
12182 while (remaining > 0) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000012183 size_t consumed = 0;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012184 uint32_t c = unibrow::Utf8::ValueOf(stream, remaining, &consumed);
12185 DCHECK(consumed > 0 && consumed <= remaining);
12186 stream += consumed;
12187 remaining -= consumed;
12188 bool is_two_characters = c > unibrow::Utf16::kMaxNonSurrogateCharCode;
12189 utf16_length += is_two_characters ? 2 : 1;
12190 // No need to keep hashing. But we do need to calculate utf16_length.
12191 if (utf16_length > String::kMaxHashCalcLength) continue;
12192 if (is_two_characters) {
12193 uint16_t c1 = unibrow::Utf16::LeadSurrogate(c);
12194 uint16_t c2 = unibrow::Utf16::TrailSurrogate(c);
12195 hasher.AddCharacter(c1);
12196 hasher.AddCharacter(c2);
12197 if (is_index) is_index = hasher.UpdateIndex(c1);
12198 if (is_index) is_index = hasher.UpdateIndex(c2);
12199 } else {
12200 hasher.AddCharacter(c);
12201 if (is_index) is_index = hasher.UpdateIndex(c);
12202 }
Steve Blocka7e24c12009-10-30 11:49:00 +000012203 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012204 *utf16_length_out = static_cast<int>(utf16_length);
12205 // Must set length here so that hash computation is correct.
12206 hasher.length_ = utf16_length;
Steve Blocka7e24c12009-10-30 11:49:00 +000012207 return hasher.GetHashField();
12208}
12209
12210
Emily Bernierd0a1eb72015-03-24 16:35:39 -040012211void IteratingStringHasher::VisitConsString(ConsString* cons_string) {
12212 // Run small ConsStrings through ConsStringIterator.
12213 if (cons_string->length() < 64) {
12214 ConsStringIterator iter(cons_string);
12215 int offset;
12216 String* string;
12217 while (nullptr != (string = iter.Next(&offset))) {
12218 DCHECK_EQ(0, offset);
12219 String::VisitFlat(this, string, 0);
12220 }
12221 return;
12222 }
12223 // Slow case.
12224 const int max_length = String::kMaxHashCalcLength;
12225 int length = std::min(cons_string->length(), max_length);
12226 if (cons_string->HasOnlyOneByteChars()) {
12227 uint8_t* buffer = new uint8_t[length];
12228 String::WriteToFlat(cons_string, buffer, 0, length);
12229 AddCharacters(buffer, length);
12230 delete[] buffer;
12231 } else {
12232 uint16_t* buffer = new uint16_t[length];
12233 String::WriteToFlat(cons_string, buffer, 0, length);
12234 AddCharacters(buffer, length);
12235 delete[] buffer;
12236 }
12237}
12238
12239
Steve Blocka7e24c12009-10-30 11:49:00 +000012240void String::PrintOn(FILE* file) {
12241 int length = this->length();
12242 for (int i = 0; i < length; i++) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012243 PrintF(file, "%c", Get(i));
Steve Blocka7e24c12009-10-30 11:49:00 +000012244 }
12245}
12246
12247
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000012248int Map::Hash() {
12249 // For performance reasons we only hash the 3 most variable fields of a map:
Emily Bernierd0a1eb72015-03-24 16:35:39 -040012250 // constructor, prototype and bit_field2. For predictability reasons we
12251 // use objects' offsets in respective pages for hashing instead of raw
12252 // addresses.
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000012253
12254 // Shift away the tag.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000012255 int hash = ObjectAddressForHashing(GetConstructor()) >> 2;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000012256
12257 // XOR-ing the prototype and constructor directly yields too many zero bits
12258 // when the two pointers are close (which is fairly common).
Emily Bernierd0a1eb72015-03-24 16:35:39 -040012259 // To avoid this we shift the prototype bits relatively to the constructor.
12260 hash ^= ObjectAddressForHashing(prototype()) << (32 - kPageSizeBits);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000012261
12262 return hash ^ (hash >> 16) ^ bit_field2();
12263}
12264
12265
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000012266namespace {
12267
12268bool CheckEquivalent(Map* first, Map* second) {
12269 return first->GetConstructor() == second->GetConstructor() &&
12270 first->prototype() == second->prototype() &&
12271 first->instance_type() == second->instance_type() &&
12272 first->bit_field() == second->bit_field() &&
12273 first->is_extensible() == second->is_extensible() &&
12274 first->is_strong() == second->is_strong() &&
Ben Murdoch097c5b22016-05-18 11:27:45 +010012275 first->new_target_is_base() == second->new_target_is_base() &&
12276 first->has_hidden_prototype() == second->has_hidden_prototype();
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012277}
12278
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000012279} // namespace
12280
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012281
12282bool Map::EquivalentToForTransition(Map* other) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000012283 if (!CheckEquivalent(this, other)) return false;
12284 if (instance_type() == JS_FUNCTION_TYPE) {
12285 // JSFunctions require more checks to ensure that sloppy function is
12286 // not equvalent to strict function.
12287 int nof = Min(NumberOfOwnDescriptors(), other->NumberOfOwnDescriptors());
12288 return instance_descriptors()->IsEqualUpTo(other->instance_descriptors(),
12289 nof);
12290 }
12291 return true;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012292}
12293
12294
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000012295bool Map::EquivalentToForNormalization(Map* other,
12296 PropertyNormalizationMode mode) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000012297 int properties =
12298 mode == CLEAR_INOBJECT_PROPERTIES ? 0 : other->GetInObjectProperties();
12299 return CheckEquivalent(this, other) && bit_field2() == other->bit_field2() &&
12300 GetInObjectProperties() == properties;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012301}
12302
12303
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000012304bool JSFunction::Inlines(SharedFunctionInfo* candidate) {
12305 DisallowHeapAllocation no_gc;
12306 if (shared() == candidate) return true;
12307 if (code()->kind() != Code::OPTIMIZED_FUNCTION) return false;
12308 DeoptimizationInputData* const data =
12309 DeoptimizationInputData::cast(code()->deoptimization_data());
12310 if (data->length() == 0) return false;
12311 FixedArray* const literals = data->LiteralArray();
12312 int const inlined_count = data->InlinedFunctionCount()->value();
12313 for (int i = 0; i < inlined_count; ++i) {
12314 if (SharedFunctionInfo::cast(literals->get(i)) == candidate) {
12315 return true;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012316 }
12317 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000012318 return false;
Steve Block791712a2010-08-27 10:21:07 +010012319}
12320
12321
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012322void JSFunction::MarkForOptimization() {
Emily Bernierd0a1eb72015-03-24 16:35:39 -040012323 Isolate* isolate = GetIsolate();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000012324 // Do not optimize if function contains break points.
12325 if (shared()->HasDebugInfo()) return;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012326 DCHECK(!IsOptimized());
12327 DCHECK(shared()->allows_lazy_compilation() ||
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000012328 !shared()->optimization_disabled());
12329 DCHECK(!shared()->HasDebugInfo());
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012330 set_code_no_write_barrier(
Emily Bernierd0a1eb72015-03-24 16:35:39 -040012331 isolate->builtins()->builtin(Builtins::kCompileOptimized));
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012332 // No write barrier required, since the builtin is part of the root set.
Ben Murdochb0fe1622011-05-05 13:52:32 +010012333}
12334
12335
Emily Bernierd0a1eb72015-03-24 16:35:39 -040012336void JSFunction::AttemptConcurrentOptimization() {
12337 Isolate* isolate = GetIsolate();
12338 if (!isolate->concurrent_recompilation_enabled() ||
12339 isolate->bootstrapper()->IsActive()) {
12340 MarkForOptimization();
12341 return;
12342 }
12343 if (isolate->concurrent_osr_enabled() &&
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000012344 isolate->optimizing_compile_dispatcher()->IsQueuedForOSR(this)) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -040012345 // Do not attempt regular recompilation if we already queued this for OSR.
12346 // TODO(yangguo): This is necessary so that we don't install optimized
12347 // code on a function that is already optimized, since OSR and regular
12348 // recompilation race. This goes away as soon as OSR becomes one-shot.
12349 return;
12350 }
Emily Bernierd0a1eb72015-03-24 16:35:39 -040012351 DCHECK(!IsInOptimizationQueue());
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012352 DCHECK(!IsOptimized());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000012353 DCHECK(shared()->allows_lazy_compilation() ||
12354 !shared()->optimization_disabled());
Emily Bernierd0a1eb72015-03-24 16:35:39 -040012355 DCHECK(isolate->concurrent_recompilation_enabled());
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012356 if (FLAG_trace_concurrent_recompilation) {
12357 PrintF(" ** Marking ");
12358 ShortPrint();
12359 PrintF(" for concurrent recompilation.\n");
Ben Murdoch3ef787d2012-04-12 10:51:47 +010012360 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012361 set_code_no_write_barrier(
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000012362 isolate->builtins()->builtin(Builtins::kCompileOptimizedConcurrent));
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012363 // No write barrier required, since the builtin is part of the root set.
Ben Murdoch3ef787d2012-04-12 10:51:47 +010012364}
12365
12366
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000012367void SharedFunctionInfo::AddSharedCodeToOptimizedCodeMap(
12368 Handle<SharedFunctionInfo> shared, Handle<Code> code) {
12369 Isolate* isolate = shared->GetIsolate();
12370 if (isolate->serializer_enabled()) return;
12371 DCHECK(code->kind() == Code::OPTIMIZED_FUNCTION);
12372 // Empty code maps are unsupported.
12373 if (!shared->OptimizedCodeMapIsCleared()) {
12374 Handle<WeakCell> cell = isolate->factory()->NewWeakCell(code);
12375 // A collection may have occured and cleared the optimized code map in the
12376 // allocation above.
12377 if (!shared->OptimizedCodeMapIsCleared()) {
12378 shared->optimized_code_map()->set(kSharedCodeIndex, *cell);
12379 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012380 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012381}
12382
12383
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000012384void SharedFunctionInfo::AddToOptimizedCodeMapInternal(
12385 Handle<SharedFunctionInfo> shared, Handle<Context> native_context,
12386 Handle<HeapObject> code, Handle<LiteralsArray> literals,
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012387 BailoutId osr_ast_id) {
12388 Isolate* isolate = shared->GetIsolate();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000012389 if (isolate->serializer_enabled()) return;
12390 DCHECK(*code == isolate->heap()->undefined_value() ||
12391 !shared->SearchOptimizedCodeMap(*native_context, osr_ast_id).code);
12392 DCHECK(*code == isolate->heap()->undefined_value() ||
12393 Code::cast(*code)->kind() == Code::OPTIMIZED_FUNCTION);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012394 DCHECK(native_context->IsNativeContext());
12395 STATIC_ASSERT(kEntryLength == 4);
12396 Handle<FixedArray> new_code_map;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000012397 int entry;
12398
12399 if (shared->OptimizedCodeMapIsCleared()) {
12400 new_code_map = isolate->factory()->NewFixedArray(kInitialLength, TENURED);
12401 new_code_map->set(kSharedCodeIndex, *isolate->factory()->empty_weak_cell(),
12402 SKIP_WRITE_BARRIER);
12403 entry = kEntriesStart;
Ben Murdoch3ef787d2012-04-12 10:51:47 +010012404 } else {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000012405 Handle<FixedArray> old_code_map(shared->optimized_code_map(), isolate);
12406 entry = shared->SearchOptimizedCodeMapEntry(*native_context, osr_ast_id);
12407 if (entry > kSharedCodeIndex) {
12408 // Found an existing context-specific entry. If the user provided valid
12409 // code, it must not contain any code.
12410 DCHECK(code->IsUndefined() ||
12411 WeakCell::cast(old_code_map->get(entry + kCachedCodeOffset))
12412 ->cleared());
12413
12414 // Just set the code and literals to the entry.
12415 if (!code->IsUndefined()) {
12416 Handle<WeakCell> code_cell = isolate->factory()->NewWeakCell(code);
12417 old_code_map->set(entry + kCachedCodeOffset, *code_cell);
12418 }
12419 Handle<WeakCell> literals_cell =
12420 isolate->factory()->NewWeakCell(literals);
12421 old_code_map->set(entry + kLiteralsOffset, *literals_cell);
12422 return;
12423 }
12424
12425 // Can we reuse an entry?
12426 DCHECK(entry < kEntriesStart);
12427 int length = old_code_map->length();
12428 for (int i = kEntriesStart; i < length; i += kEntryLength) {
12429 if (WeakCell::cast(old_code_map->get(i + kContextOffset))->cleared()) {
12430 new_code_map = old_code_map;
12431 entry = i;
12432 break;
12433 }
12434 }
12435
12436 if (entry < kEntriesStart) {
12437 // Copy old optimized code map and append one new entry.
12438 new_code_map = isolate->factory()->CopyFixedArrayAndGrow(
12439 old_code_map, kEntryLength, TENURED);
12440 // TODO(mstarzinger): Temporary workaround. The allocation above might
12441 // have flushed the optimized code map and the copy we created is full of
12442 // holes. For now we just give up on adding the entry and pretend it got
12443 // flushed.
12444 if (shared->OptimizedCodeMapIsCleared()) return;
12445 entry = old_code_map->length();
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012446 }
Ben Murdoch3ef787d2012-04-12 10:51:47 +010012447 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000012448
12449 Handle<WeakCell> code_cell = code->IsUndefined()
12450 ? isolate->factory()->empty_weak_cell()
12451 : isolate->factory()->NewWeakCell(code);
12452 Handle<WeakCell> literals_cell = isolate->factory()->NewWeakCell(literals);
12453 WeakCell* context_cell = native_context->self_weak_cell();
12454
12455 new_code_map->set(entry + kContextOffset, context_cell);
12456 new_code_map->set(entry + kCachedCodeOffset, *code_cell);
12457 new_code_map->set(entry + kLiteralsOffset, *literals_cell);
12458 new_code_map->set(entry + kOsrAstIdOffset, Smi::FromInt(osr_ast_id.ToInt()));
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012459
12460#ifdef DEBUG
12461 for (int i = kEntriesStart; i < new_code_map->length(); i += kEntryLength) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000012462 WeakCell* cell = WeakCell::cast(new_code_map->get(i + kContextOffset));
12463 DCHECK(cell->cleared() || cell->value()->IsNativeContext());
12464 cell = WeakCell::cast(new_code_map->get(i + kCachedCodeOffset));
12465 DCHECK(cell->cleared() ||
12466 (cell->value()->IsCode() &&
12467 Code::cast(cell->value())->kind() == Code::OPTIMIZED_FUNCTION));
12468 cell = WeakCell::cast(new_code_map->get(i + kLiteralsOffset));
12469 DCHECK(cell->cleared() || cell->value()->IsFixedArray());
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012470 DCHECK(new_code_map->get(i + kOsrAstIdOffset)->IsSmi());
12471 }
12472#endif
Ben Murdoch3ef787d2012-04-12 10:51:47 +010012473
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000012474 FixedArray* old_code_map = shared->optimized_code_map();
12475 if (old_code_map != *new_code_map) {
12476 shared->set_optimized_code_map(*new_code_map);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012477 }
Ben Murdochb0fe1622011-05-05 13:52:32 +010012478}
12479
12480
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012481void SharedFunctionInfo::ClearOptimizedCodeMap() {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000012482 FixedArray* cleared_map = GetHeap()->cleared_optimized_code_map();
12483 set_optimized_code_map(cleared_map, SKIP_WRITE_BARRIER);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012484}
12485
12486
12487void SharedFunctionInfo::EvictFromOptimizedCodeMap(Code* optimized_code,
12488 const char* reason) {
12489 DisallowHeapAllocation no_gc;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000012490 if (OptimizedCodeMapIsCleared()) return;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012491
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000012492 Heap* heap = GetHeap();
12493 FixedArray* code_map = optimized_code_map();
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012494 int dst = kEntriesStart;
12495 int length = code_map->length();
12496 for (int src = kEntriesStart; src < length; src += kEntryLength) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000012497 DCHECK(WeakCell::cast(code_map->get(src))->cleared() ||
12498 WeakCell::cast(code_map->get(src))->value()->IsNativeContext());
12499 if (WeakCell::cast(code_map->get(src + kCachedCodeOffset))->value() ==
12500 optimized_code) {
12501 BailoutId osr(Smi::cast(code_map->get(src + kOsrAstIdOffset))->value());
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012502 if (FLAG_trace_opt) {
12503 PrintF("[evicting entry from optimizing code map (%s) for ", reason);
12504 ShortPrint();
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012505 if (osr.IsNone()) {
12506 PrintF("]\n");
12507 } else {
12508 PrintF(" (osr ast id %d)]\n", osr.ToInt());
12509 }
12510 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000012511 if (!osr.IsNone()) {
12512 // Evict the src entry by not copying it to the dst entry.
12513 continue;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012514 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000012515 // In case of non-OSR entry just clear the code in order to proceed
12516 // sharing literals.
12517 code_map->set(src + kCachedCodeOffset, heap->empty_weak_cell(),
12518 SKIP_WRITE_BARRIER);
12519 }
12520
12521 // Keep the src entry by copying it to the dst entry.
12522 if (dst != src) {
12523 code_map->set(dst + kContextOffset, code_map->get(src + kContextOffset));
12524 code_map->set(dst + kCachedCodeOffset,
12525 code_map->get(src + kCachedCodeOffset));
12526 code_map->set(dst + kLiteralsOffset,
12527 code_map->get(src + kLiteralsOffset));
12528 code_map->set(dst + kOsrAstIdOffset,
12529 code_map->get(src + kOsrAstIdOffset));
12530 }
12531 dst += kEntryLength;
12532 }
12533 if (WeakCell::cast(code_map->get(kSharedCodeIndex))->value() ==
12534 optimized_code) {
12535 // Evict context-independent code as well.
12536 code_map->set(kSharedCodeIndex, heap->empty_weak_cell(),
12537 SKIP_WRITE_BARRIER);
12538 if (FLAG_trace_opt) {
12539 PrintF("[evicting entry from optimizing code map (%s) for ", reason);
12540 ShortPrint();
12541 PrintF(" (context-independent code)]\n");
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012542 }
12543 }
12544 if (dst != length) {
12545 // Always trim even when array is cleared because of heap verifier.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000012546 heap->RightTrimFixedArray<Heap::CONCURRENT_TO_SWEEPER>(code_map,
12547 length - dst);
12548 if (code_map->length() == kEntriesStart &&
12549 WeakCell::cast(code_map->get(kSharedCodeIndex))->cleared()) {
12550 ClearOptimizedCodeMap();
12551 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012552 }
12553}
12554
12555
12556void SharedFunctionInfo::TrimOptimizedCodeMap(int shrink_by) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000012557 FixedArray* code_map = optimized_code_map();
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012558 DCHECK(shrink_by % kEntryLength == 0);
12559 DCHECK(shrink_by <= code_map->length() - kEntriesStart);
12560 // Always trim even when array is cleared because of heap verifier.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000012561 GetHeap()->RightTrimFixedArray<Heap::SEQUENTIAL_TO_SWEEPER>(code_map,
12562 shrink_by);
12563 if (code_map->length() == kEntriesStart &&
12564 WeakCell::cast(code_map->get(kSharedCodeIndex))->cleared()) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012565 ClearOptimizedCodeMap();
12566 }
12567}
12568
12569
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000012570static void GetMinInobjectSlack(Map* map, void* data) {
12571 int slack = map->unused_property_fields();
12572 if (*reinterpret_cast<int*>(data) > slack) {
12573 *reinterpret_cast<int*>(data) = slack;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012574 }
12575}
12576
12577
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000012578static void ShrinkInstanceSize(Map* map, void* data) {
12579 int slack = *reinterpret_cast<int*>(data);
12580 map->SetInObjectProperties(map->GetInObjectProperties() - slack);
12581 map->set_unused_property_fields(map->unused_property_fields() - slack);
12582 map->set_instance_size(map->instance_size() - slack * kPointerSize);
Ben Murdoch097c5b22016-05-18 11:27:45 +010012583 map->set_construction_counter(Map::kNoSlackTracking);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000012584
12585 // Visitor id might depend on the instance size, recalculate it.
12586 map->set_visitor_id(Heap::GetStaticVisitorIdForMap(map));
12587}
12588
Ben Murdoch097c5b22016-05-18 11:27:45 +010012589static void StopSlackTracking(Map* map, void* data) {
12590 map->set_construction_counter(Map::kNoSlackTracking);
12591}
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000012592
12593void Map::CompleteInobjectSlackTracking() {
12594 // Has to be an initial map.
12595 DCHECK(GetBackPointer()->IsUndefined());
12596
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000012597 int slack = unused_property_fields();
12598 TransitionArray::TraverseTransitionTree(this, &GetMinInobjectSlack, &slack);
12599 if (slack != 0) {
12600 // Resize the initial map and all maps in its transition tree.
12601 TransitionArray::TraverseTransitionTree(this, &ShrinkInstanceSize, &slack);
Ben Murdoch097c5b22016-05-18 11:27:45 +010012602 } else {
12603 TransitionArray::TraverseTransitionTree(this, &StopSlackTracking, nullptr);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000012604 }
12605}
12606
12607
12608static bool PrototypeBenefitsFromNormalization(Handle<JSObject> object) {
12609 DisallowHeapAllocation no_gc;
12610 if (!object->HasFastProperties()) return false;
12611 Map* map = object->map();
12612 if (map->is_prototype_map()) return false;
12613 DescriptorArray* descriptors = map->instance_descriptors();
12614 for (int i = 0; i < map->NumberOfOwnDescriptors(); i++) {
12615 PropertyDetails details = descriptors->GetDetails(i);
12616 if (details.location() == kDescriptor) continue;
12617 if (details.representation().IsHeapObject() ||
12618 details.representation().IsTagged()) {
12619 FieldIndex index = FieldIndex::ForDescriptor(map, i);
12620 if (object->RawFastPropertyAt(index)->IsJSFunction()) return true;
12621 }
12622 }
12623 return false;
12624}
12625
12626
12627// static
12628void JSObject::OptimizeAsPrototype(Handle<JSObject> object,
12629 PrototypeOptimizationMode mode) {
12630 if (object->IsJSGlobalObject()) return;
12631 if (mode == FAST_PROTOTYPE && PrototypeBenefitsFromNormalization(object)) {
12632 // First normalize to ensure all JSFunctions are DATA_CONSTANT.
12633 JSObject::NormalizeProperties(object, KEEP_INOBJECT_PROPERTIES, 0,
12634 "NormalizeAsPrototype");
12635 }
12636 Handle<Map> previous_map(object->map());
12637 if (!object->HasFastProperties()) {
12638 JSObject::MigrateSlowToFast(object, 0, "OptimizeAsPrototype");
12639 }
12640 if (!object->map()->is_prototype_map()) {
12641 if (object->map() == *previous_map) {
12642 Handle<Map> new_map = Map::Copy(handle(object->map()), "CopyAsPrototype");
12643 JSObject::MigrateToMap(object, new_map);
12644 }
12645 object->map()->set_is_prototype_map(true);
12646
12647 // Replace the pointer to the exact constructor with the Object function
12648 // from the same context if undetectable from JS. This is to avoid keeping
12649 // memory alive unnecessarily.
12650 Object* maybe_constructor = object->map()->GetConstructor();
12651 if (maybe_constructor->IsJSFunction()) {
12652 JSFunction* constructor = JSFunction::cast(maybe_constructor);
12653 Isolate* isolate = object->GetIsolate();
12654 if (!constructor->shared()->IsApiFunction() &&
12655 object->class_name() == isolate->heap()->Object_string()) {
12656 Context* context = constructor->context()->native_context();
12657 JSFunction* object_function = context->object_function();
12658 object->map()->SetConstructor(object_function);
12659 }
12660 }
12661 }
12662}
12663
12664
12665// static
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012666void JSObject::ReoptimizeIfPrototype(Handle<JSObject> object) {
12667 if (!object->map()->is_prototype_map()) return;
12668 OptimizeAsPrototype(object, FAST_PROTOTYPE);
12669}
12670
12671
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000012672// static
12673void JSObject::LazyRegisterPrototypeUser(Handle<Map> user, Isolate* isolate) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -040012674 DCHECK(FLAG_track_prototype_users);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000012675 // Contract: In line with InvalidatePrototypeChains()'s requirements,
12676 // leaf maps don't need to register as users, only prototypes do.
12677 DCHECK(user->is_prototype_map());
Emily Bernierd0a1eb72015-03-24 16:35:39 -040012678
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000012679 Handle<Map> current_user = user;
12680 Handle<PrototypeInfo> current_user_info =
12681 Map::GetOrCreatePrototypeInfo(user, isolate);
12682 for (PrototypeIterator iter(user); !iter.IsAtEnd(); iter.Advance()) {
12683 // Walk up the prototype chain as far as links haven't been registered yet.
12684 if (current_user_info->registry_slot() != PrototypeInfo::UNREGISTERED) {
12685 break;
12686 }
12687 Handle<Object> maybe_proto = PrototypeIterator::GetCurrent(iter);
12688 // Proxies on the prototype chain are not supported. They make it
12689 // impossible to make any assumptions about the prototype chain anyway.
12690 if (maybe_proto->IsJSProxy()) return;
12691 Handle<JSObject> proto = Handle<JSObject>::cast(maybe_proto);
12692 Handle<PrototypeInfo> proto_info =
12693 Map::GetOrCreatePrototypeInfo(proto, isolate);
12694 Handle<Object> maybe_registry(proto_info->prototype_users(), isolate);
12695 int slot = 0;
12696 Handle<WeakFixedArray> new_array =
12697 WeakFixedArray::Add(maybe_registry, current_user, &slot);
12698 current_user_info->set_registry_slot(slot);
12699 if (!maybe_registry.is_identical_to(new_array)) {
12700 proto_info->set_prototype_users(*new_array);
12701 }
12702 if (FLAG_trace_prototype_users) {
12703 PrintF("Registering %p as a user of prototype %p (map=%p).\n",
12704 reinterpret_cast<void*>(*current_user),
12705 reinterpret_cast<void*>(*proto),
12706 reinterpret_cast<void*>(proto->map()));
12707 }
Emily Bernierd0a1eb72015-03-24 16:35:39 -040012708
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000012709 current_user = handle(proto->map(), isolate);
12710 current_user_info = proto_info;
Emily Bernierd0a1eb72015-03-24 16:35:39 -040012711 }
12712}
12713
12714
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000012715// Can be called regardless of whether |user| was actually registered with
12716// |prototype|. Returns true when there was a registration.
12717// static
12718bool JSObject::UnregisterPrototypeUser(Handle<Map> user, Isolate* isolate) {
12719 DCHECK(user->is_prototype_map());
12720 // If it doesn't have a PrototypeInfo, it was never registered.
12721 if (!user->prototype_info()->IsPrototypeInfo()) return false;
12722 // If it had no prototype before, see if it had users that might expect
12723 // registration.
12724 if (!user->prototype()->IsJSObject()) {
12725 Object* users =
12726 PrototypeInfo::cast(user->prototype_info())->prototype_users();
12727 return users->IsWeakFixedArray();
12728 }
12729 Handle<JSObject> prototype(JSObject::cast(user->prototype()), isolate);
12730 Handle<PrototypeInfo> user_info =
12731 Map::GetOrCreatePrototypeInfo(user, isolate);
12732 int slot = user_info->registry_slot();
12733 if (slot == PrototypeInfo::UNREGISTERED) return false;
12734 DCHECK(prototype->map()->is_prototype_map());
12735 Object* maybe_proto_info = prototype->map()->prototype_info();
12736 // User knows its registry slot, prototype info and user registry must exist.
12737 DCHECK(maybe_proto_info->IsPrototypeInfo());
12738 Handle<PrototypeInfo> proto_info(PrototypeInfo::cast(maybe_proto_info),
12739 isolate);
12740 Object* maybe_registry = proto_info->prototype_users();
12741 DCHECK(maybe_registry->IsWeakFixedArray());
12742 DCHECK(WeakFixedArray::cast(maybe_registry)->Get(slot) == *user);
12743 WeakFixedArray::cast(maybe_registry)->Clear(slot);
12744 if (FLAG_trace_prototype_users) {
12745 PrintF("Unregistering %p as a user of prototype %p.\n",
12746 reinterpret_cast<void*>(*user), reinterpret_cast<void*>(*prototype));
12747 }
12748 return true;
Emily Bernierd0a1eb72015-03-24 16:35:39 -040012749}
12750
12751
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000012752static void InvalidatePrototypeChainsInternal(Map* map) {
12753 if (!map->is_prototype_map()) return;
12754 if (FLAG_trace_prototype_users) {
12755 PrintF("Invalidating prototype map %p 's cell\n",
12756 reinterpret_cast<void*>(map));
12757 }
12758 Object* maybe_proto_info = map->prototype_info();
12759 if (!maybe_proto_info->IsPrototypeInfo()) return;
12760 PrototypeInfo* proto_info = PrototypeInfo::cast(maybe_proto_info);
12761 Object* maybe_cell = proto_info->validity_cell();
12762 if (maybe_cell->IsCell()) {
12763 // Just set the value; the cell will be replaced lazily.
12764 Cell* cell = Cell::cast(maybe_cell);
12765 cell->set_value(Smi::FromInt(Map::kPrototypeChainInvalid));
12766 }
12767
12768 WeakFixedArray::Iterator iterator(proto_info->prototype_users());
12769 // For now, only maps register themselves as users.
12770 Map* user;
12771 while ((user = iterator.Next<Map>())) {
12772 // Walk the prototype chain (backwards, towards leaf objects) if necessary.
12773 InvalidatePrototypeChainsInternal(user);
12774 }
12775}
12776
12777
12778// static
12779void JSObject::InvalidatePrototypeChains(Map* map) {
12780 if (!FLAG_eliminate_prototype_chain_checks) return;
12781 DisallowHeapAllocation no_gc;
12782 InvalidatePrototypeChainsInternal(map);
12783}
12784
12785
12786// static
12787Handle<PrototypeInfo> Map::GetOrCreatePrototypeInfo(Handle<JSObject> prototype,
12788 Isolate* isolate) {
12789 Object* maybe_proto_info = prototype->map()->prototype_info();
12790 if (maybe_proto_info->IsPrototypeInfo()) {
12791 return handle(PrototypeInfo::cast(maybe_proto_info), isolate);
12792 }
12793 Handle<PrototypeInfo> proto_info = isolate->factory()->NewPrototypeInfo();
12794 prototype->map()->set_prototype_info(*proto_info);
12795 return proto_info;
12796}
12797
12798
12799// static
12800Handle<PrototypeInfo> Map::GetOrCreatePrototypeInfo(Handle<Map> prototype_map,
12801 Isolate* isolate) {
12802 Object* maybe_proto_info = prototype_map->prototype_info();
12803 if (maybe_proto_info->IsPrototypeInfo()) {
12804 return handle(PrototypeInfo::cast(maybe_proto_info), isolate);
12805 }
12806 Handle<PrototypeInfo> proto_info = isolate->factory()->NewPrototypeInfo();
12807 prototype_map->set_prototype_info(*proto_info);
12808 return proto_info;
12809}
12810
12811
12812// static
12813Handle<Cell> Map::GetOrCreatePrototypeChainValidityCell(Handle<Map> map,
12814 Isolate* isolate) {
12815 Handle<Object> maybe_prototype(map->prototype(), isolate);
12816 if (!maybe_prototype->IsJSObject()) return Handle<Cell>::null();
12817 Handle<JSObject> prototype = Handle<JSObject>::cast(maybe_prototype);
12818 // Ensure the prototype is registered with its own prototypes so its cell
12819 // will be invalidated when necessary.
12820 JSObject::LazyRegisterPrototypeUser(handle(prototype->map(), isolate),
12821 isolate);
12822 Handle<PrototypeInfo> proto_info =
12823 GetOrCreatePrototypeInfo(prototype, isolate);
12824 Object* maybe_cell = proto_info->validity_cell();
12825 // Return existing cell if it's still valid.
12826 if (maybe_cell->IsCell()) {
12827 Handle<Cell> cell(Cell::cast(maybe_cell), isolate);
12828 if (cell->value() == Smi::FromInt(Map::kPrototypeChainValid)) {
12829 return cell;
12830 }
12831 }
12832 // Otherwise create a new cell.
12833 Handle<Cell> cell = isolate->factory()->NewCell(
12834 handle(Smi::FromInt(Map::kPrototypeChainValid), isolate));
12835 proto_info->set_validity_cell(*cell);
12836 return cell;
12837}
12838
12839
12840// static
12841void Map::SetPrototype(Handle<Map> map, Handle<Object> prototype,
Emily Bernierd0a1eb72015-03-24 16:35:39 -040012842 PrototypeOptimizationMode proto_mode) {
Ben Murdoch097c5b22016-05-18 11:27:45 +010012843 bool is_hidden = false;
Emily Bernierd0a1eb72015-03-24 16:35:39 -040012844 if (prototype->IsJSObject()) {
12845 Handle<JSObject> prototype_jsobj = Handle<JSObject>::cast(prototype);
Emily Bernierd0a1eb72015-03-24 16:35:39 -040012846 JSObject::OptimizeAsPrototype(prototype_jsobj, proto_mode);
Ben Murdoch097c5b22016-05-18 11:27:45 +010012847
12848 Object* maybe_constructor = prototype_jsobj->map()->GetConstructor();
12849 if (maybe_constructor->IsJSFunction()) {
12850 JSFunction* constructor = JSFunction::cast(maybe_constructor);
12851 Object* data = constructor->shared()->function_data();
12852 is_hidden = (data->IsFunctionTemplateInfo() &&
12853 FunctionTemplateInfo::cast(data)->hidden_prototype()) ||
12854 prototype->IsJSGlobalObject();
12855 }
Emily Bernierd0a1eb72015-03-24 16:35:39 -040012856 }
Ben Murdoch097c5b22016-05-18 11:27:45 +010012857 map->set_has_hidden_prototype(is_hidden);
12858
Emily Bernierd0a1eb72015-03-24 16:35:39 -040012859 WriteBarrierMode wb_mode =
12860 prototype->IsNull() ? SKIP_WRITE_BARRIER : UPDATE_WRITE_BARRIER;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000012861 map->set_prototype(*prototype, wb_mode);
Emily Bernierd0a1eb72015-03-24 16:35:39 -040012862}
12863
12864
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012865Handle<Object> CacheInitialJSArrayMaps(
12866 Handle<Context> native_context, Handle<Map> initial_map) {
12867 // Replace all of the cached initial array maps in the native context with
12868 // the appropriate transitioned elements kind maps.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000012869 Strength strength =
12870 initial_map->is_strong() ? Strength::STRONG : Strength::WEAK;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012871 Handle<Map> current_map = initial_map;
12872 ElementsKind kind = current_map->elements_kind();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000012873 DCHECK_EQ(GetInitialFastElementsKind(), kind);
12874 native_context->set(Context::ArrayMapIndex(kind, strength), *current_map);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012875 for (int i = GetSequenceIndexFromFastElementsKind(kind) + 1;
12876 i < kFastElementsKindCount; ++i) {
12877 Handle<Map> new_map;
12878 ElementsKind next_kind = GetFastElementsKindFromSequenceIndex(i);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000012879 if (Map* maybe_elements_transition = current_map->ElementsTransitionMap()) {
12880 new_map = handle(maybe_elements_transition);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012881 } else {
12882 new_map = Map::CopyAsElementsKind(
12883 current_map, next_kind, INSERT_TRANSITION);
12884 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000012885 DCHECK_EQ(next_kind, new_map->elements_kind());
12886 native_context->set(Context::ArrayMapIndex(next_kind, strength), *new_map);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012887 current_map = new_map;
12888 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012889 return initial_map;
12890}
12891
12892
12893void JSFunction::SetInstancePrototype(Handle<JSFunction> function,
12894 Handle<Object> value) {
12895 Isolate* isolate = function->GetIsolate();
12896
12897 DCHECK(value->IsJSReceiver());
12898
12899 // Now some logic for the maps of the objects that are created by using this
12900 // function as a constructor.
12901 if (function->has_initial_map()) {
12902 // If the function has allocated the initial map replace it with a
12903 // copy containing the new prototype. Also complete any in-object
12904 // slack tracking that is in progress at this point because it is
12905 // still tracking the old copy.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000012906 function->CompleteInobjectSlackTrackingIfActive();
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012907
12908 Handle<Map> initial_map(function->initial_map(), isolate);
12909
12910 if (!initial_map->GetIsolate()->bootstrapper()->IsActive() &&
12911 initial_map->instance_type() == JS_OBJECT_TYPE) {
12912 // Put the value in the initial map field until an initial map is needed.
12913 // At that point, a new initial map is created and the prototype is put
12914 // into the initial map where it belongs.
12915 function->set_prototype_or_initial_map(*value);
12916 } else {
Emily Bernierd0a1eb72015-03-24 16:35:39 -040012917 Handle<Map> new_map = Map::Copy(initial_map, "SetInstancePrototype");
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000012918 if (function->map()->is_strong()) {
12919 new_map->set_is_strong();
12920 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012921 JSFunction::SetInitialMap(function, new_map, value);
12922
12923 // If the function is used as the global Array function, cache the
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000012924 // updated initial maps (and transitioned versions) in the native context.
12925 Handle<Context> native_context(function->context()->native_context(),
12926 isolate);
12927 Handle<Object> array_function(
12928 native_context->get(Context::ARRAY_FUNCTION_INDEX), isolate);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012929 if (array_function->IsJSFunction() &&
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000012930 *function == JSFunction::cast(*array_function)) {
12931 CacheInitialJSArrayMaps(native_context, new_map);
12932 Handle<Map> new_strong_map = Map::Copy(new_map, "SetInstancePrototype");
12933 new_strong_map->set_is_strong();
12934 CacheInitialJSArrayMaps(native_context, new_strong_map);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012935 }
12936 }
12937
12938 // Deoptimize all code that embeds the previous initial map.
12939 initial_map->dependent_code()->DeoptimizeDependentCodeGroup(
12940 isolate, DependentCode::kInitialMapChangedGroup);
Steve Blocka7e24c12009-10-30 11:49:00 +000012941 } else {
12942 // Put the value in the initial map field until an initial map is
12943 // needed. At that point, a new initial map is created and the
12944 // prototype is put into the initial map where it belongs.
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012945 function->set_prototype_or_initial_map(*value);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000012946 if (value->IsJSObject()) {
12947 // Optimize as prototype to detach it from its transition tree.
12948 JSObject::OptimizeAsPrototype(Handle<JSObject>::cast(value),
12949 FAST_PROTOTYPE);
12950 }
Steve Blocka7e24c12009-10-30 11:49:00 +000012951 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012952 isolate->heap()->ClearInstanceofCache();
Steve Blocka7e24c12009-10-30 11:49:00 +000012953}
12954
12955
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012956void JSFunction::SetPrototype(Handle<JSFunction> function,
12957 Handle<Object> value) {
Ben Murdoch097c5b22016-05-18 11:27:45 +010012958 DCHECK(function->IsConstructor() ||
12959 IsGeneratorFunction(function->shared()->kind()));
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012960 Handle<Object> construct_prototype = value;
Steve Blocka7e24c12009-10-30 11:49:00 +000012961
Ben Murdoch3ef787d2012-04-12 10:51:47 +010012962 // If the value is not a JSReceiver, store the value in the map's
Steve Blocka7e24c12009-10-30 11:49:00 +000012963 // constructor field so it can be accessed. Also, set the prototype
12964 // used for constructing objects to the original object prototype.
12965 // See ECMA-262 13.2.2.
Ben Murdoch3ef787d2012-04-12 10:51:47 +010012966 if (!value->IsJSReceiver()) {
Steve Blocka7e24c12009-10-30 11:49:00 +000012967 // Copy the map so this does not affect unrelated functions.
12968 // Remove map transitions because they point to maps with a
12969 // different prototype.
Emily Bernierd0a1eb72015-03-24 16:35:39 -040012970 Handle<Map> new_map = Map::Copy(handle(function->map()), "SetPrototype");
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012971
12972 JSObject::MigrateToMap(function, new_map);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000012973 new_map->SetConstructor(*value);
Ben Murdoch8b112d22011-06-08 16:22:53 +010012974 new_map->set_non_instance_prototype(true);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012975 Isolate* isolate = new_map->GetIsolate();
12976 construct_prototype = handle(
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000012977 function->context()->native_context()->initial_object_prototype(),
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012978 isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +000012979 } else {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012980 function->map()->set_non_instance_prototype(false);
Steve Blocka7e24c12009-10-30 11:49:00 +000012981 }
12982
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012983 return SetInstancePrototype(function, construct_prototype);
Steve Blocka7e24c12009-10-30 11:49:00 +000012984}
12985
12986
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012987bool JSFunction::RemovePrototype() {
12988 Context* native_context = context()->native_context();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000012989 Map* no_prototype_map =
12990 is_strict(shared()->language_mode())
12991 ? native_context->strict_function_without_prototype_map()
12992 : native_context->sloppy_function_without_prototype_map();
Steve Block44f0eee2011-05-26 01:26:41 +010012993
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012994 if (map() == no_prototype_map) return true;
12995
12996#ifdef DEBUG
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000012997 if (map() != (is_strict(shared()->language_mode())
12998 ? native_context->strict_function_map()
12999 : native_context->sloppy_function_map())) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013000 return false;
Ben Murdoche0cee9b2011-05-25 10:26:03 +010013001 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013002#endif
Steve Block44f0eee2011-05-26 01:26:41 +010013003
13004 set_map(no_prototype_map);
Ben Murdoch3ef787d2012-04-12 10:51:47 +010013005 set_prototype_or_initial_map(no_prototype_map->GetHeap()->the_hole_value());
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013006 return true;
Steve Block6ded16b2010-05-10 14:33:55 +010013007}
13008
13009
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013010void JSFunction::SetInitialMap(Handle<JSFunction> function, Handle<Map> map,
13011 Handle<Object> prototype) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -040013012 if (map->prototype() != *prototype) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000013013 Map::SetPrototype(map, prototype, FAST_PROTOTYPE);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013014 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013015 function->set_prototype_or_initial_map(*map);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000013016 map->SetConstructor(*function);
Emily Bernierd0a1eb72015-03-24 16:35:39 -040013017#if TRACE_MAPS
13018 if (FLAG_trace_maps) {
13019 PrintF("[TraceMaps: InitialMap map= %p SFI= %d_%s ]\n",
13020 reinterpret_cast<void*>(*map), function->shared()->unique_id(),
13021 function->shared()->DebugName()->ToCString().get());
13022 }
13023#endif
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013024}
13025
13026
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000013027#ifdef DEBUG
13028namespace {
13029
13030bool CanSubclassHaveInobjectProperties(InstanceType instance_type) {
13031 switch (instance_type) {
13032 case JS_OBJECT_TYPE:
13033 case JS_CONTEXT_EXTENSION_OBJECT_TYPE:
13034 case JS_GENERATOR_OBJECT_TYPE:
13035 case JS_MODULE_TYPE:
13036 case JS_VALUE_TYPE:
13037 case JS_DATE_TYPE:
13038 case JS_ARRAY_TYPE:
13039 case JS_MESSAGE_OBJECT_TYPE:
13040 case JS_ARRAY_BUFFER_TYPE:
13041 case JS_TYPED_ARRAY_TYPE:
13042 case JS_DATA_VIEW_TYPE:
13043 case JS_SET_TYPE:
13044 case JS_MAP_TYPE:
13045 case JS_SET_ITERATOR_TYPE:
13046 case JS_MAP_ITERATOR_TYPE:
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000013047 case JS_WEAK_MAP_TYPE:
13048 case JS_WEAK_SET_TYPE:
13049 case JS_PROMISE_TYPE:
13050 case JS_REGEXP_TYPE:
13051 case JS_FUNCTION_TYPE:
13052 return true;
13053
13054 case JS_BOUND_FUNCTION_TYPE:
13055 case JS_PROXY_TYPE:
13056 case JS_GLOBAL_PROXY_TYPE:
13057 case JS_GLOBAL_OBJECT_TYPE:
13058 case FIXED_ARRAY_TYPE:
13059 case FIXED_DOUBLE_ARRAY_TYPE:
13060 case ODDBALL_TYPE:
13061 case FOREIGN_TYPE:
13062 case MAP_TYPE:
13063 case CODE_TYPE:
13064 case CELL_TYPE:
13065 case PROPERTY_CELL_TYPE:
13066 case WEAK_CELL_TYPE:
13067 case SYMBOL_TYPE:
13068 case BYTECODE_ARRAY_TYPE:
13069 case HEAP_NUMBER_TYPE:
13070 case MUTABLE_HEAP_NUMBER_TYPE:
13071 case SIMD128_VALUE_TYPE:
13072 case FILLER_TYPE:
13073 case BYTE_ARRAY_TYPE:
13074 case FREE_SPACE_TYPE:
13075 case SHARED_FUNCTION_INFO_TYPE:
13076
13077#define TYPED_ARRAY_CASE(Type, type, TYPE, ctype, size) \
13078 case FIXED_##TYPE##_ARRAY_TYPE:
13079#undef TYPED_ARRAY_CASE
13080
13081#define MAKE_STRUCT_CASE(NAME, Name, name) case NAME##_TYPE:
13082 STRUCT_LIST(MAKE_STRUCT_CASE)
13083#undef MAKE_STRUCT_CASE
13084 // We must not end up here for these instance types at all.
13085 UNREACHABLE();
13086 // Fall through.
13087 default:
13088 return false;
13089 }
13090}
13091
13092} // namespace
13093#endif
13094
13095
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013096void JSFunction::EnsureHasInitialMap(Handle<JSFunction> function) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000013097 DCHECK(function->IsConstructor() || function->shared()->is_generator());
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013098 if (function->has_initial_map()) return;
13099 Isolate* isolate = function->GetIsolate();
13100
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000013101 // The constructor should be compiled for the optimization hints to be
13102 // available.
13103 Compiler::Compile(function, CLEAR_EXCEPTION);
13104
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013105 // First create a new map with the size and number of in-object properties
13106 // suggested by the function.
13107 InstanceType instance_type;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013108 if (function->shared()->is_generator()) {
13109 instance_type = JS_GENERATOR_OBJECT_TYPE;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013110 } else {
13111 instance_type = JS_OBJECT_TYPE;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013112 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000013113 int instance_size;
13114 int in_object_properties;
13115 function->CalculateInstanceSize(instance_type, 0, &instance_size,
13116 &in_object_properties);
13117
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013118 Handle<Map> map = isolate->factory()->NewMap(instance_type, instance_size);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000013119 if (function->map()->is_strong()) {
13120 map->set_is_strong();
13121 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013122
13123 // Fetch or allocate prototype.
13124 Handle<Object> prototype;
13125 if (function->has_instance_prototype()) {
13126 prototype = handle(function->instance_prototype(), isolate);
13127 } else {
13128 prototype = isolate->factory()->NewFunctionPrototype(function);
13129 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000013130 map->SetInObjectProperties(in_object_properties);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013131 map->set_unused_property_fields(in_object_properties);
13132 DCHECK(map->has_fast_object_elements());
13133
13134 // Finally link initial map and constructor function.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000013135 DCHECK(prototype->IsJSReceiver());
13136 JSFunction::SetInitialMap(function, map, prototype);
13137 map->StartInobjectSlackTracking();
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013138}
13139
13140
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000013141// static
13142MaybeHandle<Map> JSFunction::GetDerivedMap(Isolate* isolate,
13143 Handle<JSFunction> constructor,
13144 Handle<JSReceiver> new_target) {
13145 EnsureHasInitialMap(constructor);
13146
13147 Handle<Map> constructor_initial_map(constructor->initial_map(), isolate);
13148 if (*new_target == *constructor) return constructor_initial_map;
13149
13150 // Fast case, new.target is a subclass of constructor. The map is cacheable
13151 // (and may already have been cached). new.target.prototype is guaranteed to
13152 // be a JSReceiver.
13153 if (new_target->IsJSFunction()) {
13154 Handle<JSFunction> function = Handle<JSFunction>::cast(new_target);
13155
13156 // Check that |function|'s initial map still in sync with the |constructor|,
13157 // otherwise we must create a new initial map for |function|.
13158 if (function->has_initial_map() &&
13159 function->initial_map()->GetConstructor() == *constructor) {
13160 return handle(function->initial_map(), isolate);
13161 }
13162
13163 // Create a new map with the size and number of in-object properties
13164 // suggested by |function|.
13165
13166 // Link initial map and constructor function if the new.target is actually a
13167 // subclass constructor.
13168 if (IsSubclassConstructor(function->shared()->kind())) {
13169 Handle<Object> prototype(function->instance_prototype(), isolate);
13170 InstanceType instance_type = constructor_initial_map->instance_type();
13171 DCHECK(CanSubclassHaveInobjectProperties(instance_type));
13172 int internal_fields =
13173 JSObject::GetInternalFieldCount(*constructor_initial_map);
13174 int pre_allocated = constructor_initial_map->GetInObjectProperties() -
13175 constructor_initial_map->unused_property_fields();
13176 int instance_size;
13177 int in_object_properties;
13178 function->CalculateInstanceSizeForDerivedClass(
13179 instance_type, internal_fields, &instance_size,
13180 &in_object_properties);
13181
13182 int unused_property_fields = in_object_properties - pre_allocated;
13183 Handle<Map> map =
13184 Map::CopyInitialMap(constructor_initial_map, instance_size,
13185 in_object_properties, unused_property_fields);
13186 map->set_new_target_is_base(false);
13187
13188 JSFunction::SetInitialMap(function, map, prototype);
13189 map->SetConstructor(*constructor);
Ben Murdoch097c5b22016-05-18 11:27:45 +010013190 map->set_construction_counter(Map::kNoSlackTracking);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000013191 map->StartInobjectSlackTracking();
13192 return map;
13193 }
13194 }
13195
13196 // Slow path, new.target is either a proxy or can't cache the map.
13197 // new.target.prototype is not guaranteed to be a JSReceiver, and may need to
13198 // fall back to the intrinsicDefaultProto.
13199 Handle<Object> prototype;
13200 if (new_target->IsJSFunction()) {
13201 Handle<JSFunction> function = Handle<JSFunction>::cast(new_target);
13202 // Make sure the new.target.prototype is cached.
13203 EnsureHasInitialMap(function);
13204 prototype = handle(function->prototype(), isolate);
13205 } else {
13206 Handle<String> prototype_string = isolate->factory()->prototype_string();
13207 ASSIGN_RETURN_ON_EXCEPTION(
13208 isolate, prototype,
13209 JSReceiver::GetProperty(new_target, prototype_string), Map);
13210 // The above prototype lookup might change the constructor and its
13211 // prototype, hence we have to reload the initial map.
13212 EnsureHasInitialMap(constructor);
13213 constructor_initial_map = handle(constructor->initial_map(), isolate);
13214 }
13215
13216 // If prototype is not a JSReceiver, fetch the intrinsicDefaultProto from the
13217 // correct realm. Rather than directly fetching the .prototype, we fetch the
13218 // constructor that points to the .prototype. This relies on
13219 // constructor.prototype being FROZEN for those constructors.
13220 if (!prototype->IsJSReceiver()) {
13221 Handle<Context> context;
13222 ASSIGN_RETURN_ON_EXCEPTION(isolate, context,
13223 JSReceiver::GetFunctionRealm(new_target), Map);
13224 DCHECK(context->IsNativeContext());
13225 Handle<Object> maybe_index = JSReceiver::GetDataProperty(
13226 constructor, isolate->factory()->native_context_index_symbol());
13227 int index = maybe_index->IsSmi() ? Smi::cast(*maybe_index)->value()
13228 : Context::OBJECT_FUNCTION_INDEX;
13229 Handle<JSFunction> realm_constructor(JSFunction::cast(context->get(index)));
13230 prototype = handle(realm_constructor->prototype(), isolate);
13231 }
13232
13233 Handle<Map> map = Map::CopyInitialMap(constructor_initial_map);
13234 map->set_new_target_is_base(false);
13235 DCHECK(prototype->IsJSReceiver());
13236 if (map->prototype() != *prototype) {
13237 Map::SetPrototype(map, prototype, FAST_PROTOTYPE);
13238 }
13239 map->SetConstructor(*constructor);
13240 return map;
Steve Blocka7e24c12009-10-30 11:49:00 +000013241}
13242
13243
Ben Murdochb0fe1622011-05-05 13:52:32 +010013244void JSFunction::PrintName(FILE* out) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000013245 base::SmartArrayPointer<char> name = shared()->DebugName()->ToCString();
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013246 PrintF(out, "%s", name.get());
Ben Murdochb0fe1622011-05-05 13:52:32 +010013247}
13248
13249
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013250// The filter is a pattern that matches function names in this way:
13251// "*" all; the default
13252// "-" all but the top-level function
13253// "-name" all but the function "name"
13254// "" only the top-level function
13255// "name" only the function "name"
13256// "name*" only functions starting with "name"
13257// "~" none; the tilde is not an identifier
13258bool JSFunction::PassesFilter(const char* raw_filter) {
13259 if (*raw_filter == '*') return true;
13260 String* name = shared()->DebugName();
13261 Vector<const char> filter = CStrVector(raw_filter);
13262 if (filter.length() == 0) return name->length() == 0;
13263 if (filter[0] == '-') {
13264 // Negative filter.
13265 if (filter.length() == 1) {
13266 return (name->length() != 0);
13267 } else if (name->IsUtf8EqualTo(filter.SubVector(1, filter.length()))) {
13268 return false;
13269 }
13270 if (filter[filter.length() - 1] == '*' &&
13271 name->IsUtf8EqualTo(filter.SubVector(1, filter.length() - 1), true)) {
13272 return false;
13273 }
13274 return true;
13275
13276 } else if (name->IsUtf8EqualTo(filter)) {
13277 return true;
John Reck59135872010-11-02 12:39:01 -070013278 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013279 if (filter[filter.length() - 1] == '*' &&
13280 name->IsUtf8EqualTo(filter.SubVector(0, filter.length() - 1), true)) {
13281 return true;
13282 }
13283 return false;
13284}
13285
13286
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000013287Handle<String> JSFunction::GetName(Handle<JSFunction> function) {
13288 Isolate* isolate = function->GetIsolate();
13289 Handle<Object> name =
13290 JSReceiver::GetDataProperty(function, isolate->factory()->name_string());
13291 if (name->IsString()) return Handle<String>::cast(name);
13292 return handle(function->shared()->DebugName(), isolate);
13293}
13294
13295
13296Handle<String> JSFunction::GetDebugName(Handle<JSFunction> function) {
13297 Isolate* isolate = function->GetIsolate();
13298 Handle<Object> name = JSReceiver::GetDataProperty(
13299 function, isolate->factory()->display_name_string());
13300 if (name->IsString()) return Handle<String>::cast(name);
13301 return JSFunction::GetName(function);
13302}
13303
Ben Murdoch097c5b22016-05-18 11:27:45 +010013304void JSFunction::SetName(Handle<JSFunction> function, Handle<Name> name,
13305 Handle<String> prefix) {
13306 Isolate* isolate = function->GetIsolate();
13307 Handle<String> function_name = Name::ToFunctionName(name).ToHandleChecked();
13308 if (prefix->length() > 0) {
13309 IncrementalStringBuilder builder(isolate);
13310 builder.AppendString(prefix);
13311 builder.AppendCharacter(' ');
13312 builder.AppendString(function_name);
13313 function_name = builder.Finish().ToHandleChecked();
13314 }
13315 JSObject::DefinePropertyOrElementIgnoreAttributes(
13316 function, isolate->factory()->name_string(), function_name,
13317 static_cast<PropertyAttributes>(DONT_ENUM | READ_ONLY))
13318 .ToHandleChecked();
13319}
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000013320
13321namespace {
13322
13323char const kNativeCodeSource[] = "function () { [native code] }";
13324
13325
13326Handle<String> NativeCodeFunctionSourceString(
13327 Handle<SharedFunctionInfo> shared_info) {
13328 Isolate* const isolate = shared_info->GetIsolate();
13329 if (shared_info->name()->IsString()) {
13330 IncrementalStringBuilder builder(isolate);
13331 builder.AppendCString("function ");
13332 builder.AppendString(handle(String::cast(shared_info->name()), isolate));
13333 builder.AppendCString("() { [native code] }");
13334 return builder.Finish().ToHandleChecked();
13335 }
13336 return isolate->factory()->NewStringFromAsciiChecked(kNativeCodeSource);
13337}
13338
13339} // namespace
13340
13341
13342// static
13343Handle<String> JSBoundFunction::ToString(Handle<JSBoundFunction> function) {
13344 Isolate* const isolate = function->GetIsolate();
13345 return isolate->factory()->NewStringFromAsciiChecked(kNativeCodeSource);
13346}
13347
13348
13349// static
13350Handle<String> JSFunction::ToString(Handle<JSFunction> function) {
13351 Isolate* const isolate = function->GetIsolate();
13352 Handle<SharedFunctionInfo> shared_info(function->shared(), isolate);
13353
13354 // Check if {function} should hide its source code.
13355 if (!shared_info->script()->IsScript() ||
13356 Script::cast(shared_info->script())->hide_source()) {
13357 return NativeCodeFunctionSourceString(shared_info);
13358 }
13359
13360 // Check if we should print {function} as a class.
13361 Handle<Object> class_start_position = JSReceiver::GetDataProperty(
13362 function, isolate->factory()->class_start_position_symbol());
13363 if (class_start_position->IsSmi()) {
13364 Handle<Object> class_end_position = JSReceiver::GetDataProperty(
13365 function, isolate->factory()->class_end_position_symbol());
13366 Handle<String> script_source(
13367 String::cast(Script::cast(shared_info->script())->source()), isolate);
13368 return isolate->factory()->NewSubString(
13369 script_source, Handle<Smi>::cast(class_start_position)->value(),
13370 Handle<Smi>::cast(class_end_position)->value());
13371 }
13372
13373 // Check if we have source code for the {function}.
13374 if (!shared_info->HasSourceCode()) {
13375 return NativeCodeFunctionSourceString(shared_info);
13376 }
13377
13378 IncrementalStringBuilder builder(isolate);
13379 if (!shared_info->is_arrow()) {
13380 if (shared_info->is_concise_method()) {
13381 if (shared_info->is_generator()) builder.AppendCharacter('*');
13382 } else {
13383 if (shared_info->is_generator()) {
13384 builder.AppendCString("function* ");
13385 } else {
13386 builder.AppendCString("function ");
13387 }
13388 }
13389 if (shared_info->name_should_print_as_anonymous()) {
13390 builder.AppendCString("anonymous");
Ben Murdoch097c5b22016-05-18 11:27:45 +010013391 } else if (!shared_info->is_anonymous_expression()) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000013392 builder.AppendString(handle(String::cast(shared_info->name()), isolate));
13393 }
13394 }
13395 builder.AppendString(Handle<String>::cast(shared_info->GetSourceCode()));
13396 return builder.Finish().ToHandleChecked();
13397}
13398
13399
13400void Oddball::Initialize(Isolate* isolate, Handle<Oddball> oddball,
13401 const char* to_string, Handle<Object> to_number,
13402 const char* type_of, byte kind) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013403 Handle<String> internalized_to_string =
13404 isolate->factory()->InternalizeUtf8String(to_string);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000013405 Handle<String> internalized_type_of =
13406 isolate->factory()->InternalizeUtf8String(type_of);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013407 oddball->set_to_number(*to_number);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000013408 oddball->set_to_string(*internalized_to_string);
13409 oddball->set_type_of(*internalized_type_of);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013410 oddball->set_kind(kind);
13411}
13412
13413
13414void Script::InitLineEnds(Handle<Script> script) {
13415 if (!script->line_ends()->IsUndefined()) return;
13416
13417 Isolate* isolate = script->GetIsolate();
13418
13419 if (!script->source()->IsString()) {
13420 DCHECK(script->source()->IsUndefined());
13421 Handle<FixedArray> empty = isolate->factory()->NewFixedArray(0);
13422 script->set_line_ends(*empty);
13423 DCHECK(script->line_ends()->IsFixedArray());
13424 return;
13425 }
13426
13427 Handle<String> src(String::cast(script->source()), isolate);
13428
13429 Handle<FixedArray> array = String::CalculateLineEnds(src, true);
13430
13431 if (*array != isolate->heap()->empty_fixed_array()) {
13432 array->set_map(isolate->heap()->fixed_cow_array_map());
13433 }
13434
13435 script->set_line_ends(*array);
13436 DCHECK(script->line_ends()->IsFixedArray());
13437}
13438
13439
13440int Script::GetColumnNumber(Handle<Script> script, int code_pos) {
13441 int line_number = GetLineNumber(script, code_pos);
13442 if (line_number == -1) return -1;
13443
13444 DisallowHeapAllocation no_allocation;
13445 FixedArray* line_ends_array = FixedArray::cast(script->line_ends());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000013446 line_number = line_number - script->line_offset();
13447 if (line_number == 0) return code_pos + script->column_offset();
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013448 int prev_line_end_pos =
13449 Smi::cast(line_ends_array->get(line_number - 1))->value();
13450 return code_pos - (prev_line_end_pos + 1);
13451}
13452
13453
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000013454int Script::GetLineNumberWithArray(int code_pos) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013455 DisallowHeapAllocation no_allocation;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000013456 DCHECK(line_ends()->IsFixedArray());
13457 FixedArray* line_ends_array = FixedArray::cast(line_ends());
13458 int line_ends_len = line_ends_array->length();
13459 if (line_ends_len == 0) return -1;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013460
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000013461 if ((Smi::cast(line_ends_array->get(0)))->value() >= code_pos) {
13462 return line_offset();
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013463 }
13464
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000013465 int left = 0;
13466 int right = line_ends_len;
13467 while (int half = (right - left) / 2) {
13468 if ((Smi::cast(line_ends_array->get(left + half)))->value() > code_pos) {
13469 right -= half;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013470 } else {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000013471 left += half;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013472 }
13473 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000013474 return right + line_offset();
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013475}
13476
13477
13478int Script::GetLineNumber(Handle<Script> script, int code_pos) {
13479 InitLineEnds(script);
13480 return script->GetLineNumberWithArray(code_pos);
13481}
13482
13483
13484int Script::GetLineNumber(int code_pos) {
13485 DisallowHeapAllocation no_allocation;
13486 if (!line_ends()->IsUndefined()) return GetLineNumberWithArray(code_pos);
13487
13488 // Slow mode: we do not have line_ends. We have to iterate through source.
13489 if (!source()->IsString()) return -1;
13490
13491 String* source_string = String::cast(source());
13492 int line = 0;
13493 int len = source_string->length();
13494 for (int pos = 0; pos < len; pos++) {
13495 if (pos == code_pos) break;
13496 if (source_string->Get(pos) == '\n') line++;
13497 }
13498 return line;
13499}
13500
13501
13502Handle<Object> Script::GetNameOrSourceURL(Handle<Script> script) {
13503 Isolate* isolate = script->GetIsolate();
13504 Handle<String> name_or_source_url_key =
13505 isolate->factory()->InternalizeOneByteString(
13506 STATIC_CHAR_VECTOR("nameOrSourceURL"));
13507 Handle<JSObject> script_wrapper = Script::GetWrapper(script);
13508 Handle<Object> property = Object::GetProperty(
13509 script_wrapper, name_or_source_url_key).ToHandleChecked();
13510 DCHECK(property->IsJSFunction());
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013511 Handle<Object> result;
13512 // Do not check against pending exception, since this function may be called
13513 // when an exception has already been pending.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000013514 if (!Execution::TryCall(isolate, property, script_wrapper, 0, NULL)
13515 .ToHandle(&result)) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013516 return isolate->factory()->undefined_value();
13517 }
13518 return result;
13519}
13520
13521
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013522Handle<JSObject> Script::GetWrapper(Handle<Script> script) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013523 Isolate* isolate = script->GetIsolate();
Emily Bernierd0a1eb72015-03-24 16:35:39 -040013524 if (!script->wrapper()->IsUndefined()) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000013525 DCHECK(script->wrapper()->IsWeakCell());
Emily Bernierd0a1eb72015-03-24 16:35:39 -040013526 Handle<WeakCell> cell(WeakCell::cast(script->wrapper()));
13527 if (!cell->cleared()) {
13528 // Return a handle for the existing script wrapper from the cache.
13529 return handle(JSObject::cast(cell->value()));
13530 }
13531 // If we found an empty WeakCell, that means the script wrapper was
13532 // GCed. We are not notified directly of that, so we decrement here
13533 // so that we at least don't count double for any given script.
13534 isolate->counters()->script_wrappers()->Decrement();
13535 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013536 // Construct a new script wrapper.
13537 isolate->counters()->script_wrappers()->Increment();
13538 Handle<JSFunction> constructor = isolate->script_function();
13539 Handle<JSValue> result =
13540 Handle<JSValue>::cast(isolate->factory()->NewJSObject(constructor));
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013541 result->set_value(*script);
Emily Bernierd0a1eb72015-03-24 16:35:39 -040013542 Handle<WeakCell> cell = isolate->factory()->NewWeakCell(result);
13543 script->set_wrapper(*cell);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013544 return result;
Steve Blocka7e24c12009-10-30 11:49:00 +000013545}
13546
13547
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000013548MaybeHandle<SharedFunctionInfo> Script::FindSharedFunctionInfo(
13549 FunctionLiteral* fun) {
13550 WeakFixedArray::Iterator iterator(shared_function_infos());
13551 SharedFunctionInfo* shared;
13552 while ((shared = iterator.Next<SharedFunctionInfo>())) {
13553 if (fun->function_token_position() == shared->function_token_position() &&
13554 fun->start_position() == shared->start_position()) {
13555 return Handle<SharedFunctionInfo>(shared);
13556 }
13557 }
13558 return MaybeHandle<SharedFunctionInfo>();
13559}
13560
13561
13562Script::Iterator::Iterator(Isolate* isolate)
13563 : iterator_(isolate->heap()->script_list()) {}
13564
13565
13566Script* Script::Iterator::Next() { return iterator_.Next<Script>(); }
13567
13568
13569SharedFunctionInfo::Iterator::Iterator(Isolate* isolate)
13570 : script_iterator_(isolate),
13571 sfi_iterator_(isolate->heap()->noscript_shared_function_infos()) {}
13572
13573
13574bool SharedFunctionInfo::Iterator::NextScript() {
13575 Script* script = script_iterator_.Next();
13576 if (script == NULL) return false;
13577 sfi_iterator_.Reset(script->shared_function_infos());
13578 return true;
13579}
13580
13581
13582SharedFunctionInfo* SharedFunctionInfo::Iterator::Next() {
13583 do {
13584 SharedFunctionInfo* next = sfi_iterator_.Next<SharedFunctionInfo>();
13585 if (next != NULL) return next;
13586 } while (NextScript());
13587 return NULL;
13588}
13589
13590
13591void SharedFunctionInfo::SetScript(Handle<SharedFunctionInfo> shared,
13592 Handle<Object> script_object) {
13593 if (shared->script() == *script_object) return;
13594 Isolate* isolate = shared->GetIsolate();
13595
13596 // Add shared function info to new script's list. If a collection occurs,
13597 // the shared function info may be temporarily in two lists.
13598 // This is okay because the gc-time processing of these lists can tolerate
13599 // duplicates.
13600 Handle<Object> list;
13601 if (script_object->IsScript()) {
13602 Handle<Script> script = Handle<Script>::cast(script_object);
13603 list = handle(script->shared_function_infos(), isolate);
13604 } else {
13605 list = isolate->factory()->noscript_shared_function_infos();
13606 }
13607
13608#ifdef DEBUG
13609 {
13610 WeakFixedArray::Iterator iterator(*list);
13611 SharedFunctionInfo* next;
13612 while ((next = iterator.Next<SharedFunctionInfo>())) {
13613 DCHECK_NE(next, *shared);
13614 }
13615 }
13616#endif // DEBUG
13617 list = WeakFixedArray::Add(list, shared);
13618
13619 if (script_object->IsScript()) {
13620 Handle<Script> script = Handle<Script>::cast(script_object);
13621 script->set_shared_function_infos(*list);
13622 } else {
13623 isolate->heap()->SetRootNoScriptSharedFunctionInfos(*list);
13624 }
13625
13626 // Remove shared function info from old script's list.
13627 if (shared->script()->IsScript()) {
13628 Script* old_script = Script::cast(shared->script());
13629 if (old_script->shared_function_infos()->IsWeakFixedArray()) {
13630 WeakFixedArray* list =
13631 WeakFixedArray::cast(old_script->shared_function_infos());
13632 list->Remove(shared);
13633 }
13634 } else {
13635 // Remove shared function info from root array.
13636 Object* list = isolate->heap()->noscript_shared_function_infos();
13637 CHECK(WeakFixedArray::cast(list)->Remove(shared));
13638 }
13639
13640 // Finally set new script.
13641 shared->set_script(*script_object);
13642}
13643
13644
Ben Murdochf87a2032010-10-22 12:50:53 +010013645String* SharedFunctionInfo::DebugName() {
13646 Object* n = name();
13647 if (!n->IsString() || String::cast(n)->length() == 0) return inferred_name();
13648 return String::cast(n);
13649}
13650
13651
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013652bool SharedFunctionInfo::HasSourceCode() const {
Steve Blocka7e24c12009-10-30 11:49:00 +000013653 return !script()->IsUndefined() &&
Iain Merrick75681382010-08-19 15:07:18 +010013654 !reinterpret_cast<Script*>(script())->source()->IsUndefined();
Steve Blocka7e24c12009-10-30 11:49:00 +000013655}
13656
13657
Ben Murdoch3ef787d2012-04-12 10:51:47 +010013658Handle<Object> SharedFunctionInfo::GetSourceCode() {
13659 if (!HasSourceCode()) return GetIsolate()->factory()->undefined_value();
13660 Handle<String> source(String::cast(Script::cast(script())->source()));
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013661 return GetIsolate()->factory()->NewSubString(
13662 source, start_position(), end_position());
13663}
13664
13665
13666bool SharedFunctionInfo::IsInlineable() {
13667 // Check that the function has a script associated with it.
13668 if (!script()->IsScript()) return false;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000013669 return !optimization_disabled();
Steve Blocka7e24c12009-10-30 11:49:00 +000013670}
13671
13672
Ben Murdochb0fe1622011-05-05 13:52:32 +010013673int SharedFunctionInfo::SourceSize() {
13674 return end_position() - start_position();
13675}
13676
13677
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000013678namespace {
13679
13680void CalculateInstanceSizeHelper(InstanceType instance_type,
13681 int requested_internal_fields,
13682 int requested_in_object_properties,
13683 int* instance_size,
13684 int* in_object_properties) {
13685 int header_size = JSObject::GetHeaderSize(instance_type);
13686 DCHECK_LE(requested_internal_fields,
13687 (JSObject::kMaxInstanceSize - header_size) >> kPointerSizeLog2);
13688 *instance_size =
13689 Min(header_size +
13690 ((requested_internal_fields + requested_in_object_properties)
13691 << kPointerSizeLog2),
13692 JSObject::kMaxInstanceSize);
13693 *in_object_properties = ((*instance_size - header_size) >> kPointerSizeLog2) -
13694 requested_internal_fields;
13695}
13696
13697} // namespace
13698
13699
13700void JSFunction::CalculateInstanceSize(InstanceType instance_type,
13701 int requested_internal_fields,
13702 int* instance_size,
13703 int* in_object_properties) {
13704 CalculateInstanceSizeHelper(instance_type, requested_internal_fields,
13705 shared()->expected_nof_properties(),
13706 instance_size, in_object_properties);
Steve Blocka7e24c12009-10-30 11:49:00 +000013707}
13708
13709
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000013710void JSFunction::CalculateInstanceSizeForDerivedClass(
13711 InstanceType instance_type, int requested_internal_fields,
13712 int* instance_size, int* in_object_properties) {
13713 Isolate* isolate = GetIsolate();
13714 int expected_nof_properties = 0;
13715 for (PrototypeIterator iter(isolate, this,
13716 PrototypeIterator::START_AT_RECEIVER);
13717 !iter.IsAtEnd(); iter.Advance()) {
Ben Murdoch097c5b22016-05-18 11:27:45 +010013718 JSReceiver* current = iter.GetCurrent<JSReceiver>();
13719 if (!current->IsJSFunction()) break;
13720 JSFunction* func = JSFunction::cast(current);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000013721 SharedFunctionInfo* shared = func->shared();
13722 expected_nof_properties += shared->expected_nof_properties();
13723 if (!IsSubclassConstructor(shared->kind())) {
13724 break;
13725 }
13726 }
13727 CalculateInstanceSizeHelper(instance_type, requested_internal_fields,
13728 expected_nof_properties, instance_size,
13729 in_object_properties);
Steve Blocka7e24c12009-10-30 11:49:00 +000013730}
13731
13732
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013733// Output the source code without any allocation in the heap.
Emily Bernierd0a1eb72015-03-24 16:35:39 -040013734std::ostream& operator<<(std::ostream& os, const SourceCodeOf& v) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013735 const SharedFunctionInfo* s = v.value;
Steve Blocka7e24c12009-10-30 11:49:00 +000013736 // For some native functions there is no source.
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013737 if (!s->HasSourceCode()) return os << "<No Source>";
Steve Blocka7e24c12009-10-30 11:49:00 +000013738
Steve Blockd0582a62009-12-15 09:54:21 +000013739 // Get the source for the script which this function came from.
Steve Blocka7e24c12009-10-30 11:49:00 +000013740 // Don't use String::cast because we don't want more assertion errors while
13741 // we are already creating a stack dump.
13742 String* script_source =
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013743 reinterpret_cast<String*>(Script::cast(s->script())->source());
Steve Blocka7e24c12009-10-30 11:49:00 +000013744
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013745 if (!script_source->LooksValid()) return os << "<Invalid Source>";
Steve Blocka7e24c12009-10-30 11:49:00 +000013746
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013747 if (!s->is_toplevel()) {
13748 os << "function ";
13749 Object* name = s->name();
Steve Blocka7e24c12009-10-30 11:49:00 +000013750 if (name->IsString() && String::cast(name)->length() > 0) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013751 String::cast(name)->PrintUC16(os);
Steve Blocka7e24c12009-10-30 11:49:00 +000013752 }
13753 }
13754
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013755 int len = s->end_position() - s->start_position();
13756 if (len <= v.max_length || v.max_length < 0) {
13757 script_source->PrintUC16(os, s->start_position(), s->end_position());
13758 return os;
Ben Murdochb0fe1622011-05-05 13:52:32 +010013759 } else {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013760 script_source->PrintUC16(os, s->start_position(),
13761 s->start_position() + v.max_length);
13762 return os << "...\n";
Steve Blocka7e24c12009-10-30 11:49:00 +000013763 }
13764}
13765
13766
Ben Murdochb0fe1622011-05-05 13:52:32 +010013767static bool IsCodeEquivalent(Code* code, Code* recompiled) {
13768 if (code->instruction_size() != recompiled->instruction_size()) return false;
13769 ByteArray* code_relocation = code->relocation_info();
13770 ByteArray* recompiled_relocation = recompiled->relocation_info();
13771 int length = code_relocation->length();
13772 if (length != recompiled_relocation->length()) return false;
13773 int compare = memcmp(code_relocation->GetDataStartAddress(),
13774 recompiled_relocation->GetDataStartAddress(),
13775 length);
13776 return compare == 0;
13777}
13778
13779
13780void SharedFunctionInfo::EnableDeoptimizationSupport(Code* recompiled) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013781 DCHECK(!has_deoptimization_support());
13782 DisallowHeapAllocation no_allocation;
Ben Murdochb0fe1622011-05-05 13:52:32 +010013783 Code* code = this->code();
13784 if (IsCodeEquivalent(code, recompiled)) {
13785 // Copy the deoptimization data from the recompiled code.
13786 code->set_deoptimization_data(recompiled->deoptimization_data());
13787 code->set_has_deoptimization_support(true);
13788 } else {
13789 // TODO(3025757): In case the recompiled isn't equivalent to the
13790 // old code, we have to replace it. We should try to avoid this
13791 // altogether because it flushes valuable type feedback by
13792 // effectively resetting all IC state.
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013793 ReplaceCode(recompiled);
Ben Murdochb0fe1622011-05-05 13:52:32 +010013794 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013795 DCHECK(has_deoptimization_support());
Ben Murdochb0fe1622011-05-05 13:52:32 +010013796}
13797
13798
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013799void SharedFunctionInfo::DisableOptimization(BailoutReason reason) {
Ben Murdoch257744e2011-11-30 15:57:28 +000013800 // Disable optimization for the shared function info and mark the
13801 // code as non-optimizable. The marker on the shared function info
13802 // is there because we flush non-optimized code thereby loosing the
13803 // non-optimizable information for the code. When the code is
13804 // regenerated and set on the shared function info it is marked as
13805 // non-optimizable if optimization is disabled for the shared
13806 // function info.
Emily Bernierd0a1eb72015-03-24 16:35:39 -040013807 DCHECK(reason != kNoReason);
Ben Murdoch257744e2011-11-30 15:57:28 +000013808 set_optimization_disabled(true);
Emily Bernierd0a1eb72015-03-24 16:35:39 -040013809 set_disable_optimization_reason(reason);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000013810 // Code should be the lazy compilation stub or else unoptimized.
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013811 DCHECK(code()->kind() == Code::FUNCTION || code()->kind() == Code::BUILTIN);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013812 PROFILE(GetIsolate(), CodeDisableOptEvent(code(), this));
Ben Murdoch257744e2011-11-30 15:57:28 +000013813 if (FLAG_trace_opt) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013814 PrintF("[disabled optimization for ");
13815 ShortPrint();
13816 PrintF(", reason: %s]\n", GetBailoutReason(reason));
Ben Murdoch257744e2011-11-30 15:57:28 +000013817 }
13818}
13819
13820
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000013821void SharedFunctionInfo::InitFromFunctionLiteral(
13822 Handle<SharedFunctionInfo> shared_info, FunctionLiteral* lit) {
13823 shared_info->set_length(lit->scope()->default_function_length());
13824 shared_info->set_internal_formal_parameter_count(lit->parameter_count());
13825 shared_info->set_function_token_position(lit->function_token_position());
13826 shared_info->set_start_position(lit->start_position());
13827 shared_info->set_end_position(lit->end_position());
Ben Murdoch097c5b22016-05-18 11:27:45 +010013828 shared_info->set_is_declaration(lit->is_declaration());
13829 shared_info->set_is_named_expression(lit->is_named_expression());
13830 shared_info->set_is_anonymous_expression(lit->is_anonymous_expression());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000013831 shared_info->set_inferred_name(*lit->inferred_name());
13832 shared_info->set_allows_lazy_compilation(lit->AllowsLazyCompilation());
13833 shared_info->set_allows_lazy_compilation_without_context(
13834 lit->AllowsLazyCompilationWithoutContext());
13835 shared_info->set_language_mode(lit->language_mode());
13836 shared_info->set_uses_arguments(lit->scope()->arguments() != NULL);
13837 shared_info->set_has_duplicate_parameters(lit->has_duplicate_parameters());
13838 shared_info->set_ast_node_count(lit->ast_node_count());
13839 shared_info->set_is_function(lit->is_function());
13840 if (lit->dont_optimize_reason() != kNoReason) {
13841 shared_info->DisableOptimization(lit->dont_optimize_reason());
13842 }
13843 shared_info->set_dont_crankshaft(lit->flags() &
13844 AstProperties::kDontCrankshaft);
13845 shared_info->set_kind(lit->kind());
13846 if (!IsConstructable(lit->kind(), lit->language_mode())) {
13847 shared_info->set_construct_stub(
13848 *shared_info->GetIsolate()->builtins()->ConstructedNonConstructable());
13849 }
13850 shared_info->set_needs_home_object(lit->scope()->NeedsHomeObject());
13851 shared_info->set_asm_function(lit->scope()->asm_function());
13852}
13853
13854
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013855bool SharedFunctionInfo::VerifyBailoutId(BailoutId id) {
13856 DCHECK(!id.IsNone());
Ben Murdochb0fe1622011-05-05 13:52:32 +010013857 Code* unoptimized = code();
13858 DeoptimizationOutputData* data =
13859 DeoptimizationOutputData::cast(unoptimized->deoptimization_data());
13860 unsigned ignore = Deoptimizer::GetOutputInfo(data, id, this);
13861 USE(ignore);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013862 return true; // Return true if there was no DCHECK.
Ben Murdochb0fe1622011-05-05 13:52:32 +010013863}
13864
13865
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000013866void Map::StartInobjectSlackTracking() {
13867 DCHECK(!IsInobjectSlackTrackingInProgress());
Ben Murdoch3ef787d2012-04-12 10:51:47 +010013868
Kristian Monsen0d5e1162010-09-30 15:31:59 +010013869 // No tracking during the snapshot construction phase.
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013870 Isolate* isolate = GetIsolate();
13871 if (isolate->serializer_enabled()) return;
Kristian Monsen0d5e1162010-09-30 15:31:59 +010013872
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000013873 if (unused_property_fields() == 0) return;
Kristian Monsen0d5e1162010-09-30 15:31:59 +010013874
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000013875 set_construction_counter(Map::kSlackTrackingCounterStart);
Kristian Monsen0d5e1162010-09-30 15:31:59 +010013876}
13877
13878
Ben Murdoch8f9999f2012-04-23 10:39:17 +010013879void SharedFunctionInfo::ResetForNewContext(int new_ic_age) {
13880 code()->ClearInlineCaches();
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013881 // If we clear ICs, we need to clear the type feedback vector too, since
13882 // CallICs are synced with a feedback vector slot.
13883 ClearTypeFeedbackInfo();
Ben Murdoch8f9999f2012-04-23 10:39:17 +010013884 set_ic_age(new_ic_age);
13885 if (code()->kind() == Code::FUNCTION) {
13886 code()->set_profiler_ticks(0);
13887 if (optimization_disabled() &&
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013888 opt_count() >= FLAG_max_opt_count) {
Ben Murdoch8f9999f2012-04-23 10:39:17 +010013889 // Re-enable optimizations if they were disabled due to opt_count limit.
13890 set_optimization_disabled(false);
Ben Murdoch8f9999f2012-04-23 10:39:17 +010013891 }
13892 set_opt_count(0);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013893 set_deopt_count(0);
Ben Murdoch8f9999f2012-04-23 10:39:17 +010013894 }
13895}
13896
13897
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000013898int SharedFunctionInfo::SearchOptimizedCodeMapEntry(Context* native_context,
13899 BailoutId osr_ast_id) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013900 DisallowHeapAllocation no_gc;
13901 DCHECK(native_context->IsNativeContext());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000013902 if (!OptimizedCodeMapIsCleared()) {
13903 FixedArray* optimized_code_map = this->optimized_code_map();
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013904 int length = optimized_code_map->length();
13905 Smi* osr_ast_id_smi = Smi::FromInt(osr_ast_id.ToInt());
13906 for (int i = kEntriesStart; i < length; i += kEntryLength) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000013907 if (WeakCell::cast(optimized_code_map->get(i + kContextOffset))
13908 ->value() == native_context &&
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013909 optimized_code_map->get(i + kOsrAstIdOffset) == osr_ast_id_smi) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000013910 return i;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013911 }
13912 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000013913 Object* shared_code =
13914 WeakCell::cast(optimized_code_map->get(kSharedCodeIndex))->value();
13915 if (shared_code->IsCode() && osr_ast_id.IsNone()) {
13916 return kSharedCodeIndex;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013917 }
13918 }
13919 return -1;
Ben Murdoch8f9999f2012-04-23 10:39:17 +010013920}
13921
13922
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000013923CodeAndLiterals SharedFunctionInfo::SearchOptimizedCodeMap(
13924 Context* native_context, BailoutId osr_ast_id) {
13925 CodeAndLiterals result = {nullptr, nullptr};
13926 int entry = SearchOptimizedCodeMapEntry(native_context, osr_ast_id);
13927 if (entry != kNotFound) {
13928 FixedArray* code_map = optimized_code_map();
13929 if (entry == kSharedCodeIndex) {
13930 // We know the weak cell isn't cleared because we made sure of it in
13931 // SearchOptimizedCodeMapEntry and performed no allocations since that
13932 // call.
13933 result = {
13934 Code::cast(WeakCell::cast(code_map->get(kSharedCodeIndex))->value()),
13935 nullptr};
13936 } else {
13937 DCHECK_LE(entry + kEntryLength, code_map->length());
13938 WeakCell* cell = WeakCell::cast(code_map->get(entry + kCachedCodeOffset));
13939 WeakCell* literals_cell =
13940 WeakCell::cast(code_map->get(entry + kLiteralsOffset));
13941
13942 result = {cell->cleared() ? nullptr : Code::cast(cell->value()),
13943 literals_cell->cleared()
13944 ? nullptr
13945 : LiteralsArray::cast(literals_cell->value())};
13946 }
13947 }
13948 if (FLAG_trace_opt && !OptimizedCodeMapIsCleared() &&
13949 result.code == nullptr) {
13950 PrintF("[didn't find optimized code in optimized code map for ");
13951 ShortPrint();
13952 PrintF("]\n");
13953 }
13954 return result;
13955}
13956
13957
Ben Murdoch3ef787d2012-04-12 10:51:47 +010013958#define DECLARE_TAG(ignore1, name, ignore2) name,
13959const char* const VisitorSynchronization::kTags[
13960 VisitorSynchronization::kNumberOfSyncTags] = {
13961 VISITOR_SYNCHRONIZATION_TAGS_LIST(DECLARE_TAG)
13962};
13963#undef DECLARE_TAG
13964
13965
13966#define DECLARE_TAG(ignore1, ignore2, name) name,
13967const char* const VisitorSynchronization::kTagNames[
13968 VisitorSynchronization::kNumberOfSyncTags] = {
13969 VISITOR_SYNCHRONIZATION_TAGS_LIST(DECLARE_TAG)
13970};
13971#undef DECLARE_TAG
13972
13973
Steve Blocka7e24c12009-10-30 11:49:00 +000013974void ObjectVisitor::VisitCodeTarget(RelocInfo* rinfo) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013975 DCHECK(RelocInfo::IsCodeTarget(rinfo->rmode()));
Steve Blocka7e24c12009-10-30 11:49:00 +000013976 Object* target = Code::GetCodeFromTargetAddress(rinfo->target_address());
13977 Object* old_target = target;
13978 VisitPointer(&target);
13979 CHECK_EQ(target, old_target); // VisitPointer doesn't change Code* *target.
13980}
13981
13982
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013983void ObjectVisitor::VisitCodeAgeSequence(RelocInfo* rinfo) {
13984 DCHECK(RelocInfo::IsCodeAgeSequence(rinfo->rmode()));
13985 Object* stub = rinfo->code_age_stub();
13986 if (stub) {
13987 VisitPointer(&stub);
13988 }
13989}
13990
13991
Steve Block791712a2010-08-27 10:21:07 +010013992void ObjectVisitor::VisitCodeEntry(Address entry_address) {
13993 Object* code = Code::GetObjectFromEntryAddress(entry_address);
13994 Object* old_code = code;
13995 VisitPointer(&code);
13996 if (code != old_code) {
13997 Memory::Address_at(entry_address) = reinterpret_cast<Code*>(code)->entry();
13998 }
13999}
14000
14001
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014002void ObjectVisitor::VisitCell(RelocInfo* rinfo) {
14003 DCHECK(rinfo->rmode() == RelocInfo::CELL);
Ben Murdochb0fe1622011-05-05 13:52:32 +010014004 Object* cell = rinfo->target_cell();
14005 Object* old_cell = cell;
14006 VisitPointer(&cell);
14007 if (cell != old_cell) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014008 rinfo->set_target_cell(reinterpret_cast<Cell*>(cell));
Ben Murdochb0fe1622011-05-05 13:52:32 +010014009 }
14010}
14011
14012
Steve Blocka7e24c12009-10-30 11:49:00 +000014013void ObjectVisitor::VisitDebugTarget(RelocInfo* rinfo) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000014014 DCHECK(RelocInfo::IsDebugBreakSlot(rinfo->rmode()) &&
14015 rinfo->IsPatchedDebugBreakSlotSequence());
14016 Object* target = Code::GetCodeFromTargetAddress(rinfo->debug_call_address());
Steve Blocka7e24c12009-10-30 11:49:00 +000014017 Object* old_target = target;
14018 VisitPointer(&target);
14019 CHECK_EQ(target, old_target); // VisitPointer doesn't change Code* *target.
14020}
14021
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014022
Ben Murdoch3ef787d2012-04-12 10:51:47 +010014023void ObjectVisitor::VisitEmbeddedPointer(RelocInfo* rinfo) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014024 DCHECK(rinfo->rmode() == RelocInfo::EMBEDDED_OBJECT);
14025 Object* p = rinfo->target_object();
14026 VisitPointer(&p);
Ben Murdoch3ef787d2012-04-12 10:51:47 +010014027}
14028
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014029
Ben Murdoch3ef787d2012-04-12 10:51:47 +010014030void ObjectVisitor::VisitExternalReference(RelocInfo* rinfo) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000014031 Address p = rinfo->target_external_reference();
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014032 VisitExternalReference(&p);
Ben Murdoch3ef787d2012-04-12 10:51:47 +010014033}
14034
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014035
Ben Murdochb0fe1622011-05-05 13:52:32 +010014036void Code::InvalidateRelocation() {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014037 InvalidateEmbeddedObjects();
Ben Murdoch3ef787d2012-04-12 10:51:47 +010014038 set_relocation_info(GetHeap()->empty_byte_array());
Ben Murdochb0fe1622011-05-05 13:52:32 +010014039}
14040
14041
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014042void Code::InvalidateEmbeddedObjects() {
14043 Object* undefined = GetHeap()->undefined_value();
14044 Cell* undefined_cell = GetHeap()->undefined_cell();
14045 int mode_mask = RelocInfo::ModeMask(RelocInfo::EMBEDDED_OBJECT) |
14046 RelocInfo::ModeMask(RelocInfo::CELL);
14047 for (RelocIterator it(this, mode_mask); !it.done(); it.next()) {
14048 RelocInfo::Mode mode = it.rinfo()->rmode();
14049 if (mode == RelocInfo::EMBEDDED_OBJECT) {
14050 it.rinfo()->set_target_object(undefined, SKIP_WRITE_BARRIER);
14051 } else if (mode == RelocInfo::CELL) {
14052 it.rinfo()->set_target_cell(undefined_cell, SKIP_WRITE_BARRIER);
14053 }
14054 }
14055}
14056
14057
Steve Blockd0582a62009-12-15 09:54:21 +000014058void Code::Relocate(intptr_t delta) {
Steve Blocka7e24c12009-10-30 11:49:00 +000014059 for (RelocIterator it(this, RelocInfo::kApplyMask); !it.done(); it.next()) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000014060 it.rinfo()->apply(delta);
Steve Blocka7e24c12009-10-30 11:49:00 +000014061 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000014062 Assembler::FlushICache(GetIsolate(), instruction_start(), instruction_size());
Steve Blocka7e24c12009-10-30 11:49:00 +000014063}
14064
14065
14066void Code::CopyFrom(const CodeDesc& desc) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014067 DCHECK(Marking::Color(this) == Marking::WHITE_OBJECT);
Ben Murdoch3ef787d2012-04-12 10:51:47 +010014068
Steve Blocka7e24c12009-10-30 11:49:00 +000014069 // copy code
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014070 CopyBytes(instruction_start(), desc.buffer,
14071 static_cast<size_t>(desc.instr_size));
Steve Blocka7e24c12009-10-30 11:49:00 +000014072
Steve Blocka7e24c12009-10-30 11:49:00 +000014073 // copy reloc info
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014074 CopyBytes(relocation_start(),
14075 desc.buffer + desc.buffer_size - desc.reloc_size,
14076 static_cast<size_t>(desc.reloc_size));
Steve Blocka7e24c12009-10-30 11:49:00 +000014077
14078 // unbox handles and relocate
Steve Block3ce2e202009-11-05 08:53:23 +000014079 intptr_t delta = instruction_start() - desc.buffer;
Steve Blocka7e24c12009-10-30 11:49:00 +000014080 int mode_mask = RelocInfo::kCodeTargetMask |
14081 RelocInfo::ModeMask(RelocInfo::EMBEDDED_OBJECT) |
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014082 RelocInfo::ModeMask(RelocInfo::CELL) |
14083 RelocInfo::ModeMask(RelocInfo::RUNTIME_ENTRY) |
Steve Blocka7e24c12009-10-30 11:49:00 +000014084 RelocInfo::kApplyMask;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014085 // Needed to find target_object and runtime_entry on X64
14086 Assembler* origin = desc.origin;
14087 AllowDeferredHandleDereference embedding_raw_address;
Steve Blocka7e24c12009-10-30 11:49:00 +000014088 for (RelocIterator it(this, mode_mask); !it.done(); it.next()) {
14089 RelocInfo::Mode mode = it.rinfo()->rmode();
14090 if (mode == RelocInfo::EMBEDDED_OBJECT) {
Steve Block3ce2e202009-11-05 08:53:23 +000014091 Handle<Object> p = it.rinfo()->target_object_handle(origin);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014092 it.rinfo()->set_target_object(*p, SKIP_WRITE_BARRIER, SKIP_ICACHE_FLUSH);
14093 } else if (mode == RelocInfo::CELL) {
14094 Handle<Cell> cell = it.rinfo()->target_cell_handle();
14095 it.rinfo()->set_target_cell(*cell, SKIP_WRITE_BARRIER, SKIP_ICACHE_FLUSH);
Steve Blocka7e24c12009-10-30 11:49:00 +000014096 } else if (RelocInfo::IsCodeTarget(mode)) {
14097 // rewrite code handles in inline cache targets to direct
14098 // pointers to the first instruction in the code object
Steve Block3ce2e202009-11-05 08:53:23 +000014099 Handle<Object> p = it.rinfo()->target_object_handle(origin);
Steve Blocka7e24c12009-10-30 11:49:00 +000014100 Code* code = Code::cast(*p);
Ben Murdoch3ef787d2012-04-12 10:51:47 +010014101 it.rinfo()->set_target_address(code->instruction_start(),
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014102 SKIP_WRITE_BARRIER,
14103 SKIP_ICACHE_FLUSH);
14104 } else if (RelocInfo::IsRuntimeEntry(mode)) {
14105 Address p = it.rinfo()->target_runtime_entry(origin);
14106 it.rinfo()->set_target_runtime_entry(p, SKIP_WRITE_BARRIER,
14107 SKIP_ICACHE_FLUSH);
14108 } else if (mode == RelocInfo::CODE_AGE_SEQUENCE) {
14109 Handle<Object> p = it.rinfo()->code_age_stub_handle(origin);
14110 Code* code = Code::cast(*p);
14111 it.rinfo()->set_code_age_stub(code, SKIP_ICACHE_FLUSH);
Steve Blocka7e24c12009-10-30 11:49:00 +000014112 } else {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000014113 it.rinfo()->apply(delta);
Steve Blocka7e24c12009-10-30 11:49:00 +000014114 }
14115 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000014116 Assembler::FlushICache(GetIsolate(), instruction_start(), instruction_size());
Steve Blocka7e24c12009-10-30 11:49:00 +000014117}
14118
Ben Murdoch097c5b22016-05-18 11:27:45 +010014119// Locate the source position which is closest to the code offset. This is
14120// using the source position information embedded in the relocation info.
Steve Blocka7e24c12009-10-30 11:49:00 +000014121// The position returned is relative to the beginning of the script where the
14122// source for this function is found.
Ben Murdoch097c5b22016-05-18 11:27:45 +010014123int Code::SourcePosition(int code_offset) {
14124 Address pc = instruction_start() + code_offset;
Steve Blocka7e24c12009-10-30 11:49:00 +000014125 int distance = kMaxInt;
14126 int position = RelocInfo::kNoPosition; // Initially no position found.
14127 // Run through all the relocation info to find the best matching source
14128 // position. All the code needs to be considered as the sequence of the
14129 // instructions in the code does not necessarily follow the same order as the
14130 // source.
14131 RelocIterator it(this, RelocInfo::kPositionMask);
14132 while (!it.done()) {
14133 // Only look at positions after the current pc.
14134 if (it.rinfo()->pc() < pc) {
14135 // Get position and distance.
Steve Blockd0582a62009-12-15 09:54:21 +000014136
14137 int dist = static_cast<int>(pc - it.rinfo()->pc());
14138 int pos = static_cast<int>(it.rinfo()->data());
Steve Blocka7e24c12009-10-30 11:49:00 +000014139 // If this position is closer than the current candidate or if it has the
14140 // same distance as the current candidate and the position is higher then
14141 // this position is the new candidate.
14142 if ((dist < distance) ||
14143 (dist == distance && pos > position)) {
14144 position = pos;
14145 distance = dist;
14146 }
14147 }
14148 it.next();
14149 }
14150 return position;
14151}
14152
14153
14154// Same as Code::SourcePosition above except it only looks for statement
14155// positions.
Ben Murdoch097c5b22016-05-18 11:27:45 +010014156int Code::SourceStatementPosition(int code_offset) {
Steve Blocka7e24c12009-10-30 11:49:00 +000014157 // First find the position as close as possible using all position
14158 // information.
Ben Murdoch097c5b22016-05-18 11:27:45 +010014159 int position = SourcePosition(code_offset);
Steve Blocka7e24c12009-10-30 11:49:00 +000014160 // Now find the closest statement position before the position.
14161 int statement_position = 0;
14162 RelocIterator it(this, RelocInfo::kPositionMask);
14163 while (!it.done()) {
14164 if (RelocInfo::IsStatementPosition(it.rinfo()->rmode())) {
Steve Blockd0582a62009-12-15 09:54:21 +000014165 int p = static_cast<int>(it.rinfo()->data());
Steve Blocka7e24c12009-10-30 11:49:00 +000014166 if (statement_position < p && p <= position) {
14167 statement_position = p;
14168 }
14169 }
14170 it.next();
14171 }
14172 return statement_position;
14173}
14174
14175
Ben Murdochb8e0da22011-05-16 14:20:40 +010014176SafepointEntry Code::GetSafepointEntry(Address pc) {
Ben Murdochb0fe1622011-05-05 13:52:32 +010014177 SafepointTable table(this);
Ben Murdochb8e0da22011-05-16 14:20:40 +010014178 return table.FindEntry(pc);
Ben Murdochb0fe1622011-05-05 13:52:32 +010014179}
14180
14181
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014182Object* Code::FindNthObject(int n, Map* match_map) {
14183 DCHECK(is_inline_cache_stub());
14184 DisallowHeapAllocation no_allocation;
Ben Murdochb0fe1622011-05-05 13:52:32 +010014185 int mask = RelocInfo::ModeMask(RelocInfo::EMBEDDED_OBJECT);
14186 for (RelocIterator it(this, mask); !it.done(); it.next()) {
14187 RelocInfo* info = it.rinfo();
14188 Object* object = info->target_object();
Emily Bernierd0a1eb72015-03-24 16:35:39 -040014189 if (object->IsWeakCell()) object = WeakCell::cast(object)->value();
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014190 if (object->IsHeapObject()) {
14191 if (HeapObject::cast(object)->map() == match_map) {
14192 if (--n == 0) return object;
14193 }
14194 }
14195 }
14196 return NULL;
14197}
14198
14199
14200AllocationSite* Code::FindFirstAllocationSite() {
14201 Object* result = FindNthObject(1, GetHeap()->allocation_site_map());
14202 return (result != NULL) ? AllocationSite::cast(result) : NULL;
14203}
14204
14205
14206Map* Code::FindFirstMap() {
14207 Object* result = FindNthObject(1, GetHeap()->meta_map());
14208 return (result != NULL) ? Map::cast(result) : NULL;
14209}
14210
14211
14212void Code::FindAndReplace(const FindAndReplacePattern& pattern) {
14213 DCHECK(is_inline_cache_stub() || is_handler());
14214 DisallowHeapAllocation no_allocation;
14215 int mask = RelocInfo::ModeMask(RelocInfo::EMBEDDED_OBJECT);
14216 STATIC_ASSERT(FindAndReplacePattern::kMaxCount < 32);
14217 int current_pattern = 0;
14218 for (RelocIterator it(this, mask); !it.done(); it.next()) {
14219 RelocInfo* info = it.rinfo();
14220 Object* object = info->target_object();
14221 if (object->IsHeapObject()) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -040014222 if (object->IsWeakCell()) {
14223 object = HeapObject::cast(WeakCell::cast(object)->value());
14224 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014225 Map* map = HeapObject::cast(object)->map();
14226 if (map == *pattern.find_[current_pattern]) {
14227 info->set_target_object(*pattern.replace_[current_pattern]);
14228 if (++current_pattern == pattern.count_) return;
14229 }
14230 }
14231 }
14232 UNREACHABLE();
14233}
14234
14235
14236void Code::FindAllMaps(MapHandleList* maps) {
14237 DCHECK(is_inline_cache_stub());
14238 DisallowHeapAllocation no_allocation;
14239 int mask = RelocInfo::ModeMask(RelocInfo::EMBEDDED_OBJECT);
14240 for (RelocIterator it(this, mask); !it.done(); it.next()) {
14241 RelocInfo* info = it.rinfo();
14242 Object* object = info->target_object();
Emily Bernierd0a1eb72015-03-24 16:35:39 -040014243 if (object->IsWeakCell()) object = WeakCell::cast(object)->value();
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014244 if (object->IsMap()) maps->Add(handle(Map::cast(object)));
14245 }
14246}
14247
14248
14249Code* Code::FindFirstHandler() {
14250 DCHECK(is_inline_cache_stub());
14251 DisallowHeapAllocation no_allocation;
Emily Bernierd0a1eb72015-03-24 16:35:39 -040014252 int mask = RelocInfo::ModeMask(RelocInfo::CODE_TARGET) |
14253 RelocInfo::ModeMask(RelocInfo::EMBEDDED_OBJECT);
14254 bool skip_next_handler = false;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014255 for (RelocIterator it(this, mask); !it.done(); it.next()) {
14256 RelocInfo* info = it.rinfo();
Emily Bernierd0a1eb72015-03-24 16:35:39 -040014257 if (info->rmode() == RelocInfo::EMBEDDED_OBJECT) {
14258 Object* obj = info->target_object();
14259 skip_next_handler |= obj->IsWeakCell() && WeakCell::cast(obj)->cleared();
14260 } else {
14261 Code* code = Code::GetCodeFromTargetAddress(info->target_address());
14262 if (code->kind() == Code::HANDLER) {
14263 if (!skip_next_handler) return code;
14264 skip_next_handler = false;
14265 }
14266 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014267 }
14268 return NULL;
14269}
14270
14271
14272bool Code::FindHandlers(CodeHandleList* code_list, int length) {
14273 DCHECK(is_inline_cache_stub());
14274 DisallowHeapAllocation no_allocation;
Emily Bernierd0a1eb72015-03-24 16:35:39 -040014275 int mask = RelocInfo::ModeMask(RelocInfo::CODE_TARGET) |
14276 RelocInfo::ModeMask(RelocInfo::EMBEDDED_OBJECT);
14277 bool skip_next_handler = false;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014278 int i = 0;
14279 for (RelocIterator it(this, mask); !it.done(); it.next()) {
14280 if (i == length) return true;
14281 RelocInfo* info = it.rinfo();
Emily Bernierd0a1eb72015-03-24 16:35:39 -040014282 if (info->rmode() == RelocInfo::EMBEDDED_OBJECT) {
14283 Object* obj = info->target_object();
14284 skip_next_handler |= obj->IsWeakCell() && WeakCell::cast(obj)->cleared();
14285 } else {
14286 Code* code = Code::GetCodeFromTargetAddress(info->target_address());
14287 // IC stubs with handlers never contain non-handler code objects before
14288 // handler targets.
14289 if (code->kind() != Code::HANDLER) break;
14290 if (!skip_next_handler) {
14291 code_list->Add(Handle<Code>(code));
14292 i++;
14293 }
14294 skip_next_handler = false;
14295 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014296 }
14297 return i == length;
14298}
14299
14300
14301MaybeHandle<Code> Code::FindHandlerForMap(Map* map) {
14302 DCHECK(is_inline_cache_stub());
14303 int mask = RelocInfo::ModeMask(RelocInfo::CODE_TARGET) |
14304 RelocInfo::ModeMask(RelocInfo::EMBEDDED_OBJECT);
14305 bool return_next = false;
14306 for (RelocIterator it(this, mask); !it.done(); it.next()) {
14307 RelocInfo* info = it.rinfo();
14308 if (info->rmode() == RelocInfo::EMBEDDED_OBJECT) {
14309 Object* object = info->target_object();
Emily Bernierd0a1eb72015-03-24 16:35:39 -040014310 if (object->IsWeakCell()) object = WeakCell::cast(object)->value();
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014311 if (object == map) return_next = true;
14312 } else if (return_next) {
14313 Code* code = Code::GetCodeFromTargetAddress(info->target_address());
14314 DCHECK(code->kind() == Code::HANDLER);
14315 return handle(code);
14316 }
14317 }
14318 return MaybeHandle<Code>();
14319}
14320
14321
14322Name* Code::FindFirstName() {
14323 DCHECK(is_inline_cache_stub());
14324 DisallowHeapAllocation no_allocation;
14325 int mask = RelocInfo::ModeMask(RelocInfo::EMBEDDED_OBJECT);
14326 for (RelocIterator it(this, mask); !it.done(); it.next()) {
14327 RelocInfo* info = it.rinfo();
14328 Object* object = info->target_object();
14329 if (object->IsName()) return Name::cast(object);
Ben Murdochb0fe1622011-05-05 13:52:32 +010014330 }
14331 return NULL;
14332}
14333
14334
Ben Murdoch8f9999f2012-04-23 10:39:17 +010014335void Code::ClearInlineCaches() {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014336 ClearInlineCaches(NULL);
14337}
14338
14339
14340void Code::ClearInlineCaches(Code::Kind kind) {
14341 ClearInlineCaches(&kind);
14342}
14343
14344
14345void Code::ClearInlineCaches(Code::Kind* kind) {
Ben Murdoch8f9999f2012-04-23 10:39:17 +010014346 int mask = RelocInfo::ModeMask(RelocInfo::CODE_TARGET) |
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014347 RelocInfo::ModeMask(RelocInfo::CODE_TARGET_WITH_ID);
Ben Murdoch8f9999f2012-04-23 10:39:17 +010014348 for (RelocIterator it(this, mask); !it.done(); it.next()) {
14349 RelocInfo* info = it.rinfo();
14350 Code* target(Code::GetCodeFromTargetAddress(info->target_address()));
14351 if (target->is_inline_cache_stub()) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014352 if (kind == NULL || *kind == target->kind()) {
14353 IC::Clear(this->GetIsolate(), info->pc(),
14354 info->host()->constant_pool());
14355 }
Ben Murdoch8f9999f2012-04-23 10:39:17 +010014356 }
14357 }
14358}
14359
Ben Murdoch097c5b22016-05-18 11:27:45 +010014360int AbstractCode::SourcePosition(int offset) {
14361 return IsBytecodeArray() ? GetBytecodeArray()->SourcePosition(offset)
14362 : GetCode()->SourcePosition(offset);
14363}
14364
14365int AbstractCode::SourceStatementPosition(int offset) {
14366 return IsBytecodeArray() ? GetBytecodeArray()->SourceStatementPosition(offset)
14367 : GetCode()->SourceStatementPosition(offset);
14368}
Ben Murdoch8f9999f2012-04-23 10:39:17 +010014369
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014370void SharedFunctionInfo::ClearTypeFeedbackInfo() {
Emily Bernierd0a1eb72015-03-24 16:35:39 -040014371 feedback_vector()->ClearSlots(this);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014372}
14373
14374
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000014375void SharedFunctionInfo::ClearTypeFeedbackInfoAtGCTime() {
14376 feedback_vector()->ClearSlotsAtGCTime(this);
14377}
14378
14379
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014380BailoutId Code::TranslatePcOffsetToAstId(uint32_t pc_offset) {
14381 DisallowHeapAllocation no_gc;
14382 DCHECK(kind() == FUNCTION);
14383 BackEdgeTable back_edges(this, &no_gc);
14384 for (uint32_t i = 0; i < back_edges.length(); i++) {
14385 if (back_edges.pc_offset(i) == pc_offset) return back_edges.ast_id(i);
14386 }
14387 return BailoutId::None();
14388}
14389
14390
14391uint32_t Code::TranslateAstIdToPcOffset(BailoutId ast_id) {
14392 DisallowHeapAllocation no_gc;
14393 DCHECK(kind() == FUNCTION);
14394 BackEdgeTable back_edges(this, &no_gc);
14395 for (uint32_t i = 0; i < back_edges.length(); i++) {
14396 if (back_edges.ast_id(i) == ast_id) return back_edges.pc_offset(i);
14397 }
14398 UNREACHABLE(); // We expect to find the back edge.
14399 return 0;
14400}
14401
14402
14403void Code::MakeCodeAgeSequenceYoung(byte* sequence, Isolate* isolate) {
14404 PatchPlatformCodeAge(isolate, sequence, kNoAgeCodeAge, NO_MARKING_PARITY);
14405}
14406
14407
14408void Code::MarkCodeAsExecuted(byte* sequence, Isolate* isolate) {
14409 PatchPlatformCodeAge(isolate, sequence, kExecutedOnceCodeAge,
14410 NO_MARKING_PARITY);
14411}
14412
14413
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000014414// NextAge defines the Code::Age state transitions during a GC cycle.
14415static Code::Age NextAge(Code::Age age) {
14416 switch (age) {
14417 case Code::kNotExecutedCodeAge: // Keep, until we've been executed.
14418 case Code::kToBeExecutedOnceCodeAge: // Keep, until we've been executed.
14419 case Code::kLastCodeAge: // Clamp at last Code::Age value.
14420 return age;
14421 case Code::kExecutedOnceCodeAge:
14422 // Pre-age code that has only been executed once.
14423 return static_cast<Code::Age>(Code::kPreAgedCodeAge + 1);
14424 default:
14425 return static_cast<Code::Age>(age + 1); // Default case: Increase age.
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014426 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000014427}
14428
14429
14430// IsOldAge defines the collection criteria for a Code object.
14431static bool IsOldAge(Code::Age age) {
14432 return age >= Code::kIsOldCodeAge || age == Code::kNotExecutedCodeAge;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014433}
14434
14435
Emily Bernierd0a1eb72015-03-24 16:35:39 -040014436void Code::MakeYoung(Isolate* isolate) {
14437 byte* sequence = FindCodeAgeSequence();
14438 if (sequence != NULL) MakeCodeAgeSequenceYoung(sequence, isolate);
14439}
14440
14441
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000014442void Code::MarkToBeExecutedOnce(Isolate* isolate) {
14443 byte* sequence = FindCodeAgeSequence();
14444 if (sequence != NULL) {
14445 PatchPlatformCodeAge(isolate, sequence, kToBeExecutedOnceCodeAge,
14446 NO_MARKING_PARITY);
14447 }
14448}
14449
14450
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014451void Code::MakeOlder(MarkingParity current_parity) {
14452 byte* sequence = FindCodeAgeSequence();
14453 if (sequence != NULL) {
14454 Age age;
14455 MarkingParity code_parity;
14456 Isolate* isolate = GetIsolate();
14457 GetCodeAgeAndParity(isolate, sequence, &age, &code_parity);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000014458 Age next_age = NextAge(age);
14459 if (age != next_age && code_parity != current_parity) {
14460 PatchPlatformCodeAge(isolate, sequence, next_age, current_parity);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014461 }
14462 }
14463}
14464
14465
14466bool Code::IsOld() {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000014467 return IsOldAge(GetAge());
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014468}
14469
14470
14471byte* Code::FindCodeAgeSequence() {
14472 return FLAG_age_code &&
14473 prologue_offset() != Code::kPrologueOffsetNotSet &&
14474 (kind() == OPTIMIZED_FUNCTION ||
14475 (kind() == FUNCTION && !has_debug_break_slots()))
14476 ? instruction_start() + prologue_offset()
14477 : NULL;
14478}
14479
14480
14481Code::Age Code::GetAge() {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014482 byte* sequence = FindCodeAgeSequence();
14483 if (sequence == NULL) {
14484 return kNoAgeCodeAge;
14485 }
14486 Age age;
14487 MarkingParity parity;
14488 GetCodeAgeAndParity(GetIsolate(), sequence, &age, &parity);
14489 return age;
14490}
14491
14492
14493void Code::GetCodeAgeAndParity(Code* code, Age* age,
14494 MarkingParity* parity) {
14495 Isolate* isolate = code->GetIsolate();
14496 Builtins* builtins = isolate->builtins();
14497 Code* stub = NULL;
14498#define HANDLE_CODE_AGE(AGE) \
14499 stub = *builtins->Make##AGE##CodeYoungAgainEvenMarking(); \
14500 if (code == stub) { \
14501 *age = k##AGE##CodeAge; \
14502 *parity = EVEN_MARKING_PARITY; \
14503 return; \
14504 } \
14505 stub = *builtins->Make##AGE##CodeYoungAgainOddMarking(); \
14506 if (code == stub) { \
14507 *age = k##AGE##CodeAge; \
14508 *parity = ODD_MARKING_PARITY; \
14509 return; \
14510 }
14511 CODE_AGE_LIST(HANDLE_CODE_AGE)
14512#undef HANDLE_CODE_AGE
14513 stub = *builtins->MarkCodeAsExecutedOnce();
14514 if (code == stub) {
14515 *age = kNotExecutedCodeAge;
14516 *parity = NO_MARKING_PARITY;
14517 return;
14518 }
14519 stub = *builtins->MarkCodeAsExecutedTwice();
14520 if (code == stub) {
14521 *age = kExecutedOnceCodeAge;
14522 *parity = NO_MARKING_PARITY;
14523 return;
14524 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000014525 stub = *builtins->MarkCodeAsToBeExecutedOnce();
14526 if (code == stub) {
14527 *age = kToBeExecutedOnceCodeAge;
14528 *parity = NO_MARKING_PARITY;
14529 return;
14530 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014531 UNREACHABLE();
14532}
14533
14534
14535Code* Code::GetCodeAgeStub(Isolate* isolate, Age age, MarkingParity parity) {
14536 Builtins* builtins = isolate->builtins();
14537 switch (age) {
14538#define HANDLE_CODE_AGE(AGE) \
14539 case k##AGE##CodeAge: { \
14540 Code* stub = parity == EVEN_MARKING_PARITY \
14541 ? *builtins->Make##AGE##CodeYoungAgainEvenMarking() \
14542 : *builtins->Make##AGE##CodeYoungAgainOddMarking(); \
14543 return stub; \
14544 }
14545 CODE_AGE_LIST(HANDLE_CODE_AGE)
14546#undef HANDLE_CODE_AGE
14547 case kNotExecutedCodeAge: {
14548 DCHECK(parity == NO_MARKING_PARITY);
14549 return *builtins->MarkCodeAsExecutedOnce();
14550 }
14551 case kExecutedOnceCodeAge: {
14552 DCHECK(parity == NO_MARKING_PARITY);
14553 return *builtins->MarkCodeAsExecutedTwice();
14554 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000014555 case kToBeExecutedOnceCodeAge: {
14556 DCHECK(parity == NO_MARKING_PARITY);
14557 return *builtins->MarkCodeAsToBeExecutedOnce();
14558 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014559 default:
14560 UNREACHABLE();
14561 break;
14562 }
14563 return NULL;
14564}
14565
14566
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000014567void Code::PrintDeoptLocation(FILE* out, Address pc) {
14568 Deoptimizer::DeoptInfo info = Deoptimizer::GetDeoptInfo(this, pc);
14569 class SourcePosition pos = info.position;
14570 if (info.deopt_reason != Deoptimizer::kNoReason || !pos.IsUnknown()) {
14571 if (FLAG_hydrogen_track_positions) {
14572 PrintF(out, " ;;; deoptimize at %d_%d: %s\n",
14573 pos.inlining_id(), pos.position(),
14574 Deoptimizer::GetDeoptReason(info.deopt_reason));
14575 } else {
14576 PrintF(out, " ;;; deoptimize at %d: %s\n", pos.raw(),
14577 Deoptimizer::GetDeoptReason(info.deopt_reason));
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014578 }
14579 }
14580}
14581
14582
14583bool Code::CanDeoptAt(Address pc) {
14584 DeoptimizationInputData* deopt_data =
14585 DeoptimizationInputData::cast(deoptimization_data());
14586 Address code_start_address = instruction_start();
14587 for (int i = 0; i < deopt_data->DeoptCount(); i++) {
14588 if (deopt_data->Pc(i)->value() == -1) continue;
14589 Address address = code_start_address + deopt_data->Pc(i)->value();
Ben Murdoch097c5b22016-05-18 11:27:45 +010014590 if (address == pc && deopt_data->AstId(i) != BailoutId::None()) {
14591 return true;
14592 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014593 }
14594 return false;
14595}
14596
14597
14598// Identify kind of code.
14599const char* Code::Kind2String(Kind kind) {
14600 switch (kind) {
14601#define CASE(name) case name: return #name;
14602 CODE_KIND_LIST(CASE)
14603#undef CASE
14604 case NUMBER_OF_KINDS: break;
14605 }
14606 UNREACHABLE();
14607 return NULL;
14608}
14609
14610
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000014611Handle<WeakCell> Code::WeakCellFor(Handle<Code> code) {
14612 DCHECK(code->kind() == OPTIMIZED_FUNCTION);
14613 WeakCell* raw_cell = code->CachedWeakCell();
14614 if (raw_cell != NULL) return Handle<WeakCell>(raw_cell);
14615 Handle<WeakCell> cell = code->GetIsolate()->factory()->NewWeakCell(code);
14616 DeoptimizationInputData::cast(code->deoptimization_data())
14617 ->SetWeakCellCache(*cell);
14618 return cell;
14619}
14620
14621
14622WeakCell* Code::CachedWeakCell() {
14623 DCHECK(kind() == OPTIMIZED_FUNCTION);
14624 Object* weak_cell_cache =
14625 DeoptimizationInputData::cast(deoptimization_data())->WeakCellCache();
14626 if (weak_cell_cache->IsWeakCell()) {
14627 DCHECK(this == WeakCell::cast(weak_cell_cache)->value());
14628 return WeakCell::cast(weak_cell_cache);
14629 }
14630 return NULL;
14631}
14632
14633
Steve Blocka7e24c12009-10-30 11:49:00 +000014634#ifdef ENABLE_DISASSEMBLER
Ben Murdochb0fe1622011-05-05 13:52:32 +010014635
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014636void DeoptimizationInputData::DeoptimizationInputDataPrint(
Emily Bernierd0a1eb72015-03-24 16:35:39 -040014637 std::ostream& os) { // NOLINT
Ben Murdochb0fe1622011-05-05 13:52:32 +010014638 disasm::NameConverter converter;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000014639 int const inlined_function_count = InlinedFunctionCount()->value();
14640 os << "Inlined functions (count = " << inlined_function_count << ")\n";
14641 for (int id = 0; id < inlined_function_count; ++id) {
14642 Object* info = LiteralArray()->get(id);
14643 os << " " << Brief(SharedFunctionInfo::cast(info)) << "\n";
14644 }
14645 os << "\n";
Ben Murdochb0fe1622011-05-05 13:52:32 +010014646 int deopt_count = DeoptCount();
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014647 os << "Deoptimization Input Data (deopt points = " << deopt_count << ")\n";
14648 if (0 != deopt_count) {
14649 os << " index ast id argc pc";
14650 if (FLAG_print_code_verbose) os << " commands";
14651 os << "\n";
14652 }
Ben Murdochb0fe1622011-05-05 13:52:32 +010014653 for (int i = 0; i < deopt_count; i++) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000014654 os << std::setw(6) << i << " " << std::setw(6) << AstId(i).ToInt() << " "
14655 << std::setw(6) << ArgumentsStackHeight(i)->value() << " "
14656 << std::setw(6) << Pc(i)->value();
Ben Murdoch69a99ed2011-11-30 16:03:39 +000014657
14658 if (!FLAG_print_code_verbose) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014659 os << "\n";
Ben Murdoch69a99ed2011-11-30 16:03:39 +000014660 continue;
14661 }
14662 // Print details of the frame translation.
Ben Murdochb0fe1622011-05-05 13:52:32 +010014663 int translation_index = TranslationIndex(i)->value();
14664 TranslationIterator iterator(TranslationByteArray(), translation_index);
14665 Translation::Opcode opcode =
14666 static_cast<Translation::Opcode>(iterator.Next());
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014667 DCHECK(Translation::BEGIN == opcode);
Ben Murdochb0fe1622011-05-05 13:52:32 +010014668 int frame_count = iterator.Next();
Ben Murdoch3ef787d2012-04-12 10:51:47 +010014669 int jsframe_count = iterator.Next();
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014670 os << " " << Translation::StringFor(opcode)
14671 << " {frame count=" << frame_count
14672 << ", js frame count=" << jsframe_count << "}\n";
Ben Murdochb0fe1622011-05-05 13:52:32 +010014673
Ben Murdoch69a99ed2011-11-30 16:03:39 +000014674 while (iterator.HasNext() &&
14675 Translation::BEGIN !=
14676 (opcode = static_cast<Translation::Opcode>(iterator.Next()))) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000014677 os << std::setw(31) << " " << Translation::StringFor(opcode) << " ";
Ben Murdoch69a99ed2011-11-30 16:03:39 +000014678
14679 switch (opcode) {
14680 case Translation::BEGIN:
14681 UNREACHABLE();
14682 break;
14683
Ben Murdoch3ef787d2012-04-12 10:51:47 +010014684 case Translation::JS_FRAME: {
Ben Murdoch69a99ed2011-11-30 16:03:39 +000014685 int ast_id = iterator.Next();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000014686 int shared_info_id = iterator.Next();
Ben Murdoch69a99ed2011-11-30 16:03:39 +000014687 unsigned height = iterator.Next();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000014688 Object* shared_info = LiteralArray()->get(shared_info_id);
14689 os << "{ast_id=" << ast_id << ", function="
14690 << Brief(SharedFunctionInfo::cast(shared_info)->DebugName())
14691 << ", height=" << height << "}";
14692 break;
14693 }
14694
14695 case Translation::INTERPRETED_FRAME: {
14696 int bytecode_offset = iterator.Next();
14697 int shared_info_id = iterator.Next();
14698 unsigned height = iterator.Next();
14699 Object* shared_info = LiteralArray()->get(shared_info_id);
14700 os << "{bytecode_offset=" << bytecode_offset << ", function="
14701 << Brief(SharedFunctionInfo::cast(shared_info)->DebugName())
14702 << ", height=" << height << "}";
14703 break;
14704 }
14705
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014706 case Translation::COMPILED_STUB_FRAME: {
14707 Code::Kind stub_kind = static_cast<Code::Kind>(iterator.Next());
14708 os << "{kind=" << stub_kind << "}";
Ben Murdoch69a99ed2011-11-30 16:03:39 +000014709 break;
14710 }
14711
Ben Murdoch3ef787d2012-04-12 10:51:47 +010014712 case Translation::ARGUMENTS_ADAPTOR_FRAME:
14713 case Translation::CONSTRUCT_STUB_FRAME: {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000014714 int shared_info_id = iterator.Next();
14715 Object* shared_info = LiteralArray()->get(shared_info_id);
Ben Murdoch3ef787d2012-04-12 10:51:47 +010014716 unsigned height = iterator.Next();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000014717 os << "{function="
14718 << Brief(SharedFunctionInfo::cast(shared_info)->DebugName())
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014719 << ", height=" << height << "}";
Ben Murdoch3ef787d2012-04-12 10:51:47 +010014720 break;
14721 }
14722
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014723 case Translation::GETTER_STUB_FRAME:
14724 case Translation::SETTER_STUB_FRAME: {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000014725 int shared_info_id = iterator.Next();
14726 Object* shared_info = LiteralArray()->get(shared_info_id);
14727 os << "{function=" << Brief(SharedFunctionInfo::cast(shared_info)
14728 ->DebugName()) << "}";
Ben Murdoch69a99ed2011-11-30 16:03:39 +000014729 break;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014730 }
Ben Murdoch69a99ed2011-11-30 16:03:39 +000014731
14732 case Translation::REGISTER: {
14733 int reg_code = iterator.Next();
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014734 os << "{input=" << converter.NameOfCPURegister(reg_code) << "}";
Ben Murdoch69a99ed2011-11-30 16:03:39 +000014735 break;
14736 }
14737
14738 case Translation::INT32_REGISTER: {
14739 int reg_code = iterator.Next();
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014740 os << "{input=" << converter.NameOfCPURegister(reg_code) << "}";
14741 break;
14742 }
14743
14744 case Translation::UINT32_REGISTER: {
14745 int reg_code = iterator.Next();
14746 os << "{input=" << converter.NameOfCPURegister(reg_code)
14747 << " (unsigned)}";
Ben Murdoch69a99ed2011-11-30 16:03:39 +000014748 break;
14749 }
14750
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000014751 case Translation::BOOL_REGISTER: {
14752 int reg_code = iterator.Next();
14753 os << "{input=" << converter.NameOfCPURegister(reg_code)
14754 << " (bool)}";
14755 break;
14756 }
14757
Ben Murdoch69a99ed2011-11-30 16:03:39 +000014758 case Translation::DOUBLE_REGISTER: {
14759 int reg_code = iterator.Next();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000014760 os << "{input=" << DoubleRegister::from_code(reg_code).ToString()
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014761 << "}";
Ben Murdoch69a99ed2011-11-30 16:03:39 +000014762 break;
14763 }
14764
14765 case Translation::STACK_SLOT: {
14766 int input_slot_index = iterator.Next();
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014767 os << "{input=" << input_slot_index << "}";
Ben Murdoch69a99ed2011-11-30 16:03:39 +000014768 break;
14769 }
14770
14771 case Translation::INT32_STACK_SLOT: {
14772 int input_slot_index = iterator.Next();
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014773 os << "{input=" << input_slot_index << "}";
14774 break;
14775 }
14776
14777 case Translation::UINT32_STACK_SLOT: {
14778 int input_slot_index = iterator.Next();
14779 os << "{input=" << input_slot_index << " (unsigned)}";
Ben Murdoch69a99ed2011-11-30 16:03:39 +000014780 break;
14781 }
14782
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000014783 case Translation::BOOL_STACK_SLOT: {
14784 int input_slot_index = iterator.Next();
14785 os << "{input=" << input_slot_index << " (bool)}";
14786 break;
14787 }
14788
Ben Murdoch69a99ed2011-11-30 16:03:39 +000014789 case Translation::DOUBLE_STACK_SLOT: {
14790 int input_slot_index = iterator.Next();
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014791 os << "{input=" << input_slot_index << "}";
Ben Murdoch69a99ed2011-11-30 16:03:39 +000014792 break;
14793 }
14794
14795 case Translation::LITERAL: {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000014796 int literal_index = iterator.Next();
14797 Object* literal_value = LiteralArray()->get(literal_index);
14798 os << "{literal_id=" << literal_index << " (" << Brief(literal_value)
14799 << ")}";
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014800 break;
14801 }
14802
14803 case Translation::DUPLICATED_OBJECT: {
14804 int object_index = iterator.Next();
14805 os << "{object_index=" << object_index << "}";
Ben Murdoch69a99ed2011-11-30 16:03:39 +000014806 break;
14807 }
14808
14809 case Translation::ARGUMENTS_OBJECT:
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014810 case Translation::CAPTURED_OBJECT: {
14811 int args_length = iterator.Next();
14812 os << "{length=" << args_length << "}";
Ben Murdoch69a99ed2011-11-30 16:03:39 +000014813 break;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014814 }
Ben Murdochb0fe1622011-05-05 13:52:32 +010014815 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014816 os << "\n";
Ben Murdochb0fe1622011-05-05 13:52:32 +010014817 }
Ben Murdochb0fe1622011-05-05 13:52:32 +010014818 }
14819}
14820
14821
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014822void DeoptimizationOutputData::DeoptimizationOutputDataPrint(
Emily Bernierd0a1eb72015-03-24 16:35:39 -040014823 std::ostream& os) { // NOLINT
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014824 os << "Deoptimization Output Data (deopt points = " << this->DeoptPoints()
14825 << ")\n";
Ben Murdochb0fe1622011-05-05 13:52:32 +010014826 if (this->DeoptPoints() == 0) return;
14827
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014828 os << "ast id pc state\n";
Ben Murdochb0fe1622011-05-05 13:52:32 +010014829 for (int i = 0; i < this->DeoptPoints(); i++) {
14830 int pc_and_state = this->PcAndState(i)->value();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000014831 os << std::setw(6) << this->AstId(i).ToInt() << " " << std::setw(8)
14832 << FullCodeGenerator::PcField::decode(pc_and_state) << " "
14833 << FullCodeGenerator::State2String(
14834 FullCodeGenerator::StateField::decode(pc_and_state)) << "\n";
14835 }
14836}
14837
14838
14839void HandlerTable::HandlerTableRangePrint(std::ostream& os) {
14840 os << " from to hdlr\n";
14841 for (int i = 0; i < length(); i += kRangeEntrySize) {
14842 int pc_start = Smi::cast(get(i + kRangeStartIndex))->value();
14843 int pc_end = Smi::cast(get(i + kRangeEndIndex))->value();
14844 int handler_field = Smi::cast(get(i + kRangeHandlerIndex))->value();
14845 int handler_offset = HandlerOffsetField::decode(handler_field);
14846 CatchPrediction prediction = HandlerPredictionField::decode(handler_field);
Ben Murdoch097c5b22016-05-18 11:27:45 +010014847 int data = Smi::cast(get(i + kRangeDataIndex))->value();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000014848 os << " (" << std::setw(4) << pc_start << "," << std::setw(4) << pc_end
14849 << ") -> " << std::setw(4) << handler_offset
Ben Murdoch097c5b22016-05-18 11:27:45 +010014850 << " (prediction=" << prediction << ", data=" << data << ")\n";
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000014851 }
14852}
14853
14854
14855void HandlerTable::HandlerTableReturnPrint(std::ostream& os) {
14856 os << " off hdlr (c)\n";
14857 for (int i = 0; i < length(); i += kReturnEntrySize) {
14858 int pc_offset = Smi::cast(get(i + kReturnOffsetIndex))->value();
14859 int handler_field = Smi::cast(get(i + kReturnHandlerIndex))->value();
14860 int handler_offset = HandlerOffsetField::decode(handler_field);
14861 CatchPrediction prediction = HandlerPredictionField::decode(handler_field);
14862 os << " " << std::setw(4) << pc_offset << " -> " << std::setw(4)
14863 << handler_offset << " (prediction=" << prediction << ")\n";
Ben Murdochb0fe1622011-05-05 13:52:32 +010014864 }
14865}
14866
Ben Murdochb0fe1622011-05-05 13:52:32 +010014867
Steve Blocka7e24c12009-10-30 11:49:00 +000014868const char* Code::ICState2String(InlineCacheState state) {
14869 switch (state) {
14870 case UNINITIALIZED: return "UNINITIALIZED";
14871 case PREMONOMORPHIC: return "PREMONOMORPHIC";
14872 case MONOMORPHIC: return "MONOMORPHIC";
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014873 case PROTOTYPE_FAILURE:
14874 return "PROTOTYPE_FAILURE";
14875 case POLYMORPHIC: return "POLYMORPHIC";
Steve Blocka7e24c12009-10-30 11:49:00 +000014876 case MEGAMORPHIC: return "MEGAMORPHIC";
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014877 case GENERIC: return "GENERIC";
14878 case DEBUG_STUB: return "DEBUG_STUB";
Steve Blocka7e24c12009-10-30 11:49:00 +000014879 }
14880 UNREACHABLE();
14881 return NULL;
14882}
14883
14884
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014885const char* Code::StubType2String(StubType type) {
Steve Blocka7e24c12009-10-30 11:49:00 +000014886 switch (type) {
14887 case NORMAL: return "NORMAL";
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014888 case FAST: return "FAST";
Steve Blocka7e24c12009-10-30 11:49:00 +000014889 }
Ben Murdoch3ef787d2012-04-12 10:51:47 +010014890 UNREACHABLE(); // keep the compiler happy
Steve Blocka7e24c12009-10-30 11:49:00 +000014891 return NULL;
14892}
14893
Ben Murdochb0fe1622011-05-05 13:52:32 +010014894
Emily Bernierd0a1eb72015-03-24 16:35:39 -040014895void Code::PrintExtraICState(std::ostream& os, // NOLINT
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014896 Kind kind, ExtraICState extra) {
14897 os << "extra_ic_state = ";
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000014898 if ((kind == STORE_IC || kind == KEYED_STORE_IC) &&
14899 is_strict(static_cast<LanguageMode>(extra))) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014900 os << "STRICT\n";
Steve Block1e0659c2011-05-24 12:43:12 +010014901 } else {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014902 os << extra << "\n";
Steve Block1e0659c2011-05-24 12:43:12 +010014903 }
14904}
14905
14906
Emily Bernierd0a1eb72015-03-24 16:35:39 -040014907void Code::Disassemble(const char* name, std::ostream& os) { // NOLINT
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014908 os << "kind = " << Kind2String(kind()) << "\n";
14909 if (IsCodeStubOrIC()) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000014910 const char* n = CodeStub::MajorName(CodeStub::GetMajorKey(this));
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014911 os << "major_key = " << (n == NULL ? "null" : n) << "\n";
14912 }
Steve Blocka7e24c12009-10-30 11:49:00 +000014913 if (is_inline_cache_stub()) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014914 os << "ic_state = " << ICState2String(ic_state()) << "\n";
14915 PrintExtraICState(os, kind(), extra_ic_state());
Steve Blocka7e24c12009-10-30 11:49:00 +000014916 if (ic_state() == MONOMORPHIC) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014917 os << "type = " << StubType2String(type()) << "\n";
Steve Blocka7e24c12009-10-30 11:49:00 +000014918 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014919 if (is_compare_ic_stub()) {
14920 DCHECK(CodeStub::GetMajorKey(this) == CodeStub::CompareIC);
14921 CompareICStub stub(stub_key(), GetIsolate());
14922 os << "compare_state = " << CompareICState::GetStateName(stub.left())
14923 << "*" << CompareICState::GetStateName(stub.right()) << " -> "
14924 << CompareICState::GetStateName(stub.state()) << "\n";
14925 os << "compare_operation = " << Token::Name(stub.op()) << "\n";
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000014926 }
Steve Blocka7e24c12009-10-30 11:49:00 +000014927 }
14928 if ((name != NULL) && (name[0] != '\0')) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014929 os << "name = " << name << "\n";
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000014930 } else if (kind() == BUILTIN) {
14931 name = GetIsolate()->builtins()->Lookup(instruction_start());
14932 if (name != NULL) {
14933 os << "name = " << name << "\n";
14934 }
Ben Murdochb0fe1622011-05-05 13:52:32 +010014935 }
14936 if (kind() == OPTIMIZED_FUNCTION) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014937 os << "stack_slots = " << stack_slots() << "\n";
Steve Blocka7e24c12009-10-30 11:49:00 +000014938 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000014939 os << "compiler = " << (is_turbofanned()
14940 ? "turbofan"
14941 : is_crankshafted() ? "crankshaft"
14942 : kind() == Code::FUNCTION
14943 ? "full-codegen"
14944 : "unknown") << "\n";
Steve Blocka7e24c12009-10-30 11:49:00 +000014945
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014946 os << "Instructions (size = " << instruction_size() << ")\n";
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014947 {
Emily Bernierd0a1eb72015-03-24 16:35:39 -040014948 Isolate* isolate = GetIsolate();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000014949 int size = instruction_size();
14950 int safepoint_offset =
14951 is_crankshafted() ? static_cast<int>(safepoint_table_offset()) : size;
14952 int back_edge_offset = (kind() == Code::FUNCTION)
14953 ? static_cast<int>(back_edge_table_offset())
14954 : size;
14955 int constant_pool_offset = FLAG_enable_embedded_constant_pool
14956 ? this->constant_pool_offset()
14957 : size;
14958
14959 // Stop before reaching any embedded tables
14960 int code_size = Min(safepoint_offset, back_edge_offset);
14961 code_size = Min(code_size, constant_pool_offset);
Emily Bernierd0a1eb72015-03-24 16:35:39 -040014962 byte* begin = instruction_start();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000014963 byte* end = begin + code_size;
Emily Bernierd0a1eb72015-03-24 16:35:39 -040014964 Disassembler::Decode(isolate, &os, begin, end, this);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000014965
14966 if (constant_pool_offset < size) {
14967 int constant_pool_size = size - constant_pool_offset;
14968 DCHECK((constant_pool_size & kPointerAlignmentMask) == 0);
14969 os << "\nConstant Pool (size = " << constant_pool_size << ")\n";
14970 Vector<char> buf = Vector<char>::New(50);
14971 intptr_t* ptr = reinterpret_cast<intptr_t*>(begin + constant_pool_offset);
14972 for (int i = 0; i < constant_pool_size; i += kPointerSize, ptr++) {
14973 SNPrintF(buf, "%4d %08" V8PRIxPTR, i, *ptr);
14974 os << static_cast<const void*>(ptr) << " " << buf.start() << "\n";
14975 }
14976 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014977 }
14978 os << "\n";
Ben Murdochb0fe1622011-05-05 13:52:32 +010014979
Ben Murdochb0fe1622011-05-05 13:52:32 +010014980 if (kind() == FUNCTION) {
14981 DeoptimizationOutputData* data =
14982 DeoptimizationOutputData::cast(this->deoptimization_data());
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014983 data->DeoptimizationOutputDataPrint(os);
Ben Murdochb0fe1622011-05-05 13:52:32 +010014984 } else if (kind() == OPTIMIZED_FUNCTION) {
14985 DeoptimizationInputData* data =
14986 DeoptimizationInputData::cast(this->deoptimization_data());
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014987 data->DeoptimizationInputDataPrint(os);
Ben Murdochb0fe1622011-05-05 13:52:32 +010014988 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014989 os << "\n";
Ben Murdochb0fe1622011-05-05 13:52:32 +010014990
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014991 if (is_crankshafted()) {
Ben Murdochb0fe1622011-05-05 13:52:32 +010014992 SafepointTable table(this);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014993 os << "Safepoints (size = " << table.size() << ")\n";
Ben Murdochb0fe1622011-05-05 13:52:32 +010014994 for (unsigned i = 0; i < table.length(); i++) {
14995 unsigned pc_offset = table.GetPcOffset(i);
Emily Bernierd0a1eb72015-03-24 16:35:39 -040014996 os << static_cast<const void*>(instruction_start() + pc_offset) << " ";
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000014997 os << std::setw(4) << pc_offset << " ";
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014998 table.PrintEntry(i, os);
14999 os << " (sp -> fp) ";
Ben Murdochb8e0da22011-05-16 14:20:40 +010015000 SafepointEntry entry = table.GetEntry(i);
15001 if (entry.deoptimization_index() != Safepoint::kNoDeoptimizationIndex) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000015002 os << std::setw(6) << entry.deoptimization_index();
Ben Murdochb0fe1622011-05-05 13:52:32 +010015003 } else {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015004 os << "<none>";
Ben Murdochb0fe1622011-05-05 13:52:32 +010015005 }
Ben Murdochb8e0da22011-05-16 14:20:40 +010015006 if (entry.argument_count() > 0) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015007 os << " argc: " << entry.argument_count();
Ben Murdochb8e0da22011-05-16 14:20:40 +010015008 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015009 os << "\n";
Ben Murdochb0fe1622011-05-05 13:52:32 +010015010 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015011 os << "\n";
Ben Murdochb0fe1622011-05-05 13:52:32 +010015012 } else if (kind() == FUNCTION) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015013 unsigned offset = back_edge_table_offset();
15014 // If there is no back edge table, the "table start" will be at or after
Ben Murdochb0fe1622011-05-05 13:52:32 +010015015 // (due to alignment) the end of the instruction stream.
15016 if (static_cast<int>(offset) < instruction_size()) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015017 DisallowHeapAllocation no_gc;
15018 BackEdgeTable back_edges(this, &no_gc);
15019
15020 os << "Back edges (size = " << back_edges.length() << ")\n";
15021 os << "ast_id pc_offset loop_depth\n";
15022
15023 for (uint32_t i = 0; i < back_edges.length(); i++) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000015024 os << std::setw(6) << back_edges.ast_id(i).ToInt() << " "
15025 << std::setw(9) << back_edges.pc_offset(i) << " " << std::setw(10)
15026 << back_edges.loop_depth(i) << "\n";
Ben Murdochb0fe1622011-05-05 13:52:32 +010015027 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015028
15029 os << "\n";
Ben Murdochb0fe1622011-05-05 13:52:32 +010015030 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015031#ifdef OBJECT_PRINT
15032 if (!type_feedback_info()->IsUndefined()) {
15033 OFStream os(stdout);
15034 TypeFeedbackInfo::cast(type_feedback_info())->TypeFeedbackInfoPrint(os);
15035 os << "\n";
15036 }
15037#endif
Ben Murdochb0fe1622011-05-05 13:52:32 +010015038 }
Steve Blocka7e24c12009-10-30 11:49:00 +000015039
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000015040 if (handler_table()->length() > 0) {
15041 os << "Handler Table (size = " << handler_table()->Size() << ")\n";
15042 if (kind() == FUNCTION) {
15043 HandlerTable::cast(handler_table())->HandlerTableRangePrint(os);
15044 } else if (kind() == OPTIMIZED_FUNCTION) {
15045 HandlerTable::cast(handler_table())->HandlerTableReturnPrint(os);
15046 }
15047 os << "\n";
15048 }
15049
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015050 os << "RelocInfo (size = " << relocation_size() << ")\n";
15051 for (RelocIterator it(this); !it.done(); it.next()) {
15052 it.rinfo()->Print(GetIsolate(), os);
15053 }
15054 os << "\n";
Steve Blocka7e24c12009-10-30 11:49:00 +000015055}
15056#endif // ENABLE_DISASSEMBLER
15057
Ben Murdoch097c5b22016-05-18 11:27:45 +010015058int BytecodeArray::SourcePosition(int offset) {
15059 int last_position = 0;
15060 for (interpreter::SourcePositionTableIterator iterator(this);
15061 !iterator.done() && iterator.bytecode_offset() <= offset;
15062 iterator.Advance()) {
15063 last_position = iterator.source_position();
15064 }
15065 return last_position;
15066}
15067
15068int BytecodeArray::SourceStatementPosition(int offset) {
15069 // First find the position as close as possible using all position
15070 // information.
15071 int position = SourcePosition(offset);
15072 // Now find the closest statement position before the position.
15073 int statement_position = 0;
15074 interpreter::SourcePositionTableIterator iterator(this);
15075 while (!iterator.done()) {
15076 if (iterator.is_statement()) {
15077 int p = iterator.source_position();
15078 if (statement_position < p && p <= position) {
15079 statement_position = p;
15080 }
15081 }
15082 iterator.Advance();
15083 }
15084 return statement_position;
15085}
Steve Blocka7e24c12009-10-30 11:49:00 +000015086
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000015087void BytecodeArray::Disassemble(std::ostream& os) {
15088 os << "Parameter count " << parameter_count() << "\n";
15089 os << "Frame size " << frame_size() << "\n";
15090 Vector<char> buf = Vector<char>::New(50);
Steve Block8defd9f2010-07-08 12:39:36 +010015091
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000015092 const uint8_t* first_bytecode_address = GetFirstBytecodeAddress();
15093 int bytecode_size = 0;
Ben Murdoch097c5b22016-05-18 11:27:45 +010015094
15095 interpreter::SourcePositionTableIterator source_positions(this);
15096
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000015097 for (int i = 0; i < this->length(); i += bytecode_size) {
15098 const uint8_t* bytecode_start = &first_bytecode_address[i];
15099 interpreter::Bytecode bytecode =
15100 interpreter::Bytecodes::FromByte(bytecode_start[0]);
15101 bytecode_size = interpreter::Bytecodes::Size(bytecode);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000015102
Ben Murdoch097c5b22016-05-18 11:27:45 +010015103 if (!source_positions.done() && i == source_positions.bytecode_offset()) {
15104 os << std::setw(5) << source_positions.source_position();
15105 os << (source_positions.is_statement() ? " S> " : " E> ");
15106 source_positions.Advance();
15107 } else {
15108 os << " ";
15109 }
15110
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000015111 SNPrintF(buf, "%p", bytecode_start);
15112 os << buf.start() << " : ";
15113 interpreter::Bytecodes::Decode(os, bytecode_start, parameter_count());
15114
15115 if (interpreter::Bytecodes::IsJumpConstantWide(bytecode)) {
15116 DCHECK_EQ(bytecode_size, 3);
15117 int index = static_cast<int>(ReadUnalignedUInt16(bytecode_start + 1));
15118 int offset = Smi::cast(constant_pool()->get(index))->value();
15119 SNPrintF(buf, " (%p)", bytecode_start + offset);
15120 os << buf.start();
15121 } else if (interpreter::Bytecodes::IsJumpConstant(bytecode)) {
15122 DCHECK_EQ(bytecode_size, 2);
15123 int index = static_cast<int>(bytecode_start[1]);
15124 int offset = Smi::cast(constant_pool()->get(index))->value();
15125 SNPrintF(buf, " (%p)", bytecode_start + offset);
15126 os << buf.start();
15127 } else if (interpreter::Bytecodes::IsJump(bytecode)) {
15128 DCHECK_EQ(bytecode_size, 2);
15129 int offset = static_cast<int8_t>(bytecode_start[1]);
15130 SNPrintF(buf, " (%p)", bytecode_start + offset);
15131 os << buf.start();
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015132 }
Ben Murdoch097c5b22016-05-18 11:27:45 +010015133
15134 os << std::endl;
Ben Murdoch3ef787d2012-04-12 10:51:47 +010015135 }
15136
Ben Murdoch097c5b22016-05-18 11:27:45 +010015137 if (constant_pool()->length() > 0) {
15138 os << "Constant pool (size = " << constant_pool()->length() << ")\n";
15139 constant_pool()->Print();
15140 }
15141
15142#ifdef ENABLE_DISASSEMBLER
15143 if (handler_table()->length() > 0) {
15144 os << "Handler Table (size = " << handler_table()->Size() << ")\n";
15145 HandlerTable::cast(handler_table())->HandlerTableRangePrint(os);
15146 }
15147#endif
Steve Blocka7e24c12009-10-30 11:49:00 +000015148}
15149
Ben Murdoch097c5b22016-05-18 11:27:45 +010015150void BytecodeArray::CopyBytecodesTo(BytecodeArray* to) {
15151 BytecodeArray* from = this;
15152 DCHECK_EQ(from->length(), to->length());
15153 CopyBytes(to->GetFirstBytecodeAddress(), from->GetFirstBytecodeAddress(),
15154 from->length());
15155}
Steve Blocka7e24c12009-10-30 11:49:00 +000015156
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015157// static
15158void JSArray::Initialize(Handle<JSArray> array, int capacity, int length) {
15159 DCHECK(capacity >= 0);
15160 array->GetIsolate()->factory()->NewJSArrayStorage(
15161 array, length, capacity, INITIALIZE_ARRAY_ELEMENTS_WITH_HOLE);
15162}
15163
15164
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000015165// Returns false if the passed-in index is marked non-configurable, which will
15166// cause the truncation operation to halt, and thus no further old values need
15167// be collected.
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015168static bool GetOldValue(Isolate* isolate,
15169 Handle<JSObject> object,
15170 uint32_t index,
15171 List<Handle<Object> >* old_values,
15172 List<uint32_t>* indices) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000015173 LookupIterator it(isolate, object, index, LookupIterator::HIDDEN);
15174 CHECK(JSReceiver::GetPropertyAttributes(&it).IsJust());
15175 DCHECK(it.IsFound());
15176 if (!it.IsConfigurable()) return false;
15177 Handle<Object> value =
15178 it.state() == LookupIterator::ACCESSOR
15179 ? Handle<Object>::cast(isolate->factory()->the_hole_value())
15180 : JSReceiver::GetDataProperty(&it);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015181 old_values->Add(value);
15182 indices->Add(index);
15183 return true;
15184}
15185
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015186
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000015187void JSArray::SetLength(Handle<JSArray> array, uint32_t new_length) {
Steve Block3ce2e202009-11-05 08:53:23 +000015188 // We should never end in here with a pixel or external array.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000015189 DCHECK(array->AllowsSetLength());
15190 if (array->SetLengthWouldNormalize(new_length)) {
15191 JSObject::NormalizeElements(array);
15192 }
15193 array->GetElementsAccessor()->SetLength(array, new_length);
15194}
15195
15196
15197MaybeHandle<Object> JSArray::ObservableSetLength(Handle<JSArray> array,
15198 uint32_t new_length) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015199 if (!array->map()->is_observed()) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000015200 SetLength(array, new_length);
15201 return array;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015202 }
15203
15204 Isolate* isolate = array->GetIsolate();
15205 List<uint32_t> indices;
15206 List<Handle<Object> > old_values;
15207 Handle<Object> old_length_handle(array->length(), isolate);
15208 uint32_t old_length = 0;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000015209 CHECK(old_length_handle->ToArrayLength(&old_length));
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015210
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000015211 int num_elements = array->NumberOfOwnElements(ALL_PROPERTIES);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015212 if (num_elements > 0) {
15213 if (old_length == static_cast<uint32_t>(num_elements)) {
15214 // Simple case for arrays without holes.
15215 for (uint32_t i = old_length - 1; i + 1 > new_length; --i) {
15216 if (!GetOldValue(isolate, array, i, &old_values, &indices)) break;
15217 }
15218 } else {
15219 // For sparse arrays, only iterate over existing elements.
15220 // TODO(rafaelw): For fast, sparse arrays, we can avoid iterating over
15221 // the to-be-removed indices twice.
15222 Handle<FixedArray> keys = isolate->factory()->NewFixedArray(num_elements);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000015223 array->GetOwnElementKeys(*keys, ALL_PROPERTIES);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015224 while (num_elements-- > 0) {
15225 uint32_t index = NumberToUint32(keys->get(num_elements));
15226 if (index < new_length) break;
15227 if (!GetOldValue(isolate, array, index, &old_values, &indices)) break;
15228 }
15229 }
15230 }
15231
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000015232 SetLength(array, new_length);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015233
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000015234 CHECK(array->length()->ToArrayLength(&new_length));
15235 if (old_length == new_length) return array;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015236
Emily Bernierd0a1eb72015-03-24 16:35:39 -040015237 RETURN_ON_EXCEPTION(isolate, BeginPerformSplice(array), Object);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015238
15239 for (int i = 0; i < indices.length(); ++i) {
15240 // For deletions where the property was an accessor, old_values[i]
15241 // will be the hole, which instructs EnqueueChangeRecord to elide
15242 // the "oldValue" property.
Emily Bernierd0a1eb72015-03-24 16:35:39 -040015243 RETURN_ON_EXCEPTION(
15244 isolate,
15245 JSObject::EnqueueChangeRecord(
15246 array, "delete", isolate->factory()->Uint32ToString(indices[i]),
15247 old_values[i]),
15248 Object);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015249 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000015250
Emily Bernierd0a1eb72015-03-24 16:35:39 -040015251 RETURN_ON_EXCEPTION(isolate,
15252 JSObject::EnqueueChangeRecord(
15253 array, "update", isolate->factory()->length_string(),
15254 old_length_handle),
15255 Object);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015256
Emily Bernierd0a1eb72015-03-24 16:35:39 -040015257 RETURN_ON_EXCEPTION(isolate, EndPerformSplice(array), Object);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015258
15259 uint32_t index = Min(old_length, new_length);
15260 uint32_t add_count = new_length > old_length ? new_length - old_length : 0;
15261 uint32_t delete_count = new_length < old_length ? old_length - new_length : 0;
15262 Handle<JSArray> deleted = isolate->factory()->NewJSArray(0);
15263 if (delete_count > 0) {
15264 for (int i = indices.length() - 1; i >= 0; i--) {
15265 // Skip deletions where the property was an accessor, leaving holes
15266 // in the array of old values.
15267 if (old_values[i]->IsTheHole()) continue;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000015268 JSObject::AddDataElement(deleted, indices[i] - index, old_values[i], NONE)
15269 .Assert();
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015270 }
15271
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000015272 JSArray::SetLength(deleted, delete_count);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015273 }
15274
Emily Bernierd0a1eb72015-03-24 16:35:39 -040015275 RETURN_ON_EXCEPTION(
15276 isolate, EnqueueSpliceRecord(array, index, deleted, add_count), Object);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015277
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000015278 return array;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015279}
15280
15281
15282// static
15283void Map::AddDependentCode(Handle<Map> map,
15284 DependentCode::DependencyGroup group,
15285 Handle<Code> code) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000015286 Handle<WeakCell> cell = Code::WeakCellFor(code);
15287 Handle<DependentCode> codes = DependentCode::InsertWeakCode(
15288 Handle<DependentCode>(map->dependent_code()), group, cell);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015289 if (*codes != map->dependent_code()) map->set_dependent_code(*codes);
15290}
15291
15292
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000015293Handle<DependentCode> DependentCode::InsertCompilationDependencies(
15294 Handle<DependentCode> entries, DependencyGroup group,
15295 Handle<Foreign> info) {
15296 return Insert(entries, group, info);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015297}
15298
15299
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000015300Handle<DependentCode> DependentCode::InsertWeakCode(
15301 Handle<DependentCode> entries, DependencyGroup group,
15302 Handle<WeakCell> code_cell) {
15303 return Insert(entries, group, code_cell);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015304}
15305
15306
15307Handle<DependentCode> DependentCode::Insert(Handle<DependentCode> entries,
15308 DependencyGroup group,
15309 Handle<Object> object) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000015310 if (entries->length() == 0 || entries->group() > group) {
15311 // There is no such group.
15312 return DependentCode::New(group, object, entries);
15313 }
15314 if (entries->group() < group) {
15315 // The group comes later in the list.
15316 Handle<DependentCode> old_next(entries->next_link());
15317 Handle<DependentCode> new_next = Insert(old_next, group, object);
15318 if (!old_next.is_identical_to(new_next)) {
15319 entries->set_next_link(*new_next);
15320 }
15321 return entries;
15322 }
15323 DCHECK_EQ(group, entries->group());
15324 int count = entries->count();
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015325 // Check for existing entry to avoid duplicates.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000015326 for (int i = 0; i < count; i++) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015327 if (entries->object_at(i) == *object) return entries;
15328 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000015329 if (entries->length() < kCodesStartIndex + count + 1) {
15330 entries = EnsureSpace(entries);
15331 // Count could have changed, reload it.
15332 count = entries->count();
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015333 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000015334 entries->set_object_at(count, *object);
15335 entries->set_count(count + 1);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015336 return entries;
15337}
15338
15339
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000015340Handle<DependentCode> DependentCode::New(DependencyGroup group,
15341 Handle<Object> object,
15342 Handle<DependentCode> next) {
15343 Isolate* isolate = next->GetIsolate();
15344 Handle<DependentCode> result = Handle<DependentCode>::cast(
15345 isolate->factory()->NewFixedArray(kCodesStartIndex + 1, TENURED));
15346 result->set_next_link(*next);
15347 result->set_flags(GroupField::encode(group) | CountField::encode(1));
15348 result->set_object_at(0, *object);
15349 return result;
15350}
15351
15352
15353Handle<DependentCode> DependentCode::EnsureSpace(
15354 Handle<DependentCode> entries) {
15355 if (entries->Compact()) return entries;
15356 Isolate* isolate = entries->GetIsolate();
15357 int capacity = kCodesStartIndex + DependentCode::Grow(entries->count());
15358 int grow_by = capacity - entries->length();
15359 return Handle<DependentCode>::cast(
15360 isolate->factory()->CopyFixedArrayAndGrow(entries, grow_by, TENURED));
15361}
15362
15363
15364bool DependentCode::Compact() {
15365 int old_count = count();
15366 int new_count = 0;
15367 for (int i = 0; i < old_count; i++) {
15368 Object* obj = object_at(i);
15369 if (!obj->IsWeakCell() || !WeakCell::cast(obj)->cleared()) {
15370 if (i != new_count) {
15371 copy(i, new_count);
15372 }
15373 new_count++;
15374 }
15375 }
15376 set_count(new_count);
15377 for (int i = new_count; i < old_count; i++) {
15378 clear_at(i);
15379 }
15380 return new_count < old_count;
15381}
15382
15383
15384void DependentCode::UpdateToFinishedCode(DependencyGroup group, Foreign* info,
15385 WeakCell* code_cell) {
15386 if (this->length() == 0 || this->group() > group) {
15387 // There is no such group.
15388 return;
15389 }
15390 if (this->group() < group) {
15391 // The group comes later in the list.
15392 next_link()->UpdateToFinishedCode(group, info, code_cell);
15393 return;
15394 }
15395 DCHECK_EQ(group, this->group());
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015396 DisallowHeapAllocation no_gc;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000015397 int count = this->count();
15398 for (int i = 0; i < count; i++) {
15399 if (object_at(i) == info) {
15400 set_object_at(i, code_cell);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015401 break;
15402 }
15403 }
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000015404#ifdef DEBUG
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000015405 for (int i = 0; i < count; i++) {
15406 DCHECK(object_at(i) != info);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015407 }
15408#endif
15409}
15410
15411
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000015412void DependentCode::RemoveCompilationDependencies(
15413 DependentCode::DependencyGroup group, Foreign* info) {
15414 if (this->length() == 0 || this->group() > group) {
15415 // There is no such group.
15416 return;
15417 }
15418 if (this->group() < group) {
15419 // The group comes later in the list.
15420 next_link()->RemoveCompilationDependencies(group, info);
15421 return;
15422 }
15423 DCHECK_EQ(group, this->group());
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015424 DisallowHeapAllocation no_allocation;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000015425 int old_count = count();
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015426 // Find compilation info wrapper.
15427 int info_pos = -1;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000015428 for (int i = 0; i < old_count; i++) {
15429 if (object_at(i) == info) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015430 info_pos = i;
15431 break;
15432 }
15433 }
15434 if (info_pos == -1) return; // Not found.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000015435 // Use the last code to fill the gap.
15436 if (info_pos < old_count - 1) {
15437 copy(old_count - 1, info_pos);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015438 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000015439 clear_at(old_count - 1);
15440 set_count(old_count - 1);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015441
15442#ifdef DEBUG
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000015443 for (int i = 0; i < old_count - 1; i++) {
15444 DCHECK(object_at(i) != info);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015445 }
15446#endif
15447}
15448
15449
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000015450bool DependentCode::Contains(DependencyGroup group, WeakCell* code_cell) {
15451 if (this->length() == 0 || this->group() > group) {
15452 // There is no such group.
15453 return false;
15454 }
15455 if (this->group() < group) {
15456 // The group comes later in the list.
15457 return next_link()->Contains(group, code_cell);
15458 }
15459 DCHECK_EQ(group, this->group());
15460 int count = this->count();
15461 for (int i = 0; i < count; i++) {
15462 if (object_at(i) == code_cell) return true;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015463 }
15464 return false;
15465}
15466
15467
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000015468bool DependentCode::IsEmpty(DependencyGroup group) {
15469 if (this->length() == 0 || this->group() > group) {
15470 // There is no such group.
15471 return true;
15472 }
15473 if (this->group() < group) {
15474 // The group comes later in the list.
15475 return next_link()->IsEmpty(group);
15476 }
15477 DCHECK_EQ(group, this->group());
15478 return count() == 0;
15479}
15480
15481
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015482bool DependentCode::MarkCodeForDeoptimization(
15483 Isolate* isolate,
15484 DependentCode::DependencyGroup group) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000015485 if (this->length() == 0 || this->group() > group) {
15486 // There is no such group.
15487 return false;
15488 }
15489 if (this->group() < group) {
15490 // The group comes later in the list.
15491 return next_link()->MarkCodeForDeoptimization(isolate, group);
15492 }
15493 DCHECK_EQ(group, this->group());
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015494 DisallowHeapAllocation no_allocation_scope;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015495 // Mark all the code that needs to be deoptimized.
15496 bool marked = false;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000015497 bool invalidate_embedded_objects = group == kWeakCodeGroup;
15498 int count = this->count();
15499 for (int i = 0; i < count; i++) {
15500 Object* obj = object_at(i);
15501 if (obj->IsWeakCell()) {
15502 WeakCell* cell = WeakCell::cast(obj);
15503 if (cell->cleared()) continue;
15504 Code* code = Code::cast(cell->value());
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015505 if (!code->marked_for_deoptimization()) {
15506 SetMarkedForDeoptimization(code, group);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000015507 if (invalidate_embedded_objects) {
15508 code->InvalidateEmbeddedObjects();
15509 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015510 marked = true;
15511 }
15512 } else {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000015513 DCHECK(obj->IsForeign());
15514 CompilationDependencies* info =
15515 reinterpret_cast<CompilationDependencies*>(
15516 Foreign::cast(obj)->foreign_address());
15517 info->Abort();
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015518 }
15519 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000015520 for (int i = 0; i < count; i++) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015521 clear_at(i);
15522 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000015523 set_count(0);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015524 return marked;
15525}
15526
15527
15528void DependentCode::DeoptimizeDependentCodeGroup(
15529 Isolate* isolate,
15530 DependentCode::DependencyGroup group) {
15531 DCHECK(AllowCodeDependencyChange::IsAllowed());
15532 DisallowHeapAllocation no_allocation_scope;
15533 bool marked = MarkCodeForDeoptimization(isolate, group);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015534 if (marked) Deoptimizer::DeoptimizeMarkedCode(isolate);
15535}
15536
15537
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015538void DependentCode::SetMarkedForDeoptimization(Code* code,
15539 DependencyGroup group) {
15540 code->set_marked_for_deoptimization(true);
15541 if (FLAG_trace_deopt &&
15542 (code->deoptimization_data() != code->GetHeap()->empty_fixed_array())) {
15543 DeoptimizationInputData* deopt_data =
15544 DeoptimizationInputData::cast(code->deoptimization_data());
15545 CodeTracer::Scope scope(code->GetHeap()->isolate()->GetCodeTracer());
15546 PrintF(scope.file(), "[marking dependent code 0x%08" V8PRIxPTR
15547 " (opt #%d) for deoptimization, reason: %s]\n",
15548 reinterpret_cast<intptr_t>(code),
15549 deopt_data->OptimizationId()->value(), DependencyGroupName(group));
15550 }
15551}
15552
15553
15554const char* DependentCode::DependencyGroupName(DependencyGroup group) {
15555 switch (group) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015556 case kWeakCodeGroup:
15557 return "weak-code";
15558 case kTransitionGroup:
15559 return "transition";
15560 case kPrototypeCheckGroup:
15561 return "prototype-check";
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015562 case kPropertyCellChangedGroup:
15563 return "property-cell-changed";
15564 case kFieldTypeGroup:
15565 return "field-type";
15566 case kInitialMapChangedGroup:
15567 return "initial-map-changed";
15568 case kAllocationSiteTenuringChangedGroup:
15569 return "allocation-site-tenuring-changed";
15570 case kAllocationSiteTransitionChangedGroup:
15571 return "allocation-site-transition-changed";
15572 }
15573 UNREACHABLE();
15574 return "?";
15575}
15576
15577
15578Handle<Map> Map::TransitionToPrototype(Handle<Map> map,
Emily Bernierd0a1eb72015-03-24 16:35:39 -040015579 Handle<Object> prototype,
15580 PrototypeOptimizationMode mode) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000015581 Handle<Map> new_map = TransitionArray::GetPrototypeTransition(map, prototype);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015582 if (new_map.is_null()) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -040015583 new_map = Copy(map, "TransitionToPrototype");
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000015584 TransitionArray::PutPrototypeTransition(map, prototype, new_map);
15585 Map::SetPrototype(new_map, prototype, mode);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015586 }
15587 return new_map;
15588}
15589
15590
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000015591Maybe<bool> JSReceiver::SetPrototype(Handle<JSReceiver> object,
15592 Handle<Object> value, bool from_javascript,
15593 ShouldThrow should_throw) {
15594 if (object->IsJSProxy()) {
15595 return JSProxy::SetPrototype(Handle<JSProxy>::cast(object), value,
15596 from_javascript, should_throw);
15597 }
15598 return JSObject::SetPrototype(Handle<JSObject>::cast(object), value,
15599 from_javascript, should_throw);
15600}
15601
15602
15603// ES6: 9.5.2 [[SetPrototypeOf]] (V)
15604// static
15605Maybe<bool> JSProxy::SetPrototype(Handle<JSProxy> proxy, Handle<Object> value,
15606 bool from_javascript,
15607 ShouldThrow should_throw) {
15608 Isolate* isolate = proxy->GetIsolate();
15609 STACK_CHECK(Nothing<bool>());
15610 Handle<Name> trap_name = isolate->factory()->setPrototypeOf_string();
15611 // 1. Assert: Either Type(V) is Object or Type(V) is Null.
15612 DCHECK(value->IsJSReceiver() || value->IsNull());
15613 // 2. Let handler be the value of the [[ProxyHandler]] internal slot of O.
15614 Handle<Object> handler(proxy->handler(), isolate);
15615 // 3. If handler is null, throw a TypeError exception.
15616 // 4. Assert: Type(handler) is Object.
15617 if (proxy->IsRevoked()) {
15618 isolate->Throw(*isolate->factory()->NewTypeError(
15619 MessageTemplate::kProxyRevoked, trap_name));
15620 return Nothing<bool>();
15621 }
15622 // 5. Let target be the value of the [[ProxyTarget]] internal slot.
15623 Handle<JSReceiver> target(proxy->target(), isolate);
15624 // 6. Let trap be ? GetMethod(handler, "getPrototypeOf").
15625 Handle<Object> trap;
15626 ASSIGN_RETURN_ON_EXCEPTION_VALUE(
15627 isolate, trap,
15628 Object::GetMethod(Handle<JSReceiver>::cast(handler), trap_name),
15629 Nothing<bool>());
15630 // 7. If trap is undefined, then return target.[[SetPrototypeOf]]().
15631 if (trap->IsUndefined()) {
15632 return JSReceiver::SetPrototype(target, value, from_javascript,
15633 should_throw);
15634 }
15635 // 8. Let booleanTrapResult be ToBoolean(? Call(trap, handler, «target, V»)).
15636 Handle<Object> argv[] = {target, value};
15637 Handle<Object> trap_result;
15638 ASSIGN_RETURN_ON_EXCEPTION_VALUE(
15639 isolate, trap_result,
15640 Execution::Call(isolate, trap, handler, arraysize(argv), argv),
15641 Nothing<bool>());
15642 bool bool_trap_result = trap_result->BooleanValue();
Ben Murdoch097c5b22016-05-18 11:27:45 +010015643 // 9. If booleanTrapResult is false, return false.
15644 if (!bool_trap_result) {
15645 RETURN_FAILURE(
15646 isolate, should_throw,
15647 NewTypeError(MessageTemplate::kProxyTrapReturnedFalsish, trap_name));
15648 }
15649 // 10. Let extensibleTarget be ? IsExtensible(target).
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000015650 Maybe<bool> is_extensible = JSReceiver::IsExtensible(target);
15651 if (is_extensible.IsNothing()) return Nothing<bool>();
Ben Murdoch097c5b22016-05-18 11:27:45 +010015652 // 11. If extensibleTarget is true, return true.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000015653 if (is_extensible.FromJust()) {
15654 if (bool_trap_result) return Just(true);
15655 RETURN_FAILURE(
15656 isolate, should_throw,
15657 NewTypeError(MessageTemplate::kProxyTrapReturnedFalsish, trap_name));
15658 }
Ben Murdoch097c5b22016-05-18 11:27:45 +010015659 // 12. Let targetProto be ? target.[[GetPrototypeOf]]().
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000015660 Handle<Object> target_proto;
15661 ASSIGN_RETURN_ON_EXCEPTION_VALUE(isolate, target_proto,
Ben Murdoch097c5b22016-05-18 11:27:45 +010015662 JSReceiver::GetPrototype(isolate, target),
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000015663 Nothing<bool>());
Ben Murdoch097c5b22016-05-18 11:27:45 +010015664 // 13. If SameValue(V, targetProto) is false, throw a TypeError exception.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000015665 if (bool_trap_result && !value->SameValue(*target_proto)) {
15666 isolate->Throw(*isolate->factory()->NewTypeError(
15667 MessageTemplate::kProxySetPrototypeOfNonExtensible));
15668 return Nothing<bool>();
15669 }
Ben Murdoch097c5b22016-05-18 11:27:45 +010015670 // 14. Return true.
15671 return Just(true);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000015672}
15673
15674
15675Maybe<bool> JSObject::SetPrototype(Handle<JSObject> object,
15676 Handle<Object> value, bool from_javascript,
15677 ShouldThrow should_throw) {
15678 Isolate* isolate = object->GetIsolate();
15679
Ben Murdoch097c5b22016-05-18 11:27:45 +010015680 // Setting the prototype of an Array instance invalidates the species
15681 // protector
15682 // because it could change the constructor property of the instance, which
15683 // could change the @@species constructor.
15684 if (object->IsJSArray() && isolate->IsArraySpeciesLookupChainIntact()) {
15685 isolate->CountUsage(
15686 v8::Isolate::UseCounterFeature::kArrayInstanceProtoModified);
15687 isolate->InvalidateArraySpeciesProtector();
15688 }
15689
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000015690 const bool observed = from_javascript && object->map()->is_observed();
15691 Handle<Object> old_value;
15692 if (observed) {
15693 ASSIGN_RETURN_ON_EXCEPTION_VALUE(isolate, old_value,
Ben Murdoch097c5b22016-05-18 11:27:45 +010015694 JSReceiver::GetPrototype(isolate, object),
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000015695 Nothing<bool>());
15696 }
15697
15698 Maybe<bool> result =
15699 SetPrototypeUnobserved(object, value, from_javascript, should_throw);
15700 MAYBE_RETURN(result, Nothing<bool>());
15701
15702 if (result.FromJust() && observed) {
15703 Handle<Object> new_value;
15704 ASSIGN_RETURN_ON_EXCEPTION_VALUE(isolate, new_value,
Ben Murdoch097c5b22016-05-18 11:27:45 +010015705 JSReceiver::GetPrototype(isolate, object),
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000015706 Nothing<bool>());
15707 if (!new_value->SameValue(*old_value)) {
15708 RETURN_ON_EXCEPTION_VALUE(
15709 isolate, JSObject::EnqueueChangeRecord(
15710 object, "setPrototype",
15711 isolate->factory()->proto_string(), old_value),
15712 Nothing<bool>());
15713 }
15714 }
15715
15716 return result;
15717}
15718
15719
15720Maybe<bool> JSObject::SetPrototypeUnobserved(Handle<JSObject> object,
15721 Handle<Object> value,
15722 bool from_javascript,
15723 ShouldThrow should_throw) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015724#ifdef DEBUG
15725 int size = object->Size();
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000015726#endif
15727
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015728 Isolate* isolate = object->GetIsolate();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000015729
15730 if (from_javascript) {
15731 if (object->IsAccessCheckNeeded() &&
15732 !isolate->MayAccess(handle(isolate->context()), object)) {
15733 isolate->ReportFailedAccessCheck(object);
15734 RETURN_VALUE_IF_SCHEDULED_EXCEPTION(isolate, Nothing<bool>());
15735 RETURN_FAILURE(isolate, should_throw,
15736 NewTypeError(MessageTemplate::kNoAccess));
15737 }
15738 } else {
15739 DCHECK(!object->IsAccessCheckNeeded());
15740 }
15741
15742 // Strong objects may not have their prototype set via __proto__ or
15743 // setPrototypeOf.
15744 if (from_javascript && object->map()->is_strong()) {
15745 RETURN_FAILURE(isolate, should_throw,
15746 NewTypeError(MessageTemplate::kStrongSetProto, object));
15747 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015748 Heap* heap = isolate->heap();
Andrei Popescu402d9372010-02-26 13:31:12 +000015749 // Silently ignore the change if value is not a JSObject or null.
15750 // SpiderMonkey behaves this way.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000015751 if (!value->IsJSReceiver() && !value->IsNull()) return Just(true);
15752
15753 bool dictionary_elements_in_chain =
15754 object->map()->DictionaryElementsInPrototypeChainOnly();
15755
15756 bool all_extensible = object->map()->is_extensible();
15757 Handle<JSObject> real_receiver = object;
15758 if (from_javascript) {
15759 // Find the first object in the chain whose prototype object is not
15760 // hidden.
Ben Murdoch097c5b22016-05-18 11:27:45 +010015761 PrototypeIterator iter(isolate, real_receiver,
15762 PrototypeIterator::START_AT_PROTOTYPE,
15763 PrototypeIterator::END_AT_NON_HIDDEN);
15764 while (!iter.IsAtEnd()) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000015765 // Casting to JSObject is fine because hidden prototypes are never
15766 // JSProxies.
15767 real_receiver = PrototypeIterator::GetCurrent<JSObject>(iter);
15768 iter.Advance();
15769 all_extensible = all_extensible && real_receiver->map()->is_extensible();
15770 }
15771 }
15772 Handle<Map> map(real_receiver->map());
15773
15774 // Nothing to do if prototype is already set.
15775 if (map->prototype() == *value) return Just(true);
Andrei Popescu402d9372010-02-26 13:31:12 +000015776
Ben Murdoch8b112d22011-06-08 16:22:53 +010015777 // From 8.6.2 Object Internal Methods
15778 // ...
15779 // In addition, if [[Extensible]] is false the value of the [[Class]] and
15780 // [[Prototype]] internal properties of the object may not be modified.
15781 // ...
15782 // Implementation specific extensions that modify [[Class]], [[Prototype]]
15783 // or [[Extensible]] must not violate the invariants defined in the preceding
15784 // paragraph.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000015785 if (!all_extensible) {
15786 RETURN_FAILURE(isolate, should_throw,
15787 NewTypeError(MessageTemplate::kNonExtensibleProto, object));
Ben Murdoch8b112d22011-06-08 16:22:53 +010015788 }
15789
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000015790 // Before we can set the prototype we need to be sure prototype cycles are
15791 // prevented. It is sufficient to validate that the receiver is not in the
15792 // new prototype chain.
Ben Murdoch097c5b22016-05-18 11:27:45 +010015793 if (value->IsJSReceiver()) {
15794 for (PrototypeIterator iter(isolate, JSReceiver::cast(*value),
15795 PrototypeIterator::START_AT_RECEIVER);
15796 !iter.IsAtEnd(); iter.Advance()) {
15797 if (iter.GetCurrent<JSReceiver>() == *object) {
15798 // Cycle detected.
15799 RETURN_FAILURE(isolate, should_throw,
15800 NewTypeError(MessageTemplate::kCyclicProto));
15801 }
Andrei Popescu402d9372010-02-26 13:31:12 +000015802 }
15803 }
15804
15805 // Set the new prototype of the object.
Steve Block053d10c2011-06-13 19:13:29 +010015806
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000015807 isolate->UpdateArrayProtectorOnSetPrototype(real_receiver);
Steve Block053d10c2011-06-13 19:13:29 +010015808
Emily Bernierd0a1eb72015-03-24 16:35:39 -040015809 PrototypeOptimizationMode mode =
15810 from_javascript ? REGULAR_PROTOTYPE : FAST_PROTOTYPE;
15811 Handle<Map> new_map = Map::TransitionToPrototype(map, value, mode);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015812 DCHECK(new_map->prototype() == *value);
15813 JSObject::MigrateToMap(real_receiver, new_map);
15814
Emily Bernierd0a1eb72015-03-24 16:35:39 -040015815 if (from_javascript && !dictionary_elements_in_chain &&
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015816 new_map->DictionaryElementsInPrototypeChainOnly()) {
15817 // If the prototype chain didn't previously have element callbacks, then
15818 // KeyedStoreICs need to be cleared to ensure any that involve this
15819 // map go generic.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000015820 TypeFeedbackVector::ClearAllKeyedStoreICs(isolate);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015821 }
Andrei Popescu402d9372010-02-26 13:31:12 +000015822
Steve Block44f0eee2011-05-26 01:26:41 +010015823 heap->ClearInstanceofCache();
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015824 DCHECK(size == object->Size());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000015825 return Just(true);
Andrei Popescu402d9372010-02-26 13:31:12 +000015826}
15827
15828
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015829void JSObject::EnsureCanContainElements(Handle<JSObject> object,
15830 Arguments* args,
15831 uint32_t first_arg,
15832 uint32_t arg_count,
15833 EnsureElementsMode mode) {
Ben Murdoch3ef787d2012-04-12 10:51:47 +010015834 // Elements in |Arguments| are ordered backwards (because they're on the
15835 // stack), but the method that's called here iterates over them in forward
15836 // direction.
15837 return EnsureCanContainElements(
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015838 object, args->arguments() - first_arg - (arg_count - 1), arg_count, mode);
Ben Murdoch592a9fc2012-03-05 11:04:45 +000015839}
15840
15841
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000015842ElementsAccessor* JSObject::GetElementsAccessor() {
15843 return ElementsAccessor::ForKind(GetElementsKind());
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015844}
15845
15846
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000015847void JSObject::ValidateElements(Handle<JSObject> object) {
15848#ifdef ENABLE_SLOW_DCHECKS
15849 if (FLAG_enable_slow_asserts) {
15850 ElementsAccessor* accessor = object->GetElementsAccessor();
15851 accessor->Validate(object);
Steve Blocka7e24c12009-10-30 11:49:00 +000015852 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000015853#endif
Steve Blocka7e24c12009-10-30 11:49:00 +000015854}
15855
15856
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000015857static bool ShouldConvertToSlowElements(JSObject* object, uint32_t capacity,
15858 uint32_t index,
15859 uint32_t* new_capacity) {
15860 STATIC_ASSERT(JSObject::kMaxUncheckedOldFastElementsLength <=
15861 JSObject::kMaxUncheckedFastElementsLength);
15862 if (index < capacity) {
15863 *new_capacity = capacity;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000015864 return false;
15865 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000015866 if (index - capacity >= JSObject::kMaxGap) return true;
15867 *new_capacity = JSObject::NewElementsCapacity(index + 1);
15868 DCHECK_LT(index, *new_capacity);
15869 if (*new_capacity <= JSObject::kMaxUncheckedOldFastElementsLength ||
15870 (*new_capacity <= JSObject::kMaxUncheckedFastElementsLength &&
15871 object->GetHeap()->InNewSpace(object))) {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000015872 return false;
15873 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000015874 // If the fast-case backing storage takes up roughly three times as
15875 // much space (in machine words) as a dictionary backing storage
15876 // would, the object should have slow elements.
15877 int used_elements = object->GetFastElementsUsage();
15878 int dictionary_size = SeededNumberDictionary::ComputeCapacity(used_elements) *
15879 SeededNumberDictionary::kEntrySize;
15880 return 3 * static_cast<uint32_t>(dictionary_size) <= *new_capacity;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000015881}
15882
15883
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000015884bool JSObject::WouldConvertToSlowElements(uint32_t index) {
15885 if (HasFastElements()) {
15886 Handle<FixedArrayBase> backing_store(FixedArrayBase::cast(elements()));
15887 uint32_t capacity = static_cast<uint32_t>(backing_store->length());
15888 uint32_t new_capacity;
15889 return ShouldConvertToSlowElements(this, capacity, index, &new_capacity);
15890 }
15891 return false;
15892}
15893
15894
15895static ElementsKind BestFittingFastElementsKind(JSObject* object) {
15896 if (object->HasSloppyArgumentsElements()) {
15897 return FAST_SLOPPY_ARGUMENTS_ELEMENTS;
15898 }
Ben Murdoch097c5b22016-05-18 11:27:45 +010015899 if (object->HasStringWrapperElements()) {
15900 return FAST_STRING_WRAPPER_ELEMENTS;
15901 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000015902 DCHECK(object->HasDictionaryElements());
15903 SeededNumberDictionary* dictionary = object->element_dictionary();
15904 ElementsKind kind = FAST_HOLEY_SMI_ELEMENTS;
15905 for (int i = 0; i < dictionary->Capacity(); i++) {
15906 Object* key = dictionary->KeyAt(i);
15907 if (key->IsNumber()) {
15908 Object* value = dictionary->ValueAt(i);
15909 if (!value->IsNumber()) return FAST_HOLEY_ELEMENTS;
15910 if (!value->IsSmi()) {
15911 if (!FLAG_unbox_double_arrays) return FAST_HOLEY_ELEMENTS;
15912 kind = FAST_HOLEY_DOUBLE_ELEMENTS;
15913 }
15914 }
15915 }
15916 return kind;
15917}
15918
15919
15920static bool ShouldConvertToFastElements(JSObject* object,
15921 SeededNumberDictionary* dictionary,
15922 uint32_t index,
15923 uint32_t* new_capacity) {
15924 // If properties with non-standard attributes or accessors were added, we
15925 // cannot go back to fast elements.
15926 if (dictionary->requires_slow_elements()) return false;
15927
15928 // Adding a property with this index will require slow elements.
15929 if (index >= static_cast<uint32_t>(Smi::kMaxValue)) return false;
15930
15931 if (object->IsJSArray()) {
15932 Object* length = JSArray::cast(object)->length();
15933 if (!length->IsSmi()) return false;
15934 *new_capacity = static_cast<uint32_t>(Smi::cast(length)->value());
15935 } else {
15936 *new_capacity = dictionary->max_number_key() + 1;
15937 }
15938 *new_capacity = Max(index + 1, *new_capacity);
15939
15940 uint32_t dictionary_size = static_cast<uint32_t>(dictionary->Capacity()) *
15941 SeededNumberDictionary::kEntrySize;
15942
15943 // Turn fast if the dictionary only saves 50% space.
15944 return 2 * dictionary_size >= *new_capacity;
15945}
15946
15947
15948// static
15949MaybeHandle<Object> JSObject::AddDataElement(Handle<JSObject> object,
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015950 uint32_t index,
15951 Handle<Object> value,
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000015952 PropertyAttributes attributes) {
15953 MAYBE_RETURN_NULL(
15954 AddDataElement(object, index, value, attributes, THROW_ON_ERROR));
Ben Murdoch3ef787d2012-04-12 10:51:47 +010015955 return value;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000015956}
15957
15958
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000015959// static
15960Maybe<bool> JSObject::AddDataElement(Handle<JSObject> object, uint32_t index,
15961 Handle<Object> value,
15962 PropertyAttributes attributes,
15963 ShouldThrow should_throw) {
15964 DCHECK(object->map()->is_extensible());
15965
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015966 Isolate* isolate = object->GetIsolate();
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000015967
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000015968 uint32_t old_length = 0;
15969 uint32_t new_capacity = 0;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000015970
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015971 Handle<Object> old_length_handle;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000015972 if (object->IsJSArray()) {
15973 CHECK(JSArray::cast(*object)->length()->ToArrayLength(&old_length));
15974 if (object->map()->is_observed()) {
15975 old_length_handle = handle(JSArray::cast(*object)->length(), isolate);
15976 }
15977 }
15978
15979 ElementsKind kind = object->GetElementsKind();
15980 FixedArrayBase* elements = object->elements();
15981 ElementsKind dictionary_kind = DICTIONARY_ELEMENTS;
15982 if (IsSloppyArgumentsElements(kind)) {
15983 elements = FixedArrayBase::cast(FixedArray::cast(elements)->get(1));
15984 dictionary_kind = SLOW_SLOPPY_ARGUMENTS_ELEMENTS;
Ben Murdoch097c5b22016-05-18 11:27:45 +010015985 } else if (IsStringWrapperElementsKind(kind)) {
15986 dictionary_kind = SLOW_STRING_WRAPPER_ELEMENTS;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000015987 }
15988
15989 if (attributes != NONE) {
15990 kind = dictionary_kind;
15991 } else if (elements->IsSeededNumberDictionary()) {
15992 kind = ShouldConvertToFastElements(*object,
15993 SeededNumberDictionary::cast(elements),
15994 index, &new_capacity)
15995 ? BestFittingFastElementsKind(*object)
15996 : dictionary_kind; // Overwrite in case of arguments.
15997 } else if (ShouldConvertToSlowElements(
15998 *object, static_cast<uint32_t>(elements->length()), index,
15999 &new_capacity)) {
16000 kind = dictionary_kind;
16001 }
16002
16003 ElementsKind to = value->OptimalElementsKind();
16004 if (IsHoleyElementsKind(kind) || !object->IsJSArray() || index > old_length) {
16005 to = GetHoleyElementsKind(to);
16006 kind = GetHoleyElementsKind(kind);
16007 }
16008 to = GetMoreGeneralElementsKind(kind, to);
16009 ElementsAccessor* accessor = ElementsAccessor::ForKind(to);
16010 accessor->Add(object, index, value, attributes, new_capacity);
16011
16012 uint32_t new_length = old_length;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000016013 Handle<Object> new_length_handle;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000016014 if (object->IsJSArray() && index >= old_length) {
16015 new_length = index + 1;
16016 new_length_handle = isolate->factory()->NewNumberFromUint(new_length);
16017 JSArray::cast(*object)->set_length(*new_length_handle);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000016018 }
16019
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000016020 if (!old_length_handle.is_null() && new_length != old_length) {
16021 // |old_length_handle| is kept null above unless the object is observed.
16022 DCHECK(object->map()->is_observed());
16023 Handle<JSArray> array = Handle<JSArray>::cast(object);
16024 Handle<String> name = isolate->factory()->Uint32ToString(index);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000016025
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000016026 RETURN_ON_EXCEPTION_VALUE(isolate, BeginPerformSplice(array),
16027 Nothing<bool>());
16028 RETURN_ON_EXCEPTION_VALUE(
16029 isolate, EnqueueChangeRecord(array, "add", name,
16030 isolate->factory()->the_hole_value()),
16031 Nothing<bool>());
16032 RETURN_ON_EXCEPTION_VALUE(
16033 isolate, EnqueueChangeRecord(array, "update",
16034 isolate->factory()->length_string(),
16035 old_length_handle),
16036 Nothing<bool>());
16037 RETURN_ON_EXCEPTION_VALUE(isolate, EndPerformSplice(array),
16038 Nothing<bool>());
16039 Handle<JSArray> deleted = isolate->factory()->NewJSArray(0);
16040 RETURN_ON_EXCEPTION_VALUE(isolate,
16041 EnqueueSpliceRecord(array, old_length, deleted,
16042 new_length - old_length),
16043 Nothing<bool>());
16044 } else if (object->map()->is_observed()) {
16045 Handle<String> name = isolate->factory()->Uint32ToString(index);
16046 RETURN_ON_EXCEPTION_VALUE(
16047 isolate, EnqueueChangeRecord(object, "add", name,
16048 isolate->factory()->the_hole_value()),
16049 Nothing<bool>());
Ben Murdochb8a8cc12014-11-26 15:28:44 +000016050 }
16051
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000016052 return Just(true);
Steve Blocka7e24c12009-10-30 11:49:00 +000016053}
16054
16055
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000016056bool JSArray::SetLengthWouldNormalize(uint32_t new_length) {
16057 if (!HasFastElements()) return false;
16058 uint32_t capacity = static_cast<uint32_t>(elements()->length());
16059 uint32_t new_capacity;
16060 return JSArray::SetLengthWouldNormalize(GetHeap(), new_length) &&
16061 ShouldConvertToSlowElements(this, capacity, new_length - 1,
16062 &new_capacity);
Steve Blocka7e24c12009-10-30 11:49:00 +000016063}
16064
16065
Ben Murdochb8a8cc12014-11-26 15:28:44 +000016066const double AllocationSite::kPretenureRatio = 0.85;
16067
16068
16069void AllocationSite::ResetPretenureDecision() {
16070 set_pretenure_decision(kUndecided);
16071 set_memento_found_count(0);
16072 set_memento_create_count(0);
Ben Murdoch3ef787d2012-04-12 10:51:47 +010016073}
16074
16075
Ben Murdochb8a8cc12014-11-26 15:28:44 +000016076PretenureFlag AllocationSite::GetPretenureMode() {
16077 PretenureDecision mode = pretenure_decision();
16078 // Zombie objects "decide" to be untenured.
16079 return mode == kTenure ? TENURED : NOT_TENURED;
16080}
Ben Murdoch3ef787d2012-04-12 10:51:47 +010016081
Ben Murdochb8a8cc12014-11-26 15:28:44 +000016082
16083bool AllocationSite::IsNestedSite() {
16084 DCHECK(FLAG_trace_track_allocation_sites);
16085 Object* current = GetHeap()->allocation_sites_list();
16086 while (current->IsAllocationSite()) {
16087 AllocationSite* current_site = AllocationSite::cast(current);
16088 if (current_site->nested_site() == this) {
16089 return true;
Ben Murdoch3ef787d2012-04-12 10:51:47 +010016090 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +000016091 current = current_site->weak_next();
16092 }
16093 return false;
16094}
16095
16096
16097void AllocationSite::DigestTransitionFeedback(Handle<AllocationSite> site,
16098 ElementsKind to_kind) {
16099 Isolate* isolate = site->GetIsolate();
16100
16101 if (site->SitePointsToLiteral() && site->transition_info()->IsJSArray()) {
16102 Handle<JSArray> transition_info =
16103 handle(JSArray::cast(site->transition_info()));
16104 ElementsKind kind = transition_info->GetElementsKind();
16105 // if kind is holey ensure that to_kind is as well.
16106 if (IsHoleyElementsKind(kind)) {
16107 to_kind = GetHoleyElementsKind(to_kind);
16108 }
16109 if (IsMoreGeneralElementsKindTransition(kind, to_kind)) {
16110 // If the array is huge, it's not likely to be defined in a local
16111 // function, so we shouldn't make new instances of it very often.
16112 uint32_t length = 0;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000016113 CHECK(transition_info->length()->ToArrayLength(&length));
Ben Murdochb8a8cc12014-11-26 15:28:44 +000016114 if (length <= kMaximumArrayBytesToPretransition) {
16115 if (FLAG_trace_track_allocation_sites) {
16116 bool is_nested = site->IsNestedSite();
16117 PrintF(
16118 "AllocationSite: JSArray %p boilerplate %s updated %s->%s\n",
16119 reinterpret_cast<void*>(*site),
16120 is_nested ? "(nested)" : "",
16121 ElementsKindToString(kind),
16122 ElementsKindToString(to_kind));
16123 }
16124 JSObject::TransitionElementsKind(transition_info, to_kind);
16125 site->dependent_code()->DeoptimizeDependentCodeGroup(
16126 isolate, DependentCode::kAllocationSiteTransitionChangedGroup);
16127 }
16128 }
16129 } else {
16130 ElementsKind kind = site->GetElementsKind();
16131 // if kind is holey ensure that to_kind is as well.
16132 if (IsHoleyElementsKind(kind)) {
16133 to_kind = GetHoleyElementsKind(to_kind);
16134 }
16135 if (IsMoreGeneralElementsKindTransition(kind, to_kind)) {
16136 if (FLAG_trace_track_allocation_sites) {
16137 PrintF("AllocationSite: JSArray %p site updated %s->%s\n",
16138 reinterpret_cast<void*>(*site),
16139 ElementsKindToString(kind),
16140 ElementsKindToString(to_kind));
16141 }
16142 site->SetElementsKind(to_kind);
16143 site->dependent_code()->DeoptimizeDependentCodeGroup(
16144 isolate, DependentCode::kAllocationSiteTransitionChangedGroup);
16145 }
16146 }
16147}
16148
16149
Ben Murdochb8a8cc12014-11-26 15:28:44 +000016150const char* AllocationSite::PretenureDecisionName(PretenureDecision decision) {
16151 switch (decision) {
16152 case kUndecided: return "undecided";
16153 case kDontTenure: return "don't tenure";
16154 case kMaybeTenure: return "maybe tenure";
16155 case kTenure: return "tenure";
16156 case kZombie: return "zombie";
16157 default: UNREACHABLE();
16158 }
16159 return NULL;
16160}
16161
16162
16163void JSObject::UpdateAllocationSite(Handle<JSObject> object,
16164 ElementsKind to_kind) {
16165 if (!object->IsJSArray()) return;
16166
16167 Heap* heap = object->GetHeap();
16168 if (!heap->InNewSpace(*object)) return;
16169
16170 Handle<AllocationSite> site;
16171 {
16172 DisallowHeapAllocation no_allocation;
16173
Ben Murdoch097c5b22016-05-18 11:27:45 +010016174 AllocationMemento* memento =
16175 heap->FindAllocationMemento<Heap::kForRuntime>(*object);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000016176 if (memento == NULL) return;
16177
16178 // Walk through to the Allocation Site
16179 site = handle(memento->GetAllocationSite());
16180 }
16181 AllocationSite::DigestTransitionFeedback(site, to_kind);
16182}
16183
16184
16185void JSObject::TransitionElementsKind(Handle<JSObject> object,
16186 ElementsKind to_kind) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000016187 ElementsKind from_kind = object->GetElementsKind();
Ben Murdochb8a8cc12014-11-26 15:28:44 +000016188
16189 if (IsFastHoleyElementsKind(from_kind)) {
16190 to_kind = GetHoleyElementsKind(to_kind);
Ben Murdoch3ef787d2012-04-12 10:51:47 +010016191 }
16192
Ben Murdochb8a8cc12014-11-26 15:28:44 +000016193 if (from_kind == to_kind) return;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000016194
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000016195 // This method should never be called for any other case.
16196 DCHECK(IsFastElementsKind(from_kind));
16197 DCHECK(IsFastElementsKind(to_kind));
16198 DCHECK_NE(TERMINAL_FAST_ELEMENTS_KIND, from_kind);
16199
16200 UpdateAllocationSite(object, to_kind);
16201 if (object->elements() == object->GetHeap()->empty_fixed_array() ||
16202 IsFastDoubleElementsKind(from_kind) ==
16203 IsFastDoubleElementsKind(to_kind)) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000016204 // No change is needed to the elements() buffer, the transition
16205 // only requires a map change.
16206 Handle<Map> new_map = GetElementsTransitionMap(object, to_kind);
16207 MigrateToMap(object, new_map);
16208 if (FLAG_trace_elements_transitions) {
16209 Handle<FixedArrayBase> elms(object->elements());
16210 PrintElementsTransition(stdout, object, from_kind, elms, to_kind, elms);
16211 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000016212 } else {
16213 DCHECK((IsFastSmiElementsKind(from_kind) &&
16214 IsFastDoubleElementsKind(to_kind)) ||
16215 (IsFastDoubleElementsKind(from_kind) &&
16216 IsFastObjectElementsKind(to_kind)));
16217 uint32_t c = static_cast<uint32_t>(object->elements()->length());
16218 ElementsAccessor::ForKind(to_kind)->GrowCapacityAndConvert(object, c);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000016219 }
Ben Murdoch3ef787d2012-04-12 10:51:47 +010016220}
16221
16222
16223// static
16224bool Map::IsValidElementsTransition(ElementsKind from_kind,
16225 ElementsKind to_kind) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000016226 // Transitions can't go backwards.
16227 if (!IsMoreGeneralElementsKindTransition(from_kind, to_kind)) {
16228 return false;
16229 }
16230
16231 // Transitions from HOLEY -> PACKED are not allowed.
16232 return !IsFastHoleyElementsKind(from_kind) ||
16233 IsFastHoleyElementsKind(to_kind);
Ben Murdoch3ef787d2012-04-12 10:51:47 +010016234}
16235
16236
Emily Bernierd0a1eb72015-03-24 16:35:39 -040016237bool JSArray::HasReadOnlyLength(Handle<JSArray> array) {
16238 LookupIterator it(array, array->GetIsolate()->factory()->length_string(),
16239 LookupIterator::OWN_SKIP_INTERCEPTOR);
16240 CHECK_NE(LookupIterator::ACCESS_CHECK, it.state());
16241 CHECK(it.IsFound());
16242 CHECK_EQ(LookupIterator::ACCESSOR, it.state());
16243 return it.IsReadOnly();
16244}
16245
16246
Ben Murdochb8a8cc12014-11-26 15:28:44 +000016247bool JSArray::WouldChangeReadOnlyLength(Handle<JSArray> array,
16248 uint32_t index) {
16249 uint32_t length = 0;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000016250 CHECK(array->length()->ToArrayLength(&length));
Emily Bernierd0a1eb72015-03-24 16:35:39 -040016251 if (length <= index) return HasReadOnlyLength(array);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000016252 return false;
16253}
16254
16255
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000016256template <typename BackingStore>
16257static int FastHoleyElementsUsage(JSObject* object, BackingStore* store) {
16258 int limit = object->IsJSArray()
16259 ? Smi::cast(JSArray::cast(object)->length())->value()
16260 : store->length();
Ben Murdoch69a99ed2011-11-30 16:03:39 +000016261 int used = 0;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000016262 for (int i = 0; i < limit; ++i) {
16263 if (!store->is_the_hole(i)) ++used;
16264 }
16265 return used;
Ben Murdoch69a99ed2011-11-30 16:03:39 +000016266}
16267
16268
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000016269int JSObject::GetFastElementsUsage() {
16270 FixedArrayBase* store = elements();
Steve Blocka7e24c12009-10-30 11:49:00 +000016271 switch (GetElementsKind()) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000016272 case FAST_SMI_ELEMENTS:
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000016273 case FAST_DOUBLE_ELEMENTS:
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000016274 case FAST_ELEMENTS:
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000016275 return IsJSArray() ? Smi::cast(JSArray::cast(this)->length())->value()
16276 : store->length();
16277 case FAST_SLOPPY_ARGUMENTS_ELEMENTS:
16278 store = FixedArray::cast(FixedArray::cast(store)->get(1));
16279 // Fall through.
Ben Murdochb8a8cc12014-11-26 15:28:44 +000016280 case FAST_HOLEY_SMI_ELEMENTS:
16281 case FAST_HOLEY_ELEMENTS:
Ben Murdoch097c5b22016-05-18 11:27:45 +010016282 case FAST_STRING_WRAPPER_ELEMENTS:
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000016283 return FastHoleyElementsUsage(this, FixedArray::cast(store));
16284 case FAST_HOLEY_DOUBLE_ELEMENTS:
16285 if (elements()->length() == 0) return 0;
16286 return FastHoleyElementsUsage(this, FixedDoubleArray::cast(store));
Ben Murdochb8a8cc12014-11-26 15:28:44 +000016287
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000016288 case SLOW_SLOPPY_ARGUMENTS_ELEMENTS:
Ben Murdoch097c5b22016-05-18 11:27:45 +010016289 case SLOW_STRING_WRAPPER_ELEMENTS:
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000016290 case DICTIONARY_ELEMENTS:
Ben Murdoch097c5b22016-05-18 11:27:45 +010016291 case NO_ELEMENTS:
Ben Murdochb8a8cc12014-11-26 15:28:44 +000016292#define TYPED_ARRAY_CASE(Type, type, TYPE, ctype, size) \
Ben Murdochb8a8cc12014-11-26 15:28:44 +000016293 case TYPE##_ELEMENTS: \
16294
16295 TYPED_ARRAYS(TYPED_ARRAY_CASE)
16296#undef TYPED_ARRAY_CASE
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000016297 UNREACHABLE();
Steve Blocka7e24c12009-10-30 11:49:00 +000016298 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000016299 return 0;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000016300}
16301
16302
Steve Blocka7e24c12009-10-30 11:49:00 +000016303// Certain compilers request function template instantiation when they
16304// see the definition of the other template functions in the
16305// class. This requires us to have the template functions put
16306// together, so even though this function belongs in objects-debug.cc,
16307// we keep it here instead to satisfy certain compilers.
Ben Murdochb0fe1622011-05-05 13:52:32 +010016308#ifdef OBJECT_PRINT
Ben Murdochb8a8cc12014-11-26 15:28:44 +000016309template <typename Derived, typename Shape, typename Key>
Emily Bernierd0a1eb72015-03-24 16:35:39 -040016310void Dictionary<Derived, Shape, Key>::Print(std::ostream& os) { // NOLINT
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000016311 int capacity = this->Capacity();
Steve Blocka7e24c12009-10-30 11:49:00 +000016312 for (int i = 0; i < capacity; i++) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000016313 Object* k = this->KeyAt(i);
16314 if (this->IsKey(k)) {
16315 os << "\n ";
Steve Blocka7e24c12009-10-30 11:49:00 +000016316 if (k->IsString()) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000016317 String::cast(k)->StringPrint(os);
Steve Blocka7e24c12009-10-30 11:49:00 +000016318 } else {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000016319 os << Brief(k);
Steve Blocka7e24c12009-10-30 11:49:00 +000016320 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000016321 os << ": " << Brief(this->ValueAt(i)) << " " << this->DetailsAt(i);
Steve Blocka7e24c12009-10-30 11:49:00 +000016322 }
16323 }
16324}
16325#endif
16326
16327
Ben Murdochb8a8cc12014-11-26 15:28:44 +000016328template<typename Derived, typename Shape, typename Key>
16329void Dictionary<Derived, Shape, Key>::CopyValuesTo(FixedArray* elements) {
Steve Blocka7e24c12009-10-30 11:49:00 +000016330 int pos = 0;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000016331 int capacity = this->Capacity();
Ben Murdochb8a8cc12014-11-26 15:28:44 +000016332 DisallowHeapAllocation no_gc;
Leon Clarke4515c472010-02-03 11:58:03 +000016333 WriteBarrierMode mode = elements->GetWriteBarrierMode(no_gc);
Steve Blocka7e24c12009-10-30 11:49:00 +000016334 for (int i = 0; i < capacity; i++) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000016335 Object* k = this->KeyAt(i);
16336 if (this->IsKey(k)) {
16337 elements->set(pos++, this->ValueAt(i), mode);
Steve Blocka7e24c12009-10-30 11:49:00 +000016338 }
16339 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +000016340 DCHECK(pos == elements->length());
Steve Blocka7e24c12009-10-30 11:49:00 +000016341}
16342
16343
16344InterceptorInfo* JSObject::GetNamedInterceptor() {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000016345 DCHECK(map()->has_named_interceptor());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000016346 JSFunction* constructor = JSFunction::cast(map()->GetConstructor());
Ben Murdochb8a8cc12014-11-26 15:28:44 +000016347 DCHECK(constructor->shared()->IsApiFunction());
Steve Blocka7e24c12009-10-30 11:49:00 +000016348 Object* result =
Steve Block6ded16b2010-05-10 14:33:55 +010016349 constructor->shared()->get_api_func_data()->named_property_handler();
Steve Blocka7e24c12009-10-30 11:49:00 +000016350 return InterceptorInfo::cast(result);
16351}
16352
16353
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000016354MaybeHandle<Object> JSObject::GetPropertyWithInterceptor(LookupIterator* it,
16355 bool* done) {
16356 *done = false;
16357 Isolate* isolate = it->isolate();
16358 // Make sure that the top context does not change when doing callbacks or
16359 // interceptor calls.
16360 AssertNoContextChange ncc(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +000016361
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000016362 DCHECK_EQ(LookupIterator::INTERCEPTOR, it->state());
16363 Handle<InterceptorInfo> interceptor = it->GetInterceptor();
16364 if (interceptor->getter()->IsUndefined()) {
16365 return isolate->factory()->undefined_value();
Emily Bernierd0a1eb72015-03-24 16:35:39 -040016366 }
16367
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000016368 Handle<JSObject> holder = it->GetHolder<JSObject>();
16369 v8::Local<v8::Value> result;
16370 PropertyCallbackArguments args(isolate, interceptor->data(),
Ben Murdoch097c5b22016-05-18 11:27:45 +010016371 *it->GetReceiver(), *holder,
16372 Object::DONT_THROW);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000016373
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000016374 if (it->IsElement()) {
16375 uint32_t index = it->index();
16376 v8::IndexedPropertyGetterCallback getter =
16377 v8::ToCData<v8::IndexedPropertyGetterCallback>(interceptor->getter());
16378 LOG(isolate,
16379 ApiIndexedPropertyAccess("interceptor-indexed-get", *holder, index));
16380 result = args.Call(getter, index);
16381 } else {
16382 Handle<Name> name = it->name();
16383 DCHECK(!name->IsPrivate());
16384
16385 if (name->IsSymbol() && !interceptor->can_intercept_symbols()) {
16386 return isolate->factory()->undefined_value();
16387 }
16388
16389 v8::GenericNamedPropertyGetterCallback getter =
16390 v8::ToCData<v8::GenericNamedPropertyGetterCallback>(
16391 interceptor->getter());
16392 LOG(isolate,
16393 ApiNamedPropertyAccess("interceptor-named-get", *holder, *name));
16394 result = args.Call(getter, v8::Utils::ToLocal(name));
16395 }
16396
16397 RETURN_EXCEPTION_IF_SCHEDULED_EXCEPTION(isolate, Object);
16398 if (result.IsEmpty()) return isolate->factory()->undefined_value();
Ben Murdochb8a8cc12014-11-26 15:28:44 +000016399 Handle<Object> result_internal = v8::Utils::OpenHandle(*result);
16400 result_internal->VerifyApiCallResultType();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000016401 *done = true;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000016402 // Rebox handle before return
16403 return handle(*result_internal, isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +000016404}
16405
16406
Ben Murdochb8a8cc12014-11-26 15:28:44 +000016407Maybe<bool> JSObject::HasRealNamedProperty(Handle<JSObject> object,
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000016408 Handle<Name> name) {
16409 LookupIterator it = LookupIterator::PropertyOrElement(
16410 name->GetIsolate(), object, name, LookupIterator::OWN_SKIP_INTERCEPTOR);
16411 return HasProperty(&it);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000016412}
16413
16414
16415Maybe<bool> JSObject::HasRealElementProperty(Handle<JSObject> object,
16416 uint32_t index) {
16417 Isolate* isolate = object->GetIsolate();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000016418 LookupIterator it(isolate, object, index,
16419 LookupIterator::OWN_SKIP_INTERCEPTOR);
16420 return HasProperty(&it);
Steve Blocka7e24c12009-10-30 11:49:00 +000016421}
16422
16423
Ben Murdochb8a8cc12014-11-26 15:28:44 +000016424Maybe<bool> JSObject::HasRealNamedCallbackProperty(Handle<JSObject> object,
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000016425 Handle<Name> name) {
16426 LookupIterator it = LookupIterator::PropertyOrElement(
16427 name->GetIsolate(), object, name, LookupIterator::OWN_SKIP_INTERCEPTOR);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000016428 Maybe<PropertyAttributes> maybe_result = GetPropertyAttributes(&it);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000016429 return maybe_result.IsJust() ? Just(it.state() == LookupIterator::ACCESSOR)
16430 : Nothing<bool>();
Steve Blocka7e24c12009-10-30 11:49:00 +000016431}
16432
16433
16434void FixedArray::SwapPairs(FixedArray* numbers, int i, int j) {
16435 Object* temp = get(i);
16436 set(i, get(j));
16437 set(j, temp);
16438 if (this != numbers) {
16439 temp = numbers->get(i);
Ben Murdoch3ef787d2012-04-12 10:51:47 +010016440 numbers->set(i, Smi::cast(numbers->get(j)));
16441 numbers->set(j, Smi::cast(temp));
Steve Blocka7e24c12009-10-30 11:49:00 +000016442 }
16443}
16444
16445
16446static void InsertionSortPairs(FixedArray* content,
16447 FixedArray* numbers,
16448 int len) {
16449 for (int i = 1; i < len; i++) {
16450 int j = i;
16451 while (j > 0 &&
16452 (NumberToUint32(numbers->get(j - 1)) >
16453 NumberToUint32(numbers->get(j)))) {
16454 content->SwapPairs(numbers, j - 1, j);
16455 j--;
16456 }
16457 }
16458}
16459
16460
16461void HeapSortPairs(FixedArray* content, FixedArray* numbers, int len) {
16462 // In-place heap sort.
Ben Murdochb8a8cc12014-11-26 15:28:44 +000016463 DCHECK(content->length() == numbers->length());
Steve Blocka7e24c12009-10-30 11:49:00 +000016464
16465 // Bottom-up max-heap construction.
16466 for (int i = 1; i < len; ++i) {
16467 int child_index = i;
16468 while (child_index > 0) {
16469 int parent_index = ((child_index + 1) >> 1) - 1;
16470 uint32_t parent_value = NumberToUint32(numbers->get(parent_index));
16471 uint32_t child_value = NumberToUint32(numbers->get(child_index));
16472 if (parent_value < child_value) {
16473 content->SwapPairs(numbers, parent_index, child_index);
16474 } else {
16475 break;
16476 }
16477 child_index = parent_index;
16478 }
16479 }
16480
16481 // Extract elements and create sorted array.
16482 for (int i = len - 1; i > 0; --i) {
16483 // Put max element at the back of the array.
16484 content->SwapPairs(numbers, 0, i);
16485 // Sift down the new top element.
16486 int parent_index = 0;
16487 while (true) {
16488 int child_index = ((parent_index + 1) << 1) - 1;
16489 if (child_index >= i) break;
16490 uint32_t child1_value = NumberToUint32(numbers->get(child_index));
16491 uint32_t child2_value = NumberToUint32(numbers->get(child_index + 1));
16492 uint32_t parent_value = NumberToUint32(numbers->get(parent_index));
16493 if (child_index + 1 >= i || child1_value > child2_value) {
16494 if (parent_value > child1_value) break;
16495 content->SwapPairs(numbers, parent_index, child_index);
16496 parent_index = child_index;
16497 } else {
16498 if (parent_value > child2_value) break;
16499 content->SwapPairs(numbers, parent_index, child_index + 1);
16500 parent_index = child_index + 1;
16501 }
16502 }
16503 }
16504}
16505
16506
16507// Sort this array and the numbers as pairs wrt. the (distinct) numbers.
16508void FixedArray::SortPairs(FixedArray* numbers, uint32_t len) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000016509 DCHECK(this->length() == numbers->length());
Steve Blocka7e24c12009-10-30 11:49:00 +000016510 // For small arrays, simply use insertion sort.
16511 if (len <= 10) {
16512 InsertionSortPairs(this, numbers, len);
16513 return;
16514 }
16515 // Check the range of indices.
16516 uint32_t min_index = NumberToUint32(numbers->get(0));
16517 uint32_t max_index = min_index;
16518 uint32_t i;
16519 for (i = 1; i < len; i++) {
16520 if (NumberToUint32(numbers->get(i)) < min_index) {
16521 min_index = NumberToUint32(numbers->get(i));
16522 } else if (NumberToUint32(numbers->get(i)) > max_index) {
16523 max_index = NumberToUint32(numbers->get(i));
16524 }
16525 }
16526 if (max_index - min_index + 1 == len) {
16527 // Indices form a contiguous range, unless there are duplicates.
16528 // Do an in-place linear time sort assuming distinct numbers, but
16529 // avoid hanging in case they are not.
16530 for (i = 0; i < len; i++) {
16531 uint32_t p;
16532 uint32_t j = 0;
16533 // While the current element at i is not at its correct position p,
16534 // swap the elements at these two positions.
16535 while ((p = NumberToUint32(numbers->get(i)) - min_index) != i &&
16536 j++ < len) {
16537 SwapPairs(numbers, i, p);
16538 }
16539 }
16540 } else {
16541 HeapSortPairs(this, numbers, len);
16542 return;
16543 }
16544}
16545
16546
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000016547void JSObject::CollectOwnPropertyNames(KeyAccumulator* keys,
16548 PropertyFilter filter) {
Steve Blocka7e24c12009-10-30 11:49:00 +000016549 if (HasFastProperties()) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000016550 int real_size = map()->NumberOfOwnDescriptors();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000016551 Handle<DescriptorArray> descs(map()->instance_descriptors());
Ben Murdochb8a8cc12014-11-26 15:28:44 +000016552 for (int i = 0; i < real_size; i++) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000016553 PropertyDetails details = descs->GetDetails(i);
16554 if ((details.attributes() & filter) != 0) continue;
16555 if (filter & ONLY_ALL_CAN_READ) {
16556 if (details.kind() != kAccessor) continue;
16557 Object* accessors = descs->GetValue(i);
16558 if (!accessors->IsAccessorInfo()) continue;
16559 if (!AccessorInfo::cast(accessors)->all_can_read()) continue;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000016560 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000016561 Name* key = descs->GetKey(i);
16562 if (key->FilterKey(filter)) continue;
Ben Murdoch097c5b22016-05-18 11:27:45 +010016563 keys->AddKey(key, DO_NOT_CONVERT);
Steve Blocka7e24c12009-10-30 11:49:00 +000016564 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000016565 } else if (IsJSGlobalObject()) {
16566 GlobalDictionary::CollectKeysTo(handle(global_dictionary()), keys, filter);
Steve Blocka7e24c12009-10-30 11:49:00 +000016567 } else {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000016568 NameDictionary::CollectKeysTo(handle(property_dictionary()), keys, filter);
Steve Blocka7e24c12009-10-30 11:49:00 +000016569 }
16570}
16571
16572
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000016573int JSObject::NumberOfOwnElements(PropertyFilter filter) {
16574 // Fast case for objects with no elements.
16575 if (!IsJSValue() && HasFastElements()) {
16576 uint32_t length =
16577 IsJSArray()
16578 ? static_cast<uint32_t>(
16579 Smi::cast(JSArray::cast(this)->length())->value())
16580 : static_cast<uint32_t>(FixedArrayBase::cast(elements())->length());
16581 if (length == 0) return 0;
16582 }
16583 // Compute the number of enumerable elements.
Ben Murdochb8a8cc12014-11-26 15:28:44 +000016584 return GetOwnElementKeys(NULL, filter);
Steve Blocka7e24c12009-10-30 11:49:00 +000016585}
16586
16587
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000016588void JSObject::CollectOwnElementKeys(Handle<JSObject> object,
16589 KeyAccumulator* keys,
16590 PropertyFilter filter) {
16591 if (filter & SKIP_STRINGS) return;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000016592 ElementsAccessor* accessor = object->GetElementsAccessor();
16593 accessor->CollectElementIndices(object, keys, kMaxUInt32, filter, 0);
Steve Blocka7e24c12009-10-30 11:49:00 +000016594}
16595
16596
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000016597int JSObject::GetOwnElementKeys(FixedArray* storage, PropertyFilter filter) {
Steve Blocka7e24c12009-10-30 11:49:00 +000016598 int counter = 0;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000016599
16600 // If this is a String wrapper, add the string indices first,
16601 // as they're guaranteed to precede the elements in numerical order
16602 // and ascending order is required by ECMA-262, 6th, 9.1.12.
16603 if (IsJSValue()) {
16604 Object* val = JSValue::cast(this)->value();
16605 if (val->IsString()) {
16606 String* str = String::cast(val);
16607 if (storage) {
16608 for (int i = 0; i < str->length(); i++) {
16609 storage->set(counter + i, Smi::FromInt(i));
16610 }
16611 }
16612 counter += str->length();
16613 }
16614 }
16615
Steve Blocka7e24c12009-10-30 11:49:00 +000016616 switch (GetElementsKind()) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000016617 case FAST_SMI_ELEMENTS:
16618 case FAST_ELEMENTS:
16619 case FAST_HOLEY_SMI_ELEMENTS:
Ben Murdoch097c5b22016-05-18 11:27:45 +010016620 case FAST_HOLEY_ELEMENTS:
16621 case FAST_STRING_WRAPPER_ELEMENTS: {
Steve Blocka7e24c12009-10-30 11:49:00 +000016622 int length = IsJSArray() ?
16623 Smi::cast(JSArray::cast(this)->length())->value() :
16624 FixedArray::cast(elements())->length();
16625 for (int i = 0; i < length; i++) {
16626 if (!FixedArray::cast(elements())->get(i)->IsTheHole()) {
16627 if (storage != NULL) {
Leon Clarke4515c472010-02-03 11:58:03 +000016628 storage->set(counter, Smi::FromInt(i));
Steve Blocka7e24c12009-10-30 11:49:00 +000016629 }
16630 counter++;
16631 }
16632 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +000016633 DCHECK(!storage || storage->length() >= counter);
Steve Blocka7e24c12009-10-30 11:49:00 +000016634 break;
16635 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +000016636 case FAST_DOUBLE_ELEMENTS:
16637 case FAST_HOLEY_DOUBLE_ELEMENTS: {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000016638 int length = IsJSArray() ?
16639 Smi::cast(JSArray::cast(this)->length())->value() :
Ben Murdochb8a8cc12014-11-26 15:28:44 +000016640 FixedArrayBase::cast(elements())->length();
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000016641 for (int i = 0; i < length; i++) {
16642 if (!FixedDoubleArray::cast(elements())->is_the_hole(i)) {
16643 if (storage != NULL) {
16644 storage->set(counter, Smi::FromInt(i));
16645 }
16646 counter++;
16647 }
16648 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +000016649 DCHECK(!storage || storage->length() >= counter);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000016650 break;
16651 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +000016652
16653#define TYPED_ARRAY_CASE(Type, type, TYPE, ctype, size) \
Ben Murdochb8a8cc12014-11-26 15:28:44 +000016654 case TYPE##_ELEMENTS: \
16655
16656 TYPED_ARRAYS(TYPED_ARRAY_CASE)
16657#undef TYPED_ARRAY_CASE
16658 {
16659 int length = FixedArrayBase::cast(elements())->length();
Steve Blocka7e24c12009-10-30 11:49:00 +000016660 while (counter < length) {
16661 if (storage != NULL) {
Leon Clarke4515c472010-02-03 11:58:03 +000016662 storage->set(counter, Smi::FromInt(counter));
Steve Blocka7e24c12009-10-30 11:49:00 +000016663 }
16664 counter++;
16665 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +000016666 DCHECK(!storage || storage->length() >= counter);
Steve Blocka7e24c12009-10-30 11:49:00 +000016667 break;
16668 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +000016669
Ben Murdoch097c5b22016-05-18 11:27:45 +010016670 case DICTIONARY_ELEMENTS:
16671 case SLOW_STRING_WRAPPER_ELEMENTS: {
Steve Blocka7e24c12009-10-30 11:49:00 +000016672 if (storage != NULL) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000016673 element_dictionary()->CopyKeysTo(storage, counter, filter,
Ben Murdochc7cc0282012-03-05 14:35:55 +000016674 SeededNumberDictionary::SORTED);
Steve Blocka7e24c12009-10-30 11:49:00 +000016675 }
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000016676 counter += element_dictionary()->NumberOfElementsFilterAttributes(filter);
Steve Blocka7e24c12009-10-30 11:49:00 +000016677 break;
16678 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000016679 case FAST_SLOPPY_ARGUMENTS_ELEMENTS:
16680 case SLOW_SLOPPY_ARGUMENTS_ELEMENTS: {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000016681 FixedArray* parameter_map = FixedArray::cast(elements());
16682 int mapped_length = parameter_map->length() - 2;
16683 FixedArray* arguments = FixedArray::cast(parameter_map->get(1));
16684 if (arguments->IsDictionary()) {
16685 // Copy the keys from arguments first, because Dictionary::CopyKeysTo
16686 // will insert in storage starting at index 0.
Ben Murdochc7cc0282012-03-05 14:35:55 +000016687 SeededNumberDictionary* dictionary =
16688 SeededNumberDictionary::cast(arguments);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000016689 if (storage != NULL) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000016690 dictionary->CopyKeysTo(storage, counter, filter,
16691 SeededNumberDictionary::UNSORTED);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000016692 }
16693 counter += dictionary->NumberOfElementsFilterAttributes(filter);
16694 for (int i = 0; i < mapped_length; ++i) {
16695 if (!parameter_map->get(i + 2)->IsTheHole()) {
16696 if (storage != NULL) storage->set(counter, Smi::FromInt(i));
16697 ++counter;
16698 }
16699 }
16700 if (storage != NULL) storage->SortPairs(storage, counter);
16701
16702 } else {
16703 int backing_length = arguments->length();
16704 int i = 0;
16705 for (; i < mapped_length; ++i) {
16706 if (!parameter_map->get(i + 2)->IsTheHole()) {
16707 if (storage != NULL) storage->set(counter, Smi::FromInt(i));
16708 ++counter;
16709 } else if (i < backing_length && !arguments->get(i)->IsTheHole()) {
16710 if (storage != NULL) storage->set(counter, Smi::FromInt(i));
16711 ++counter;
16712 }
16713 }
16714 for (; i < backing_length; ++i) {
16715 if (storage != NULL) storage->set(counter, Smi::FromInt(i));
16716 ++counter;
16717 }
16718 }
Steve Blocka7e24c12009-10-30 11:49:00 +000016719 break;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000016720 }
Ben Murdoch097c5b22016-05-18 11:27:45 +010016721 case NO_ELEMENTS:
16722 break;
Steve Blocka7e24c12009-10-30 11:49:00 +000016723 }
16724
Ben Murdochb8a8cc12014-11-26 15:28:44 +000016725 DCHECK(!storage || storage->length() == counter);
Steve Blocka7e24c12009-10-30 11:49:00 +000016726 return counter;
16727}
16728
16729
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000016730MaybeHandle<String> Object::ObjectProtoToString(Isolate* isolate,
16731 Handle<Object> object) {
16732 if (object->IsUndefined()) return isolate->factory()->undefined_to_string();
16733 if (object->IsNull()) return isolate->factory()->null_to_string();
16734
Ben Murdoch097c5b22016-05-18 11:27:45 +010016735 Handle<JSReceiver> receiver =
16736 Object::ToObject(isolate, object).ToHandleChecked();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000016737
16738 Handle<String> tag;
16739 if (FLAG_harmony_tostring) {
16740 Handle<Object> to_string_tag;
16741 ASSIGN_RETURN_ON_EXCEPTION(
16742 isolate, to_string_tag,
16743 GetProperty(receiver, isolate->factory()->to_string_tag_symbol()),
16744 String);
16745 if (to_string_tag->IsString()) {
16746 tag = Handle<String>::cast(to_string_tag);
16747 }
16748 }
16749
16750 if (tag.is_null()) {
16751 ASSIGN_RETURN_ON_EXCEPTION(isolate, tag,
16752 JSReceiver::BuiltinStringTag(receiver), String);
16753 }
16754
16755 IncrementalStringBuilder builder(isolate);
16756 builder.AppendCString("[object ");
16757 builder.AppendString(tag);
16758 builder.AppendCharacter(']');
16759 return builder.Finish();
Steve Blocka7e24c12009-10-30 11:49:00 +000016760}
16761
16762
Emily Bernierd0a1eb72015-03-24 16:35:39 -040016763const char* Symbol::PrivateSymbolToName() const {
16764 Heap* heap = GetIsolate()->heap();
16765#define SYMBOL_CHECK_AND_PRINT(name) \
16766 if (this == heap->name()) return #name;
16767 PRIVATE_SYMBOL_LIST(SYMBOL_CHECK_AND_PRINT)
16768#undef SYMBOL_CHECK_AND_PRINT
16769 return "UNKNOWN";
16770}
16771
16772
16773void Symbol::SymbolShortPrint(std::ostream& os) {
16774 os << "<Symbol: " << Hash();
16775 if (!name()->IsUndefined()) {
16776 os << " ";
16777 HeapStringAllocator allocator;
16778 StringStream accumulator(&allocator);
16779 String::cast(name())->StringShortPrint(&accumulator);
16780 os << accumulator.ToCString().get();
16781 } else {
16782 os << " (" << PrivateSymbolToName() << ")";
16783 }
16784 os << ">";
16785}
16786
16787
Steve Blocka7e24c12009-10-30 11:49:00 +000016788// StringSharedKeys are used as keys in the eval cache.
16789class StringSharedKey : public HashTableKey {
16790 public:
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000016791 StringSharedKey(Handle<String> source, Handle<SharedFunctionInfo> shared,
16792 LanguageMode language_mode, int scope_position)
Steve Block1e0659c2011-05-24 12:43:12 +010016793 : source_(source),
16794 shared_(shared),
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000016795 language_mode_(language_mode),
16796 scope_position_(scope_position) {}
Steve Blocka7e24c12009-10-30 11:49:00 +000016797
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000016798 bool IsMatch(Object* other) override {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000016799 DisallowHeapAllocation no_allocation;
Emily Bernierd0a1eb72015-03-24 16:35:39 -040016800 if (!other->IsFixedArray()) {
16801 if (!other->IsNumber()) return false;
16802 uint32_t other_hash = static_cast<uint32_t>(other->Number());
16803 return Hash() == other_hash;
16804 }
Ben Murdoch3ef787d2012-04-12 10:51:47 +010016805 FixedArray* other_array = FixedArray::cast(other);
16806 SharedFunctionInfo* shared = SharedFunctionInfo::cast(other_array->get(0));
Ben Murdochb8a8cc12014-11-26 15:28:44 +000016807 if (shared != *shared_) return false;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000016808 int language_unchecked = Smi::cast(other_array->get(2))->value();
16809 DCHECK(is_valid_language_mode(language_unchecked));
16810 LanguageMode language_mode = static_cast<LanguageMode>(language_unchecked);
16811 if (language_mode != language_mode_) return false;
Ben Murdoch3ef787d2012-04-12 10:51:47 +010016812 int scope_position = Smi::cast(other_array->get(3))->value();
16813 if (scope_position != scope_position_) return false;
16814 String* source = String::cast(other_array->get(1));
Ben Murdochb8a8cc12014-11-26 15:28:44 +000016815 return source->Equals(*source_);
Steve Blocka7e24c12009-10-30 11:49:00 +000016816 }
16817
16818 static uint32_t StringSharedHashHelper(String* source,
Steve Block1e0659c2011-05-24 12:43:12 +010016819 SharedFunctionInfo* shared,
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000016820 LanguageMode language_mode,
Ben Murdoch3ef787d2012-04-12 10:51:47 +010016821 int scope_position) {
Steve Blocka7e24c12009-10-30 11:49:00 +000016822 uint32_t hash = source->Hash();
16823 if (shared->HasSourceCode()) {
16824 // Instead of using the SharedFunctionInfo pointer in the hash
16825 // code computation, we use a combination of the hash of the
Ben Murdoch3ef787d2012-04-12 10:51:47 +010016826 // script source code and the start position of the calling scope.
16827 // We do this to ensure that the cache entries can survive garbage
Steve Blocka7e24c12009-10-30 11:49:00 +000016828 // collection.
Ben Murdochb8a8cc12014-11-26 15:28:44 +000016829 Script* script(Script::cast(shared->script()));
Steve Blocka7e24c12009-10-30 11:49:00 +000016830 hash ^= String::cast(script->source())->Hash();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000016831 STATIC_ASSERT(LANGUAGE_END == 3);
16832 if (is_strict(language_mode)) hash ^= 0x8000;
16833 if (is_strong(language_mode)) hash ^= 0x10000;
Ben Murdoch3ef787d2012-04-12 10:51:47 +010016834 hash += scope_position;
Steve Blocka7e24c12009-10-30 11:49:00 +000016835 }
16836 return hash;
16837 }
16838
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000016839 uint32_t Hash() override {
16840 return StringSharedHashHelper(*source_, *shared_, language_mode_,
Ben Murdochb8a8cc12014-11-26 15:28:44 +000016841 scope_position_);
Steve Blocka7e24c12009-10-30 11:49:00 +000016842 }
16843
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000016844 uint32_t HashForObject(Object* obj) override {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000016845 DisallowHeapAllocation no_allocation;
Emily Bernierd0a1eb72015-03-24 16:35:39 -040016846 if (obj->IsNumber()) {
16847 return static_cast<uint32_t>(obj->Number());
16848 }
Ben Murdoch3ef787d2012-04-12 10:51:47 +010016849 FixedArray* other_array = FixedArray::cast(obj);
16850 SharedFunctionInfo* shared = SharedFunctionInfo::cast(other_array->get(0));
16851 String* source = String::cast(other_array->get(1));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000016852 int language_unchecked = Smi::cast(other_array->get(2))->value();
16853 DCHECK(is_valid_language_mode(language_unchecked));
16854 LanguageMode language_mode = static_cast<LanguageMode>(language_unchecked);
Ben Murdoch3ef787d2012-04-12 10:51:47 +010016855 int scope_position = Smi::cast(other_array->get(3))->value();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000016856 return StringSharedHashHelper(source, shared, language_mode,
16857 scope_position);
Steve Blocka7e24c12009-10-30 11:49:00 +000016858 }
16859
Ben Murdochb8a8cc12014-11-26 15:28:44 +000016860
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000016861 Handle<Object> AsHandle(Isolate* isolate) override {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000016862 Handle<FixedArray> array = isolate->factory()->NewFixedArray(4);
16863 array->set(0, *shared_);
16864 array->set(1, *source_);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000016865 array->set(2, Smi::FromInt(language_mode_));
Ben Murdochb8a8cc12014-11-26 15:28:44 +000016866 array->set(3, Smi::FromInt(scope_position_));
16867 return array;
Steve Blocka7e24c12009-10-30 11:49:00 +000016868 }
16869
16870 private:
Ben Murdochb8a8cc12014-11-26 15:28:44 +000016871 Handle<String> source_;
16872 Handle<SharedFunctionInfo> shared_;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000016873 LanguageMode language_mode_;
Ben Murdoch3ef787d2012-04-12 10:51:47 +010016874 int scope_position_;
Steve Blocka7e24c12009-10-30 11:49:00 +000016875};
16876
16877
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000016878namespace {
16879
16880JSRegExp::Flags RegExpFlagsFromString(Handle<String> flags, bool* success) {
16881 JSRegExp::Flags value = JSRegExp::kNone;
16882 int length = flags->length();
16883 // A longer flags string cannot be valid.
16884 if (length > 5) return JSRegExp::Flags(0);
16885 for (int i = 0; i < length; i++) {
16886 JSRegExp::Flag flag = JSRegExp::kNone;
16887 switch (flags->Get(i)) {
16888 case 'g':
16889 flag = JSRegExp::kGlobal;
16890 break;
16891 case 'i':
16892 flag = JSRegExp::kIgnoreCase;
16893 break;
16894 case 'm':
16895 flag = JSRegExp::kMultiline;
16896 break;
16897 case 'u':
16898 if (!FLAG_harmony_unicode_regexps) return JSRegExp::Flags(0);
16899 flag = JSRegExp::kUnicode;
16900 break;
16901 case 'y':
16902 if (!FLAG_harmony_regexps) return JSRegExp::Flags(0);
16903 flag = JSRegExp::kSticky;
16904 break;
16905 default:
16906 return JSRegExp::Flags(0);
16907 }
16908 // Duplicate flag.
16909 if (value & flag) return JSRegExp::Flags(0);
16910 value |= flag;
16911 }
16912 *success = true;
16913 return value;
16914}
16915
16916} // namespace
16917
16918
16919// static
16920MaybeHandle<JSRegExp> JSRegExp::New(Handle<String> pattern, Flags flags) {
16921 Isolate* isolate = pattern->GetIsolate();
16922 Handle<JSFunction> constructor = isolate->regexp_function();
16923 Handle<JSRegExp> regexp =
16924 Handle<JSRegExp>::cast(isolate->factory()->NewJSObject(constructor));
16925
16926 return JSRegExp::Initialize(regexp, pattern, flags);
16927}
16928
16929
16930// static
16931MaybeHandle<JSRegExp> JSRegExp::New(Handle<String> pattern,
16932 Handle<String> flags_string) {
16933 Isolate* isolate = pattern->GetIsolate();
16934 bool success = false;
16935 Flags flags = RegExpFlagsFromString(flags_string, &success);
16936 if (!success) {
16937 THROW_NEW_ERROR(
16938 isolate,
16939 NewSyntaxError(MessageTemplate::kInvalidRegExpFlags, flags_string),
16940 JSRegExp);
16941 }
16942 return New(pattern, flags);
16943}
16944
16945
16946// static
16947Handle<JSRegExp> JSRegExp::Copy(Handle<JSRegExp> regexp) {
16948 Isolate* const isolate = regexp->GetIsolate();
16949 return Handle<JSRegExp>::cast(isolate->factory()->CopyJSObject(regexp));
16950}
16951
16952
16953template <typename Char>
16954inline int CountRequiredEscapes(Handle<String> source) {
16955 DisallowHeapAllocation no_gc;
16956 int escapes = 0;
16957 Vector<const Char> src = source->GetCharVector<Char>();
16958 for (int i = 0; i < src.length(); i++) {
16959 if (src[i] == '/' && (i == 0 || src[i - 1] != '\\')) escapes++;
16960 }
16961 return escapes;
16962}
16963
16964
16965template <typename Char, typename StringType>
16966inline Handle<StringType> WriteEscapedRegExpSource(Handle<String> source,
16967 Handle<StringType> result) {
16968 DisallowHeapAllocation no_gc;
16969 Vector<const Char> src = source->GetCharVector<Char>();
16970 Vector<Char> dst(result->GetChars(), result->length());
16971 int s = 0;
16972 int d = 0;
16973 while (s < src.length()) {
16974 if (src[s] == '/' && (s == 0 || src[s - 1] != '\\')) dst[d++] = '\\';
16975 dst[d++] = src[s++];
16976 }
16977 DCHECK_EQ(result->length(), d);
16978 return result;
16979}
16980
16981
16982MaybeHandle<String> EscapeRegExpSource(Isolate* isolate,
16983 Handle<String> source) {
16984 String::Flatten(source);
16985 if (source->length() == 0) return isolate->factory()->query_colon_string();
16986 bool one_byte = source->IsOneByteRepresentationUnderneath();
16987 int escapes = one_byte ? CountRequiredEscapes<uint8_t>(source)
16988 : CountRequiredEscapes<uc16>(source);
16989 if (escapes == 0) return source;
16990 int length = source->length() + escapes;
16991 if (one_byte) {
16992 Handle<SeqOneByteString> result;
16993 ASSIGN_RETURN_ON_EXCEPTION(isolate, result,
16994 isolate->factory()->NewRawOneByteString(length),
16995 String);
16996 return WriteEscapedRegExpSource<uint8_t>(source, result);
16997 } else {
16998 Handle<SeqTwoByteString> result;
16999 ASSIGN_RETURN_ON_EXCEPTION(isolate, result,
17000 isolate->factory()->NewRawTwoByteString(length),
17001 String);
17002 return WriteEscapedRegExpSource<uc16>(source, result);
17003 }
17004}
17005
17006
17007// static
17008MaybeHandle<JSRegExp> JSRegExp::Initialize(Handle<JSRegExp> regexp,
17009 Handle<String> source,
17010 Handle<String> flags_string) {
17011 Isolate* isolate = source->GetIsolate();
17012 bool success = false;
17013 Flags flags = RegExpFlagsFromString(flags_string, &success);
17014 if (!success) {
17015 THROW_NEW_ERROR(
17016 isolate,
17017 NewSyntaxError(MessageTemplate::kInvalidRegExpFlags, flags_string),
17018 JSRegExp);
17019 }
17020 return Initialize(regexp, source, flags);
17021}
17022
17023
17024// static
17025MaybeHandle<JSRegExp> JSRegExp::Initialize(Handle<JSRegExp> regexp,
17026 Handle<String> source, Flags flags) {
17027 Isolate* isolate = regexp->GetIsolate();
17028 Factory* factory = isolate->factory();
17029 // If source is the empty string we set it to "(?:)" instead as
17030 // suggested by ECMA-262, 5th, section 15.10.4.1.
17031 if (source->length() == 0) source = factory->query_colon_string();
17032
17033 Handle<String> escaped_source;
17034 ASSIGN_RETURN_ON_EXCEPTION(isolate, escaped_source,
17035 EscapeRegExpSource(isolate, source), JSRegExp);
17036
17037 regexp->set_source(*escaped_source);
17038 regexp->set_flags(Smi::FromInt(flags));
17039
17040 Map* map = regexp->map();
17041 Object* constructor = map->GetConstructor();
17042 if (constructor->IsJSFunction() &&
17043 JSFunction::cast(constructor)->initial_map() == map) {
17044 // If we still have the original map, set in-object properties directly.
17045 regexp->InObjectPropertyAtPut(JSRegExp::kLastIndexFieldIndex,
17046 Smi::FromInt(0), SKIP_WRITE_BARRIER);
17047 } else {
17048 // Map has changed, so use generic, but slower, method.
17049 PropertyAttributes writable =
17050 static_cast<PropertyAttributes>(DONT_ENUM | DONT_DELETE);
17051 JSObject::SetOwnPropertyIgnoreAttributes(
17052 regexp, factory->last_index_string(),
17053 Handle<Smi>(Smi::FromInt(0), isolate), writable)
17054 .Check();
17055 }
17056
17057 RETURN_ON_EXCEPTION(isolate, RegExpImpl::Compile(regexp, source, flags),
17058 JSRegExp);
17059
17060 return regexp;
17061}
17062
17063
Steve Blocka7e24c12009-10-30 11:49:00 +000017064// RegExpKey carries the source and flags of a regular expression as key.
17065class RegExpKey : public HashTableKey {
17066 public:
Ben Murdochb8a8cc12014-11-26 15:28:44 +000017067 RegExpKey(Handle<String> string, JSRegExp::Flags flags)
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000017068 : string_(string), flags_(Smi::FromInt(flags)) {}
Steve Blocka7e24c12009-10-30 11:49:00 +000017069
Steve Block3ce2e202009-11-05 08:53:23 +000017070 // Rather than storing the key in the hash table, a pointer to the
17071 // stored value is stored where the key should be. IsMatch then
17072 // compares the search key to the found object, rather than comparing
17073 // a key to a key.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000017074 bool IsMatch(Object* obj) override {
Steve Blocka7e24c12009-10-30 11:49:00 +000017075 FixedArray* val = FixedArray::cast(obj);
17076 return string_->Equals(String::cast(val->get(JSRegExp::kSourceIndex)))
17077 && (flags_ == val->get(JSRegExp::kFlagsIndex));
17078 }
17079
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000017080 uint32_t Hash() override { return RegExpHash(*string_, flags_); }
Steve Blocka7e24c12009-10-30 11:49:00 +000017081
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000017082 Handle<Object> AsHandle(Isolate* isolate) override {
Steve Blocka7e24c12009-10-30 11:49:00 +000017083 // Plain hash maps, which is where regexp keys are used, don't
17084 // use this function.
17085 UNREACHABLE();
Ben Murdochb8a8cc12014-11-26 15:28:44 +000017086 return MaybeHandle<Object>().ToHandleChecked();
Steve Blocka7e24c12009-10-30 11:49:00 +000017087 }
17088
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000017089 uint32_t HashForObject(Object* obj) override {
Steve Blocka7e24c12009-10-30 11:49:00 +000017090 FixedArray* val = FixedArray::cast(obj);
17091 return RegExpHash(String::cast(val->get(JSRegExp::kSourceIndex)),
17092 Smi::cast(val->get(JSRegExp::kFlagsIndex)));
17093 }
17094
17095 static uint32_t RegExpHash(String* string, Smi* flags) {
17096 return string->Hash() + flags->value();
17097 }
17098
Ben Murdochb8a8cc12014-11-26 15:28:44 +000017099 Handle<String> string_;
Steve Blocka7e24c12009-10-30 11:49:00 +000017100 Smi* flags_;
17101};
17102
Ben Murdochb8a8cc12014-11-26 15:28:44 +000017103
17104Handle<Object> OneByteStringKey::AsHandle(Isolate* isolate) {
17105 if (hash_field_ == 0) Hash();
17106 return isolate->factory()->NewOneByteInternalizedString(string_, hash_field_);
17107}
17108
17109
17110Handle<Object> TwoByteStringKey::AsHandle(Isolate* isolate) {
17111 if (hash_field_ == 0) Hash();
17112 return isolate->factory()->NewTwoByteInternalizedString(string_, hash_field_);
17113}
17114
17115
17116Handle<Object> SeqOneByteSubStringKey::AsHandle(Isolate* isolate) {
17117 if (hash_field_ == 0) Hash();
17118 return isolate->factory()->NewOneByteInternalizedSubString(
17119 string_, from_, length_, hash_field_);
17120}
17121
17122
17123bool SeqOneByteSubStringKey::IsMatch(Object* string) {
17124 Vector<const uint8_t> chars(string_->GetChars() + from_, length_);
17125 return String::cast(string)->IsOneByteEqualTo(chars);
17126}
17127
17128
17129// InternalizedStringKey carries a string/internalized-string object as key.
17130class InternalizedStringKey : public HashTableKey {
Steve Blocka7e24c12009-10-30 11:49:00 +000017131 public:
Ben Murdochb8a8cc12014-11-26 15:28:44 +000017132 explicit InternalizedStringKey(Handle<String> string)
Steve Block44f0eee2011-05-26 01:26:41 +010017133 : string_(string) { }
Steve Blocka7e24c12009-10-30 11:49:00 +000017134
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000017135 bool IsMatch(Object* string) override {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000017136 return String::cast(string)->Equals(*string_);
Steve Blocka7e24c12009-10-30 11:49:00 +000017137 }
17138
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000017139 uint32_t Hash() override { return string_->Hash(); }
Steve Blocka7e24c12009-10-30 11:49:00 +000017140
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000017141 uint32_t HashForObject(Object* other) override {
Steve Blocka7e24c12009-10-30 11:49:00 +000017142 return String::cast(other)->Hash();
17143 }
17144
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000017145 Handle<Object> AsHandle(Isolate* isolate) override {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000017146 // Internalize the string if possible.
17147 MaybeHandle<Map> maybe_map =
17148 isolate->factory()->InternalizedStringMapForString(string_);
17149 Handle<Map> map;
17150 if (maybe_map.ToHandle(&map)) {
17151 string_->set_map_no_write_barrier(*map);
17152 DCHECK(string_->IsInternalizedString());
Steve Blocka7e24c12009-10-30 11:49:00 +000017153 return string_;
17154 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +000017155 // Otherwise allocate a new internalized string.
17156 return isolate->factory()->NewInternalizedStringImpl(
17157 string_, string_->length(), string_->hash_field());
Steve Blocka7e24c12009-10-30 11:49:00 +000017158 }
17159
17160 static uint32_t StringHash(Object* obj) {
17161 return String::cast(obj)->Hash();
17162 }
17163
Ben Murdochb8a8cc12014-11-26 15:28:44 +000017164 Handle<String> string_;
Steve Blocka7e24c12009-10-30 11:49:00 +000017165};
17166
17167
Ben Murdochb8a8cc12014-11-26 15:28:44 +000017168template<typename Derived, typename Shape, typename Key>
17169void HashTable<Derived, Shape, Key>::IteratePrefix(ObjectVisitor* v) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000017170 BodyDescriptorBase::IteratePointers(this, 0, kElementsStartOffset, v);
Steve Blocka7e24c12009-10-30 11:49:00 +000017171}
17172
17173
Ben Murdochb8a8cc12014-11-26 15:28:44 +000017174template<typename Derived, typename Shape, typename Key>
17175void HashTable<Derived, Shape, Key>::IterateElements(ObjectVisitor* v) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000017176 BodyDescriptorBase::IteratePointers(this, kElementsStartOffset,
17177 kHeaderSize + length() * kPointerSize, v);
Steve Blocka7e24c12009-10-30 11:49:00 +000017178}
17179
17180
Ben Murdochb8a8cc12014-11-26 15:28:44 +000017181template<typename Derived, typename Shape, typename Key>
17182Handle<Derived> HashTable<Derived, Shape, Key>::New(
17183 Isolate* isolate,
17184 int at_least_space_for,
17185 MinimumCapacity capacity_option,
17186 PretenureFlag pretenure) {
17187 DCHECK(0 <= at_least_space_for);
17188 DCHECK(!capacity_option || base::bits::IsPowerOfTwo32(at_least_space_for));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000017189
Ben Murdochb8a8cc12014-11-26 15:28:44 +000017190 int capacity = (capacity_option == USE_CUSTOM_MINIMUM_CAPACITY)
17191 ? at_least_space_for
17192 : ComputeCapacity(at_least_space_for);
Ben Murdoch69a99ed2011-11-30 16:03:39 +000017193 if (capacity > HashTable::kMaxCapacity) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000017194 v8::internal::Heap::FatalProcessOutOfMemory("invalid table size", true);
Leon Clarkee46be812010-01-19 14:06:41 +000017195 }
17196
Ben Murdochb8a8cc12014-11-26 15:28:44 +000017197 Factory* factory = isolate->factory();
17198 int length = EntryToIndex(capacity);
17199 Handle<FixedArray> array = factory->NewFixedArray(length, pretenure);
17200 array->set_map_no_write_barrier(*factory->hash_table_map());
17201 Handle<Derived> table = Handle<Derived>::cast(array);
17202
17203 table->SetNumberOfElements(0);
17204 table->SetNumberOfDeletedElements(0);
17205 table->SetCapacity(capacity);
17206 return table;
Steve Blocka7e24c12009-10-30 11:49:00 +000017207}
17208
17209
Leon Clarkee46be812010-01-19 14:06:41 +000017210// Find entry for key otherwise return kNotFound.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000017211template <typename Derived, typename Shape>
17212int NameDictionaryBase<Derived, Shape>::FindEntry(Handle<Name> key) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000017213 if (!key->IsUniqueName()) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000017214 return DerivedDictionary::FindEntry(key);
Ben Murdoch3bec4d22010-07-22 14:51:16 +010017215 }
17216
Ben Murdochb8a8cc12014-11-26 15:28:44 +000017217 // Optimized for unique names. Knowledge of the key type allows:
17218 // 1. Move the check if the key is unique out of the loop.
17219 // 2. Avoid comparing hash codes in unique-to-unique comparison.
17220 // 3. Detect a case when a dictionary key is not unique but the key is.
17221 // In case of positive result the dictionary key may be replaced by the
17222 // internalized string with minimal performance penalty. It gives a chance
17223 // to perform further lookups in code stubs (and significant performance
17224 // boost a certain style of code).
Ben Murdoch3bec4d22010-07-22 14:51:16 +010017225
17226 // EnsureCapacity will guarantee the hash table is never full.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000017227 uint32_t capacity = this->Capacity();
17228 uint32_t entry = Derived::FirstProbe(key->Hash(), capacity);
Ben Murdoch3bec4d22010-07-22 14:51:16 +010017229 uint32_t count = 1;
17230
17231 while (true) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000017232 int index = Derived::EntryToIndex(entry);
17233 Object* element = this->get(index);
Ben Murdoch3bec4d22010-07-22 14:51:16 +010017234 if (element->IsUndefined()) break; // Empty entry.
Ben Murdochb8a8cc12014-11-26 15:28:44 +000017235 if (*key == element) return entry;
17236 if (!element->IsUniqueName() &&
Ben Murdoch3ef787d2012-04-12 10:51:47 +010017237 !element->IsTheHole() &&
Ben Murdochb8a8cc12014-11-26 15:28:44 +000017238 Name::cast(element)->Equals(*key)) {
17239 // Replace a key that is a non-internalized string by the equivalent
17240 // internalized string for faster further lookups.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000017241 this->set(index, *key);
Ben Murdoch3bec4d22010-07-22 14:51:16 +010017242 return entry;
17243 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +000017244 DCHECK(element->IsTheHole() || !Name::cast(element)->Equals(*key));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000017245 entry = Derived::NextProbe(entry, count++, capacity);
Ben Murdoch3bec4d22010-07-22 14:51:16 +010017246 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000017247 return Derived::kNotFound;
Ben Murdoch3bec4d22010-07-22 14:51:16 +010017248}
17249
17250
Ben Murdochb8a8cc12014-11-26 15:28:44 +000017251template<typename Derived, typename Shape, typename Key>
17252void HashTable<Derived, Shape, Key>::Rehash(
17253 Handle<Derived> new_table,
17254 Key key) {
17255 DCHECK(NumberOfElements() < new_table->Capacity());
Ben Murdoch3ef787d2012-04-12 10:51:47 +010017256
Ben Murdochb8a8cc12014-11-26 15:28:44 +000017257 DisallowHeapAllocation no_gc;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000017258 WriteBarrierMode mode = new_table->GetWriteBarrierMode(no_gc);
17259
17260 // Copy prefix to new array.
17261 for (int i = kPrefixStartIndex;
17262 i < kPrefixStartIndex + Shape::kPrefixSize;
17263 i++) {
17264 new_table->set(i, get(i), mode);
17265 }
17266
17267 // Rehash the elements.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000017268 int capacity = this->Capacity();
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000017269 for (int i = 0; i < capacity; i++) {
17270 uint32_t from_index = EntryToIndex(i);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000017271 Object* k = this->get(from_index);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000017272 if (IsKey(k)) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000017273 uint32_t hash = this->HashForObject(key, k);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000017274 uint32_t insertion_index =
17275 EntryToIndex(new_table->FindInsertionEntry(hash));
17276 for (int j = 0; j < Shape::kEntrySize; j++) {
17277 new_table->set(insertion_index + j, get(from_index + j), mode);
17278 }
17279 }
17280 }
17281 new_table->SetNumberOfElements(NumberOfElements());
17282 new_table->SetNumberOfDeletedElements(0);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000017283}
17284
17285
Ben Murdochb8a8cc12014-11-26 15:28:44 +000017286template<typename Derived, typename Shape, typename Key>
17287uint32_t HashTable<Derived, Shape, Key>::EntryForProbe(
17288 Key key,
17289 Object* k,
17290 int probe,
17291 uint32_t expected) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000017292 uint32_t hash = this->HashForObject(key, k);
17293 uint32_t capacity = this->Capacity();
Ben Murdochb8a8cc12014-11-26 15:28:44 +000017294 uint32_t entry = FirstProbe(hash, capacity);
17295 for (int i = 1; i < probe; i++) {
17296 if (entry == expected) return expected;
17297 entry = NextProbe(entry, i, capacity);
17298 }
17299 return entry;
17300}
17301
17302
17303template<typename Derived, typename Shape, typename Key>
17304void HashTable<Derived, Shape, Key>::Swap(uint32_t entry1,
17305 uint32_t entry2,
17306 WriteBarrierMode mode) {
17307 int index1 = EntryToIndex(entry1);
17308 int index2 = EntryToIndex(entry2);
17309 Object* temp[Shape::kEntrySize];
17310 for (int j = 0; j < Shape::kEntrySize; j++) {
17311 temp[j] = get(index1 + j);
17312 }
17313 for (int j = 0; j < Shape::kEntrySize; j++) {
17314 set(index1 + j, get(index2 + j), mode);
17315 }
17316 for (int j = 0; j < Shape::kEntrySize; j++) {
17317 set(index2 + j, temp[j], mode);
17318 }
17319}
17320
17321
17322template<typename Derived, typename Shape, typename Key>
17323void HashTable<Derived, Shape, Key>::Rehash(Key key) {
17324 DisallowHeapAllocation no_gc;
17325 WriteBarrierMode mode = GetWriteBarrierMode(no_gc);
17326 uint32_t capacity = Capacity();
17327 bool done = false;
17328 for (int probe = 1; !done; probe++) {
17329 // All elements at entries given by one of the first _probe_ probes
17330 // are placed correctly. Other elements might need to be moved.
17331 done = true;
17332 for (uint32_t current = 0; current < capacity; current++) {
17333 Object* current_key = get(EntryToIndex(current));
17334 if (IsKey(current_key)) {
17335 uint32_t target = EntryForProbe(key, current_key, probe, current);
17336 if (current == target) continue;
17337 Object* target_key = get(EntryToIndex(target));
17338 if (!IsKey(target_key) ||
17339 EntryForProbe(key, target_key, probe, target) != target) {
17340 // Put the current element into the correct position.
17341 Swap(current, target, mode);
17342 // The other element will be processed on the next iteration.
17343 current--;
17344 } else {
17345 // The place for the current element is occupied. Leave the element
17346 // for the next probe.
17347 done = false;
17348 }
17349 }
17350 }
17351 }
Ben Murdoch097c5b22016-05-18 11:27:45 +010017352 // Wipe deleted entries.
17353 Heap* heap = GetHeap();
17354 Object* the_hole = heap->the_hole_value();
17355 Object* undefined = heap->undefined_value();
17356 for (uint32_t current = 0; current < capacity; current++) {
17357 if (get(EntryToIndex(current)) == the_hole) {
17358 set(EntryToIndex(current), undefined);
17359 }
17360 }
17361 SetNumberOfDeletedElements(0);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000017362}
17363
17364
17365template<typename Derived, typename Shape, typename Key>
17366Handle<Derived> HashTable<Derived, Shape, Key>::EnsureCapacity(
17367 Handle<Derived> table,
17368 int n,
17369 Key key,
17370 PretenureFlag pretenure) {
17371 Isolate* isolate = table->GetIsolate();
17372 int capacity = table->Capacity();
17373 int nof = table->NumberOfElements() + n;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000017374
17375 if (table->HasSufficientCapacity(n)) return table;
Steve Blocka7e24c12009-10-30 11:49:00 +000017376
Steve Block6ded16b2010-05-10 14:33:55 +010017377 const int kMinCapacityForPretenure = 256;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000017378 bool should_pretenure = pretenure == TENURED ||
17379 ((capacity > kMinCapacityForPretenure) &&
17380 !isolate->heap()->InNewSpace(*table));
17381 Handle<Derived> new_table = HashTable::New(
17382 isolate,
17383 nof * 2,
17384 USE_DEFAULT_MINIMUM_CAPACITY,
17385 should_pretenure ? TENURED : NOT_TENURED);
Leon Clarke4515c472010-02-03 11:58:03 +000017386
Ben Murdochb8a8cc12014-11-26 15:28:44 +000017387 table->Rehash(new_table, key);
17388 return new_table;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000017389}
Steve Blocka7e24c12009-10-30 11:49:00 +000017390
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000017391
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000017392template <typename Derived, typename Shape, typename Key>
17393bool HashTable<Derived, Shape, Key>::HasSufficientCapacity(int n) {
17394 int capacity = Capacity();
17395 int nof = NumberOfElements() + n;
17396 int nod = NumberOfDeletedElements();
17397 // Return true if:
17398 // 50% is still free after adding n elements and
17399 // at most 50% of the free elements are deleted elements.
17400 if (nod <= (capacity - nof) >> 1) {
17401 int needed_free = nof >> 1;
17402 if (nof + needed_free <= capacity) return true;
17403 }
17404 return false;
17405}
17406
17407
Ben Murdochb8a8cc12014-11-26 15:28:44 +000017408template<typename Derived, typename Shape, typename Key>
17409Handle<Derived> HashTable<Derived, Shape, Key>::Shrink(Handle<Derived> table,
17410 Key key) {
17411 int capacity = table->Capacity();
17412 int nof = table->NumberOfElements();
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000017413
17414 // Shrink to fit the number of elements if only a quarter of the
17415 // capacity is filled with elements.
Ben Murdochb8a8cc12014-11-26 15:28:44 +000017416 if (nof > (capacity >> 2)) return table;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000017417 // Allocate a new dictionary with room for at least the current
17418 // number of elements. The allocation method will make sure that
17419 // there is extra room in the dictionary for additions. Don't go
17420 // lower than room for 16 elements.
17421 int at_least_room_for = nof;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000017422 if (at_least_room_for < 16) return table;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000017423
Ben Murdochb8a8cc12014-11-26 15:28:44 +000017424 Isolate* isolate = table->GetIsolate();
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000017425 const int kMinCapacityForPretenure = 256;
17426 bool pretenure =
17427 (at_least_room_for > kMinCapacityForPretenure) &&
Ben Murdochb8a8cc12014-11-26 15:28:44 +000017428 !isolate->heap()->InNewSpace(*table);
17429 Handle<Derived> new_table = HashTable::New(
17430 isolate,
17431 at_least_room_for,
17432 USE_DEFAULT_MINIMUM_CAPACITY,
17433 pretenure ? TENURED : NOT_TENURED);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000017434
Ben Murdochb8a8cc12014-11-26 15:28:44 +000017435 table->Rehash(new_table, key);
17436 return new_table;
Steve Blocka7e24c12009-10-30 11:49:00 +000017437}
17438
17439
Ben Murdochb8a8cc12014-11-26 15:28:44 +000017440template<typename Derived, typename Shape, typename Key>
17441uint32_t HashTable<Derived, Shape, Key>::FindInsertionEntry(uint32_t hash) {
Steve Blocka7e24c12009-10-30 11:49:00 +000017442 uint32_t capacity = Capacity();
Leon Clarkee46be812010-01-19 14:06:41 +000017443 uint32_t entry = FirstProbe(hash, capacity);
17444 uint32_t count = 1;
17445 // EnsureCapacity will guarantee the hash table is never full.
17446 while (true) {
17447 Object* element = KeyAt(entry);
Ben Murdoch3ef787d2012-04-12 10:51:47 +010017448 if (element->IsUndefined() || element->IsTheHole()) break;
Leon Clarkee46be812010-01-19 14:06:41 +000017449 entry = NextProbe(entry, count++, capacity);
Steve Blocka7e24c12009-10-30 11:49:00 +000017450 }
Steve Blocka7e24c12009-10-30 11:49:00 +000017451 return entry;
17452}
17453
Ben Murdochb8a8cc12014-11-26 15:28:44 +000017454
Steve Blocka7e24c12009-10-30 11:49:00 +000017455// Force instantiation of template instances class.
17456// Please note this list is compiler dependent.
17457
Ben Murdochb8a8cc12014-11-26 15:28:44 +000017458template class HashTable<StringTable, StringTableShape, HashTableKey*>;
Steve Blocka7e24c12009-10-30 11:49:00 +000017459
Ben Murdochb8a8cc12014-11-26 15:28:44 +000017460template class HashTable<CompilationCacheTable,
17461 CompilationCacheShape,
17462 HashTableKey*>;
Steve Blocka7e24c12009-10-30 11:49:00 +000017463
Ben Murdochb8a8cc12014-11-26 15:28:44 +000017464template class HashTable<ObjectHashTable,
17465 ObjectHashTableShape,
17466 Handle<Object> >;
Ben Murdoch3ef787d2012-04-12 10:51:47 +010017467
Ben Murdochb8a8cc12014-11-26 15:28:44 +000017468template class HashTable<WeakHashTable, WeakHashTableShape<2>, Handle<Object> >;
Ben Murdoch69a99ed2011-11-30 16:03:39 +000017469
Ben Murdochb8a8cc12014-11-26 15:28:44 +000017470template class Dictionary<NameDictionary, NameDictionaryShape, Handle<Name> >;
Steve Blocka7e24c12009-10-30 11:49:00 +000017471
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000017472template class Dictionary<GlobalDictionary, GlobalDictionaryShape,
17473 Handle<Name> >;
17474
Ben Murdochb8a8cc12014-11-26 15:28:44 +000017475template class Dictionary<SeededNumberDictionary,
17476 SeededNumberDictionaryShape,
17477 uint32_t>;
Steve Blocka7e24c12009-10-30 11:49:00 +000017478
Ben Murdochb8a8cc12014-11-26 15:28:44 +000017479template class Dictionary<UnseededNumberDictionary,
17480 UnseededNumberDictionaryShape,
17481 uint32_t>;
Ben Murdochc7cc0282012-03-05 14:35:55 +000017482
Ben Murdochb8a8cc12014-11-26 15:28:44 +000017483template Handle<SeededNumberDictionary>
17484Dictionary<SeededNumberDictionary, SeededNumberDictionaryShape, uint32_t>::
17485 New(Isolate*, int at_least_space_for, PretenureFlag pretenure);
Ben Murdochc7cc0282012-03-05 14:35:55 +000017486
Ben Murdochb8a8cc12014-11-26 15:28:44 +000017487template Handle<UnseededNumberDictionary>
17488Dictionary<UnseededNumberDictionary, UnseededNumberDictionaryShape, uint32_t>::
17489 New(Isolate*, int at_least_space_for, PretenureFlag pretenure);
Steve Blocka7e24c12009-10-30 11:49:00 +000017490
Ben Murdochb8a8cc12014-11-26 15:28:44 +000017491template Handle<NameDictionary>
17492Dictionary<NameDictionary, NameDictionaryShape, Handle<Name> >::
17493 New(Isolate*, int n, PretenureFlag pretenure);
Steve Blocka7e24c12009-10-30 11:49:00 +000017494
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000017495template Handle<GlobalDictionary>
17496Dictionary<GlobalDictionary, GlobalDictionaryShape, Handle<Name> >::New(
17497 Isolate*, int n, PretenureFlag pretenure);
17498
Ben Murdochb8a8cc12014-11-26 15:28:44 +000017499template Handle<SeededNumberDictionary>
17500Dictionary<SeededNumberDictionary, SeededNumberDictionaryShape, uint32_t>::
17501 AtPut(Handle<SeededNumberDictionary>, uint32_t, Handle<Object>);
Steve Blocka7e24c12009-10-30 11:49:00 +000017502
Ben Murdochb8a8cc12014-11-26 15:28:44 +000017503template Handle<UnseededNumberDictionary>
17504Dictionary<UnseededNumberDictionary, UnseededNumberDictionaryShape, uint32_t>::
17505 AtPut(Handle<UnseededNumberDictionary>, uint32_t, Handle<Object>);
Ben Murdochc7cc0282012-03-05 14:35:55 +000017506
Ben Murdochb8a8cc12014-11-26 15:28:44 +000017507template Object*
17508Dictionary<SeededNumberDictionary, SeededNumberDictionaryShape, uint32_t>::
Ben Murdoch3ef787d2012-04-12 10:51:47 +010017509 SlowReverseLookup(Object* value);
17510
Ben Murdochb8a8cc12014-11-26 15:28:44 +000017511template Object*
17512Dictionary<NameDictionary, NameDictionaryShape, Handle<Name> >::
Ben Murdochc7cc0282012-03-05 14:35:55 +000017513 SlowReverseLookup(Object* value);
Steve Blocka7e24c12009-10-30 11:49:00 +000017514
Ben Murdochb8a8cc12014-11-26 15:28:44 +000017515template Handle<Object>
17516Dictionary<NameDictionary, NameDictionaryShape, Handle<Name> >::DeleteProperty(
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000017517 Handle<NameDictionary>, int);
Steve Blocka7e24c12009-10-30 11:49:00 +000017518
Ben Murdochb8a8cc12014-11-26 15:28:44 +000017519template Handle<Object>
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000017520Dictionary<SeededNumberDictionary, SeededNumberDictionaryShape,
17521 uint32_t>::DeleteProperty(Handle<SeededNumberDictionary>, int);
Steve Blocka7e24c12009-10-30 11:49:00 +000017522
Ben Murdochb8a8cc12014-11-26 15:28:44 +000017523template Handle<NameDictionary>
17524HashTable<NameDictionary, NameDictionaryShape, Handle<Name> >::
17525 New(Isolate*, int, MinimumCapacity, PretenureFlag);
Steve Blocka7e24c12009-10-30 11:49:00 +000017526
Ben Murdochb8a8cc12014-11-26 15:28:44 +000017527template Handle<NameDictionary>
17528HashTable<NameDictionary, NameDictionaryShape, Handle<Name> >::
17529 Shrink(Handle<NameDictionary>, Handle<Name>);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000017530
Ben Murdochb8a8cc12014-11-26 15:28:44 +000017531template Handle<SeededNumberDictionary>
17532HashTable<SeededNumberDictionary, SeededNumberDictionaryShape, uint32_t>::
17533 Shrink(Handle<SeededNumberDictionary>, uint32_t);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000017534
Ben Murdochb8a8cc12014-11-26 15:28:44 +000017535template Handle<NameDictionary>
17536Dictionary<NameDictionary, NameDictionaryShape, Handle<Name> >::Add(
17537 Handle<NameDictionary>, Handle<Name>, Handle<Object>, PropertyDetails);
Steve Blocka7e24c12009-10-30 11:49:00 +000017538
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000017539template Handle<GlobalDictionary>
17540 Dictionary<GlobalDictionary, GlobalDictionaryShape, Handle<Name> >::Add(
17541 Handle<GlobalDictionary>, Handle<Name>, Handle<Object>,
17542 PropertyDetails);
17543
Emily Bernierd0a1eb72015-03-24 16:35:39 -040017544template Handle<FixedArray> Dictionary<
17545 NameDictionary, NameDictionaryShape,
17546 Handle<Name> >::BuildIterationIndicesArray(Handle<NameDictionary>);
17547
17548template Handle<FixedArray> Dictionary<
17549 NameDictionary, NameDictionaryShape,
17550 Handle<Name> >::GenerateNewEnumerationIndices(Handle<NameDictionary>);
Ben Murdochc7cc0282012-03-05 14:35:55 +000017551
Ben Murdochb8a8cc12014-11-26 15:28:44 +000017552template Handle<SeededNumberDictionary>
17553Dictionary<SeededNumberDictionary, SeededNumberDictionaryShape, uint32_t>::
17554 Add(Handle<SeededNumberDictionary>,
17555 uint32_t,
17556 Handle<Object>,
17557 PropertyDetails);
Steve Blocka7e24c12009-10-30 11:49:00 +000017558
Ben Murdochb8a8cc12014-11-26 15:28:44 +000017559template Handle<UnseededNumberDictionary>
17560Dictionary<UnseededNumberDictionary, UnseededNumberDictionaryShape, uint32_t>::
17561 Add(Handle<UnseededNumberDictionary>,
17562 uint32_t,
17563 Handle<Object>,
17564 PropertyDetails);
Steve Blocka7e24c12009-10-30 11:49:00 +000017565
Ben Murdochb8a8cc12014-11-26 15:28:44 +000017566template Handle<SeededNumberDictionary>
17567Dictionary<SeededNumberDictionary, SeededNumberDictionaryShape, uint32_t>::
17568 EnsureCapacity(Handle<SeededNumberDictionary>, int, uint32_t);
Ben Murdochc7cc0282012-03-05 14:35:55 +000017569
Ben Murdochb8a8cc12014-11-26 15:28:44 +000017570template Handle<UnseededNumberDictionary>
17571Dictionary<UnseededNumberDictionary, UnseededNumberDictionaryShape, uint32_t>::
17572 EnsureCapacity(Handle<UnseededNumberDictionary>, int, uint32_t);
Steve Blocka7e24c12009-10-30 11:49:00 +000017573
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000017574template void Dictionary<NameDictionary, NameDictionaryShape,
17575 Handle<Name> >::SetRequiresCopyOnCapacityChange();
17576
Ben Murdochb8a8cc12014-11-26 15:28:44 +000017577template Handle<NameDictionary>
17578Dictionary<NameDictionary, NameDictionaryShape, Handle<Name> >::
17579 EnsureCapacity(Handle<NameDictionary>, int, Handle<Name>);
Steve Blocka7e24c12009-10-30 11:49:00 +000017580
Emily Bernierd0a1eb72015-03-24 16:35:39 -040017581template bool Dictionary<SeededNumberDictionary, SeededNumberDictionaryShape,
17582 uint32_t>::HasComplexElements();
17583
17584template int HashTable<SeededNumberDictionary, SeededNumberDictionaryShape,
17585 uint32_t>::FindEntry(uint32_t);
Leon Clarkee46be812010-01-19 14:06:41 +000017586
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000017587template int NameDictionaryBase<NameDictionary, NameDictionaryShape>::FindEntry(
17588 Handle<Name>);
17589
Leon Clarkee46be812010-01-19 14:06:41 +000017590
Ben Murdochb8a8cc12014-11-26 15:28:44 +000017591Handle<Object> JSObject::PrepareSlowElementsForSort(
17592 Handle<JSObject> object, uint32_t limit) {
17593 DCHECK(object->HasDictionaryElements());
17594 Isolate* isolate = object->GetIsolate();
Steve Blocka7e24c12009-10-30 11:49:00 +000017595 // Must stay in dictionary mode, either because of requires_slow_elements,
17596 // or because we are not going to sort (and therefore compact) all of the
17597 // elements.
Ben Murdochb8a8cc12014-11-26 15:28:44 +000017598 Handle<SeededNumberDictionary> dict(object->element_dictionary(), isolate);
17599 Handle<SeededNumberDictionary> new_dict =
17600 SeededNumberDictionary::New(isolate, dict->NumberOfElements());
Steve Blocka7e24c12009-10-30 11:49:00 +000017601
17602 uint32_t pos = 0;
17603 uint32_t undefs = 0;
Steve Block6ded16b2010-05-10 14:33:55 +010017604 int capacity = dict->Capacity();
Ben Murdochb8a8cc12014-11-26 15:28:44 +000017605 Handle<Smi> bailout(Smi::FromInt(-1), isolate);
17606 // Entry to the new dictionary does not cause it to grow, as we have
17607 // allocated one that is large enough for all entries.
17608 DisallowHeapAllocation no_gc;
Steve Blocka7e24c12009-10-30 11:49:00 +000017609 for (int i = 0; i < capacity; i++) {
17610 Object* k = dict->KeyAt(i);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000017611 if (!dict->IsKey(k)) continue;
17612
17613 DCHECK(k->IsNumber());
17614 DCHECK(!k->IsSmi() || Smi::cast(k)->value() >= 0);
17615 DCHECK(!k->IsHeapNumber() || HeapNumber::cast(k)->value() >= 0);
17616 DCHECK(!k->IsHeapNumber() || HeapNumber::cast(k)->value() <= kMaxUInt32);
17617
17618 HandleScope scope(isolate);
17619 Handle<Object> value(dict->ValueAt(i), isolate);
17620 PropertyDetails details = dict->DetailsAt(i);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000017621 if (details.type() == ACCESSOR_CONSTANT || details.IsReadOnly()) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000017622 // Bail out and do the sorting of undefineds and array holes in JS.
17623 // Also bail out if the element is not supposed to be moved.
17624 return bailout;
17625 }
17626
17627 uint32_t key = NumberToUint32(k);
17628 if (key < limit) {
17629 if (value->IsUndefined()) {
17630 undefs++;
17631 } else if (pos > static_cast<uint32_t>(Smi::kMaxValue)) {
17632 // Adding an entry with the key beyond smi-range requires
17633 // allocation. Bailout.
17634 return bailout;
Steve Blocka7e24c12009-10-30 11:49:00 +000017635 } else {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000017636 Handle<Object> result = SeededNumberDictionary::AddNumberEntry(
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000017637 new_dict, pos, value, details, object->map()->is_prototype_map());
Ben Murdochb8a8cc12014-11-26 15:28:44 +000017638 DCHECK(result.is_identical_to(new_dict));
17639 USE(result);
17640 pos++;
Steve Blocka7e24c12009-10-30 11:49:00 +000017641 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +000017642 } else if (key > static_cast<uint32_t>(Smi::kMaxValue)) {
17643 // Adding an entry with the key beyond smi-range requires
17644 // allocation. Bailout.
17645 return bailout;
17646 } else {
17647 Handle<Object> result = SeededNumberDictionary::AddNumberEntry(
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000017648 new_dict, key, value, details, object->map()->is_prototype_map());
Ben Murdochb8a8cc12014-11-26 15:28:44 +000017649 DCHECK(result.is_identical_to(new_dict));
17650 USE(result);
Steve Blocka7e24c12009-10-30 11:49:00 +000017651 }
17652 }
17653
17654 uint32_t result = pos;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000017655 PropertyDetails no_details = PropertyDetails::Empty();
Steve Blocka7e24c12009-10-30 11:49:00 +000017656 while (undefs > 0) {
Steve Block1e0659c2011-05-24 12:43:12 +010017657 if (pos > static_cast<uint32_t>(Smi::kMaxValue)) {
17658 // Adding an entry with the key beyond smi-range requires
17659 // allocation. Bailout.
Ben Murdochb8a8cc12014-11-26 15:28:44 +000017660 return bailout;
Steve Block1e0659c2011-05-24 12:43:12 +010017661 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +000017662 HandleScope scope(isolate);
17663 Handle<Object> result = SeededNumberDictionary::AddNumberEntry(
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000017664 new_dict, pos, isolate->factory()->undefined_value(), no_details,
17665 object->map()->is_prototype_map());
Ben Murdochb8a8cc12014-11-26 15:28:44 +000017666 DCHECK(result.is_identical_to(new_dict));
17667 USE(result);
Steve Blocka7e24c12009-10-30 11:49:00 +000017668 pos++;
17669 undefs--;
17670 }
17671
Ben Murdochb8a8cc12014-11-26 15:28:44 +000017672 object->set_elements(*new_dict);
Steve Blocka7e24c12009-10-30 11:49:00 +000017673
Ben Murdochb8a8cc12014-11-26 15:28:44 +000017674 AllowHeapAllocation allocate_return_value;
17675 return isolate->factory()->NewNumberFromUint(result);
Steve Blocka7e24c12009-10-30 11:49:00 +000017676}
17677
17678
17679// Collects all defined (non-hole) and non-undefined (array) elements at
17680// the start of the elements array.
17681// If the object is in dictionary mode, it is converted to fast elements
17682// mode.
Ben Murdochb8a8cc12014-11-26 15:28:44 +000017683Handle<Object> JSObject::PrepareElementsForSort(Handle<JSObject> object,
17684 uint32_t limit) {
17685 Isolate* isolate = object->GetIsolate();
17686 if (object->HasSloppyArgumentsElements() ||
17687 object->map()->is_observed()) {
17688 return handle(Smi::FromInt(-1), isolate);
17689 }
Ben Murdoch8b112d22011-06-08 16:22:53 +010017690
Ben Murdoch097c5b22016-05-18 11:27:45 +010017691 if (object->HasStringWrapperElements()) {
17692 int len = String::cast(Handle<JSValue>::cast(object)->value())->length();
17693 return handle(Smi::FromInt(len), isolate);
17694 }
17695
Ben Murdochb8a8cc12014-11-26 15:28:44 +000017696 if (object->HasDictionaryElements()) {
Steve Blocka7e24c12009-10-30 11:49:00 +000017697 // Convert to fast elements containing only the existing properties.
17698 // Ordering is irrelevant, since we are going to sort anyway.
Ben Murdochb8a8cc12014-11-26 15:28:44 +000017699 Handle<SeededNumberDictionary> dict(object->element_dictionary());
17700 if (object->IsJSArray() || dict->requires_slow_elements() ||
Steve Blocka7e24c12009-10-30 11:49:00 +000017701 dict->max_number_key() >= limit) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000017702 return JSObject::PrepareSlowElementsForSort(object, limit);
Steve Blocka7e24c12009-10-30 11:49:00 +000017703 }
17704 // Convert to fast elements.
17705
Ben Murdochb8a8cc12014-11-26 15:28:44 +000017706 Handle<Map> new_map =
17707 JSObject::GetElementsTransitionMap(object, FAST_HOLEY_ELEMENTS);
Steve Block8defd9f2010-07-08 12:39:36 +010017708
Ben Murdochb8a8cc12014-11-26 15:28:44 +000017709 PretenureFlag tenure = isolate->heap()->InNewSpace(*object) ?
17710 NOT_TENURED: TENURED;
17711 Handle<FixedArray> fast_elements =
17712 isolate->factory()->NewFixedArray(dict->NumberOfElements(), tenure);
17713 dict->CopyValuesTo(*fast_elements);
17714 JSObject::ValidateElements(object);
Steve Block8defd9f2010-07-08 12:39:36 +010017715
Ben Murdochb8a8cc12014-11-26 15:28:44 +000017716 JSObject::SetMapAndElements(object, new_map, fast_elements);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000017717 } else if (object->HasFixedTypedArrayElements()) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000017718 // Typed arrays cannot have holes or undefined elements.
17719 return handle(Smi::FromInt(
17720 FixedArrayBase::cast(object->elements())->length()), isolate);
17721 } else if (!object->HasFastDoubleElements()) {
17722 EnsureWritableFastElements(object);
Steve Blocka7e24c12009-10-30 11:49:00 +000017723 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +000017724 DCHECK(object->HasFastSmiOrObjectElements() ||
17725 object->HasFastDoubleElements());
Steve Blocka7e24c12009-10-30 11:49:00 +000017726
17727 // Collect holes at the end, undefined before that and the rest at the
17728 // start, and return the number of non-hole, non-undefined values.
17729
Ben Murdochb8a8cc12014-11-26 15:28:44 +000017730 Handle<FixedArrayBase> elements_base(object->elements());
Ben Murdoch69a99ed2011-11-30 16:03:39 +000017731 uint32_t elements_length = static_cast<uint32_t>(elements_base->length());
Steve Blocka7e24c12009-10-30 11:49:00 +000017732 if (limit > elements_length) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000017733 limit = elements_length;
Steve Blocka7e24c12009-10-30 11:49:00 +000017734 }
17735 if (limit == 0) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000017736 return handle(Smi::FromInt(0), isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +000017737 }
17738
Ben Murdoch69a99ed2011-11-30 16:03:39 +000017739 uint32_t result = 0;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000017740 if (elements_base->map() == isolate->heap()->fixed_double_array_map()) {
17741 FixedDoubleArray* elements = FixedDoubleArray::cast(*elements_base);
Ben Murdoch69a99ed2011-11-30 16:03:39 +000017742 // Split elements into defined and the_hole, in that order.
17743 unsigned int holes = limit;
17744 // Assume most arrays contain no holes and undefined values, so minimize the
17745 // number of stores of non-undefined, non-the-hole values.
17746 for (unsigned int i = 0; i < holes; i++) {
17747 if (elements->is_the_hole(i)) {
17748 holes--;
17749 } else {
17750 continue;
17751 }
17752 // Position i needs to be filled.
17753 while (holes > i) {
17754 if (elements->is_the_hole(holes)) {
17755 holes--;
17756 } else {
17757 elements->set(i, elements->get_scalar(holes));
17758 break;
17759 }
17760 }
Steve Blocka7e24c12009-10-30 11:49:00 +000017761 }
Ben Murdoch69a99ed2011-11-30 16:03:39 +000017762 result = holes;
17763 while (holes < limit) {
17764 elements->set_the_hole(holes);
17765 holes++;
17766 }
17767 } else {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000017768 FixedArray* elements = FixedArray::cast(*elements_base);
17769 DisallowHeapAllocation no_gc;
Ben Murdoch69a99ed2011-11-30 16:03:39 +000017770
17771 // Split elements into defined, undefined and the_hole, in that order. Only
17772 // count locations for undefined and the hole, and fill them afterwards.
Ben Murdochb8a8cc12014-11-26 15:28:44 +000017773 WriteBarrierMode write_barrier = elements->GetWriteBarrierMode(no_gc);
Ben Murdoch69a99ed2011-11-30 16:03:39 +000017774 unsigned int undefs = limit;
17775 unsigned int holes = limit;
17776 // Assume most arrays contain no holes and undefined values, so minimize the
17777 // number of stores of non-undefined, non-the-hole values.
17778 for (unsigned int i = 0; i < undefs; i++) {
17779 Object* current = elements->get(i);
Steve Blocka7e24c12009-10-30 11:49:00 +000017780 if (current->IsTheHole()) {
17781 holes--;
17782 undefs--;
17783 } else if (current->IsUndefined()) {
17784 undefs--;
17785 } else {
Ben Murdoch69a99ed2011-11-30 16:03:39 +000017786 continue;
17787 }
17788 // Position i needs to be filled.
17789 while (undefs > i) {
17790 current = elements->get(undefs);
17791 if (current->IsTheHole()) {
17792 holes--;
17793 undefs--;
17794 } else if (current->IsUndefined()) {
17795 undefs--;
17796 } else {
17797 elements->set(i, current, write_barrier);
17798 break;
17799 }
Steve Blocka7e24c12009-10-30 11:49:00 +000017800 }
17801 }
Ben Murdoch69a99ed2011-11-30 16:03:39 +000017802 result = undefs;
17803 while (undefs < holes) {
17804 elements->set_undefined(undefs);
17805 undefs++;
17806 }
17807 while (holes < limit) {
17808 elements->set_the_hole(holes);
17809 holes++;
17810 }
Steve Blocka7e24c12009-10-30 11:49:00 +000017811 }
17812
Ben Murdochb8a8cc12014-11-26 15:28:44 +000017813 return isolate->factory()->NewNumberFromUint(result);
Steve Blocka7e24c12009-10-30 11:49:00 +000017814}
17815
17816
Ben Murdochb8a8cc12014-11-26 15:28:44 +000017817ExternalArrayType JSTypedArray::type() {
17818 switch (elements()->map()->instance_type()) {
17819#define INSTANCE_TYPE_TO_ARRAY_TYPE(Type, type, TYPE, ctype, size) \
Ben Murdochb8a8cc12014-11-26 15:28:44 +000017820 case FIXED_##TYPE##_ARRAY_TYPE: \
17821 return kExternal##Type##Array;
17822
17823 TYPED_ARRAYS(INSTANCE_TYPE_TO_ARRAY_TYPE)
17824#undef INSTANCE_TYPE_TO_ARRAY_TYPE
17825
17826 default:
17827 UNREACHABLE();
17828 return static_cast<ExternalArrayType>(-1);
17829 }
17830}
17831
17832
17833size_t JSTypedArray::element_size() {
17834 switch (elements()->map()->instance_type()) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000017835#define INSTANCE_TYPE_TO_ELEMENT_SIZE(Type, type, TYPE, ctype, size) \
17836 case FIXED_##TYPE##_ARRAY_TYPE: \
17837 return size;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000017838
17839 TYPED_ARRAYS(INSTANCE_TYPE_TO_ELEMENT_SIZE)
17840#undef INSTANCE_TYPE_TO_ELEMENT_SIZE
17841
17842 default:
17843 UNREACHABLE();
17844 return 0;
17845 }
17846}
17847
17848
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000017849void JSGlobalObject::InvalidatePropertyCell(Handle<JSGlobalObject> global,
17850 Handle<Name> name) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -040017851 DCHECK(!global->HasFastProperties());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000017852 auto dictionary = handle(global->global_dictionary());
17853 int entry = dictionary->FindEntry(name);
17854 if (entry == GlobalDictionary::kNotFound) return;
17855 PropertyCell::InvalidateEntry(dictionary, entry);
Emily Bernierd0a1eb72015-03-24 16:35:39 -040017856}
17857
17858
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000017859// TODO(ishell): rename to EnsureEmptyPropertyCell or something.
Ben Murdochb8a8cc12014-11-26 15:28:44 +000017860Handle<PropertyCell> JSGlobalObject::EnsurePropertyCell(
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000017861 Handle<JSGlobalObject> global, Handle<Name> name) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000017862 DCHECK(!global->HasFastProperties());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000017863 auto dictionary = handle(global->global_dictionary());
17864 int entry = dictionary->FindEntry(name);
17865 Handle<PropertyCell> cell;
17866 if (entry != GlobalDictionary::kNotFound) {
17867 // This call should be idempotent.
17868 DCHECK(dictionary->ValueAt(entry)->IsPropertyCell());
17869 cell = handle(PropertyCell::cast(dictionary->ValueAt(entry)));
17870 DCHECK(cell->property_details().cell_type() ==
17871 PropertyCellType::kUninitialized ||
17872 cell->property_details().cell_type() ==
17873 PropertyCellType::kInvalidated);
17874 DCHECK(cell->value()->IsTheHole());
Steve Blocka7e24c12009-10-30 11:49:00 +000017875 return cell;
Steve Blocka7e24c12009-10-30 11:49:00 +000017876 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000017877 Isolate* isolate = global->GetIsolate();
17878 cell = isolate->factory()->NewPropertyCell();
17879 PropertyDetails details(NONE, DATA, 0, PropertyCellType::kUninitialized);
17880 dictionary = GlobalDictionary::Add(dictionary, name, cell, details);
17881 global->set_properties(*dictionary);
17882 return cell;
Steve Blocka7e24c12009-10-30 11:49:00 +000017883}
17884
17885
Ben Murdochb8a8cc12014-11-26 15:28:44 +000017886// This class is used for looking up two character strings in the string table.
Steve Blockd0582a62009-12-15 09:54:21 +000017887// If we don't have a hit we don't want to waste much time so we unroll the
17888// string hash calculation loop here for speed. Doesn't work if the two
17889// characters form a decimal integer, since such strings have a different hash
17890// algorithm.
17891class TwoCharHashTableKey : public HashTableKey {
17892 public:
Ben Murdochb8a8cc12014-11-26 15:28:44 +000017893 TwoCharHashTableKey(uint16_t c1, uint16_t c2, uint32_t seed)
Steve Blockd0582a62009-12-15 09:54:21 +000017894 : c1_(c1), c2_(c2) {
17895 // Char 1.
Ben Murdochc7cc0282012-03-05 14:35:55 +000017896 uint32_t hash = seed;
17897 hash += c1;
17898 hash += hash << 10;
Steve Blockd0582a62009-12-15 09:54:21 +000017899 hash ^= hash >> 6;
17900 // Char 2.
17901 hash += c2;
17902 hash += hash << 10;
17903 hash ^= hash >> 6;
17904 // GetHash.
17905 hash += hash << 3;
17906 hash ^= hash >> 11;
17907 hash += hash << 15;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000017908 if ((hash & String::kHashBitMask) == 0) hash = StringHasher::kZeroHash;
17909 hash_ = hash;
Steve Blockd0582a62009-12-15 09:54:21 +000017910#ifdef DEBUG
Steve Blockd0582a62009-12-15 09:54:21 +000017911 // If this assert fails then we failed to reproduce the two-character
17912 // version of the string hashing algorithm above. One reason could be
17913 // that we were passed two digits as characters, since the hash
17914 // algorithm is different in that case.
Ben Murdochb8a8cc12014-11-26 15:28:44 +000017915 uint16_t chars[2] = {c1, c2};
17916 uint32_t check_hash = StringHasher::HashSequentialString(chars, 2, seed);
17917 hash = (hash << String::kHashShift) | String::kIsNotArrayIndexMask;
17918 DCHECK_EQ(static_cast<int32_t>(hash), static_cast<int32_t>(check_hash));
Steve Blockd0582a62009-12-15 09:54:21 +000017919#endif
Steve Blockd0582a62009-12-15 09:54:21 +000017920 }
17921
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000017922 bool IsMatch(Object* o) override {
Steve Blockd0582a62009-12-15 09:54:21 +000017923 if (!o->IsString()) return false;
17924 String* other = String::cast(o);
17925 if (other->length() != 2) return false;
17926 if (other->Get(0) != c1_) return false;
17927 return other->Get(1) == c2_;
17928 }
17929
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000017930 uint32_t Hash() override { return hash_; }
17931 uint32_t HashForObject(Object* key) override {
Steve Blockd0582a62009-12-15 09:54:21 +000017932 if (!key->IsString()) return 0;
17933 return String::cast(key)->Hash();
17934 }
17935
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000017936 Handle<Object> AsHandle(Isolate* isolate) override {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000017937 // The TwoCharHashTableKey is only used for looking in the string
Steve Blockd0582a62009-12-15 09:54:21 +000017938 // table, not for adding to it.
17939 UNREACHABLE();
Ben Murdochb8a8cc12014-11-26 15:28:44 +000017940 return MaybeHandle<Object>().ToHandleChecked();
Steve Blockd0582a62009-12-15 09:54:21 +000017941 }
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000017942
Steve Blockd0582a62009-12-15 09:54:21 +000017943 private:
Ben Murdochb8a8cc12014-11-26 15:28:44 +000017944 uint16_t c1_;
17945 uint16_t c2_;
Steve Blockd0582a62009-12-15 09:54:21 +000017946 uint32_t hash_;
17947};
17948
17949
Ben Murdochb8a8cc12014-11-26 15:28:44 +000017950MaybeHandle<String> StringTable::InternalizeStringIfExists(
17951 Isolate* isolate,
17952 Handle<String> string) {
17953 if (string->IsInternalizedString()) {
17954 return string;
17955 }
17956 return LookupStringIfExists(isolate, string);
17957}
17958
17959
17960MaybeHandle<String> StringTable::LookupStringIfExists(
17961 Isolate* isolate,
17962 Handle<String> string) {
17963 Handle<StringTable> string_table = isolate->factory()->string_table();
17964 InternalizedStringKey key(string);
17965 int entry = string_table->FindEntry(&key);
Steve Blocka7e24c12009-10-30 11:49:00 +000017966 if (entry == kNotFound) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000017967 return MaybeHandle<String>();
Steve Blocka7e24c12009-10-30 11:49:00 +000017968 } else {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000017969 Handle<String> result(String::cast(string_table->KeyAt(entry)), isolate);
17970 DCHECK(StringShape(*result).IsInternalized());
17971 return result;
Steve Blocka7e24c12009-10-30 11:49:00 +000017972 }
17973}
17974
17975
Ben Murdochb8a8cc12014-11-26 15:28:44 +000017976MaybeHandle<String> StringTable::LookupTwoCharsStringIfExists(
17977 Isolate* isolate,
17978 uint16_t c1,
17979 uint16_t c2) {
17980 Handle<StringTable> string_table = isolate->factory()->string_table();
17981 TwoCharHashTableKey key(c1, c2, isolate->heap()->HashSeed());
17982 int entry = string_table->FindEntry(&key);
Steve Blockd0582a62009-12-15 09:54:21 +000017983 if (entry == kNotFound) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000017984 return MaybeHandle<String>();
Steve Blockd0582a62009-12-15 09:54:21 +000017985 } else {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000017986 Handle<String> result(String::cast(string_table->KeyAt(entry)), isolate);
17987 DCHECK(StringShape(*result).IsInternalized());
17988 return result;
Steve Blockd0582a62009-12-15 09:54:21 +000017989 }
17990}
17991
17992
Emily Bernierd0a1eb72015-03-24 16:35:39 -040017993void StringTable::EnsureCapacityForDeserialization(Isolate* isolate,
17994 int expected) {
17995 Handle<StringTable> table = isolate->factory()->string_table();
17996 // We need a key instance for the virtual hash function.
17997 InternalizedStringKey dummy_key(Handle<String>::null());
17998 table = StringTable::EnsureCapacity(table, expected, &dummy_key);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000017999 isolate->heap()->SetRootStringTable(*table);
Emily Bernierd0a1eb72015-03-24 16:35:39 -040018000}
18001
18002
Ben Murdochb8a8cc12014-11-26 15:28:44 +000018003Handle<String> StringTable::LookupString(Isolate* isolate,
18004 Handle<String> string) {
18005 InternalizedStringKey key(string);
18006 return LookupKey(isolate, &key);
Steve Blocka7e24c12009-10-30 11:49:00 +000018007}
18008
18009
Ben Murdochb8a8cc12014-11-26 15:28:44 +000018010Handle<String> StringTable::LookupKey(Isolate* isolate, HashTableKey* key) {
18011 Handle<StringTable> table = isolate->factory()->string_table();
18012 int entry = table->FindEntry(key);
Steve Block9fac8402011-05-12 15:51:54 +010018013
Ben Murdochb8a8cc12014-11-26 15:28:44 +000018014 // String already in table.
Steve Blocka7e24c12009-10-30 11:49:00 +000018015 if (entry != kNotFound) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000018016 return handle(String::cast(table->KeyAt(entry)), isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +000018017 }
18018
Ben Murdochb8a8cc12014-11-26 15:28:44 +000018019 // Adding new string. Grow table if needed.
18020 table = StringTable::EnsureCapacity(table, 1, key);
Steve Blocka7e24c12009-10-30 11:49:00 +000018021
Ben Murdochb8a8cc12014-11-26 15:28:44 +000018022 // Create string object.
18023 Handle<Object> string = key->AsHandle(isolate);
18024 // There must be no attempts to internalize strings that could throw
18025 // InvalidStringLength error.
18026 CHECK(!string.is_null());
Steve Blocka7e24c12009-10-30 11:49:00 +000018027
Ben Murdochb8a8cc12014-11-26 15:28:44 +000018028 // Add the new string and return it along with the string table.
Steve Blocka7e24c12009-10-30 11:49:00 +000018029 entry = table->FindInsertionEntry(key->Hash());
Ben Murdochb8a8cc12014-11-26 15:28:44 +000018030 table->set(EntryToIndex(entry), *string);
Steve Blocka7e24c12009-10-30 11:49:00 +000018031 table->ElementAdded();
Ben Murdochb8a8cc12014-11-26 15:28:44 +000018032
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000018033 isolate->heap()->SetRootStringTable(*table);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000018034 return Handle<String>::cast(string);
Steve Blocka7e24c12009-10-30 11:49:00 +000018035}
18036
18037
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000018038String* StringTable::LookupKeyIfExists(Isolate* isolate, HashTableKey* key) {
18039 Handle<StringTable> table = isolate->factory()->string_table();
18040 int entry = table->FindEntry(key);
18041 if (entry != kNotFound) return String::cast(table->KeyAt(entry));
18042 return NULL;
18043}
18044
18045
Ben Murdochb8a8cc12014-11-26 15:28:44 +000018046Handle<Object> CompilationCacheTable::Lookup(Handle<String> src,
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000018047 Handle<Context> context,
18048 LanguageMode language_mode) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000018049 Isolate* isolate = GetIsolate();
18050 Handle<SharedFunctionInfo> shared(context->closure()->shared());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000018051 StringSharedKey key(src, shared, language_mode, RelocInfo::kNoPosition);
Steve Blocka7e24c12009-10-30 11:49:00 +000018052 int entry = FindEntry(&key);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000018053 if (entry == kNotFound) return isolate->factory()->undefined_value();
Emily Bernierd0a1eb72015-03-24 16:35:39 -040018054 int index = EntryToIndex(entry);
18055 if (!get(index)->IsFixedArray()) return isolate->factory()->undefined_value();
18056 return Handle<Object>(get(index + 1), isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +000018057}
18058
18059
Ben Murdochb8a8cc12014-11-26 15:28:44 +000018060Handle<Object> CompilationCacheTable::LookupEval(
18061 Handle<String> src, Handle<SharedFunctionInfo> outer_info,
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000018062 LanguageMode language_mode, int scope_position) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000018063 Isolate* isolate = GetIsolate();
18064 // Cache key is the tuple (source, outer shared function info, scope position)
18065 // to unambiguously identify the context chain the cached eval code assumes.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000018066 StringSharedKey key(src, outer_info, language_mode, scope_position);
Steve Blocka7e24c12009-10-30 11:49:00 +000018067 int entry = FindEntry(&key);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000018068 if (entry == kNotFound) return isolate->factory()->undefined_value();
Emily Bernierd0a1eb72015-03-24 16:35:39 -040018069 int index = EntryToIndex(entry);
18070 if (!get(index)->IsFixedArray()) return isolate->factory()->undefined_value();
Ben Murdochb8a8cc12014-11-26 15:28:44 +000018071 return Handle<Object>(get(EntryToIndex(entry) + 1), isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +000018072}
18073
18074
Ben Murdochb8a8cc12014-11-26 15:28:44 +000018075Handle<Object> CompilationCacheTable::LookupRegExp(Handle<String> src,
18076 JSRegExp::Flags flags) {
18077 Isolate* isolate = GetIsolate();
18078 DisallowHeapAllocation no_allocation;
Steve Blocka7e24c12009-10-30 11:49:00 +000018079 RegExpKey key(src, flags);
18080 int entry = FindEntry(&key);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000018081 if (entry == kNotFound) return isolate->factory()->undefined_value();
18082 return Handle<Object>(get(EntryToIndex(entry) + 1), isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +000018083}
18084
18085
Ben Murdochb8a8cc12014-11-26 15:28:44 +000018086Handle<CompilationCacheTable> CompilationCacheTable::Put(
18087 Handle<CompilationCacheTable> cache, Handle<String> src,
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000018088 Handle<Context> context, LanguageMode language_mode, Handle<Object> value) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000018089 Isolate* isolate = cache->GetIsolate();
18090 Handle<SharedFunctionInfo> shared(context->closure()->shared());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000018091 StringSharedKey key(src, shared, language_mode, RelocInfo::kNoPosition);
Emily Bernierd0a1eb72015-03-24 16:35:39 -040018092 {
18093 Handle<Object> k = key.AsHandle(isolate);
18094 DisallowHeapAllocation no_allocation_scope;
18095 int entry = cache->FindEntry(&key);
18096 if (entry != kNotFound) {
18097 cache->set(EntryToIndex(entry), *k);
18098 cache->set(EntryToIndex(entry) + 1, *value);
18099 return cache;
18100 }
18101 }
18102
Ben Murdochb8a8cc12014-11-26 15:28:44 +000018103 cache = EnsureCapacity(cache, 1, &key);
Steve Blocka7e24c12009-10-30 11:49:00 +000018104 int entry = cache->FindInsertionEntry(key.Hash());
Emily Bernierd0a1eb72015-03-24 16:35:39 -040018105 Handle<Object> k =
18106 isolate->factory()->NewNumber(static_cast<double>(key.Hash()));
Ben Murdochb8a8cc12014-11-26 15:28:44 +000018107 cache->set(EntryToIndex(entry), *k);
Emily Bernierd0a1eb72015-03-24 16:35:39 -040018108 cache->set(EntryToIndex(entry) + 1, Smi::FromInt(kHashGenerations));
Steve Blocka7e24c12009-10-30 11:49:00 +000018109 cache->ElementAdded();
18110 return cache;
18111}
18112
18113
Ben Murdochb8a8cc12014-11-26 15:28:44 +000018114Handle<CompilationCacheTable> CompilationCacheTable::PutEval(
18115 Handle<CompilationCacheTable> cache, Handle<String> src,
18116 Handle<SharedFunctionInfo> outer_info, Handle<SharedFunctionInfo> value,
18117 int scope_position) {
18118 Isolate* isolate = cache->GetIsolate();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000018119 StringSharedKey key(src, outer_info, value->language_mode(), scope_position);
Emily Bernierd0a1eb72015-03-24 16:35:39 -040018120 {
18121 Handle<Object> k = key.AsHandle(isolate);
18122 DisallowHeapAllocation no_allocation_scope;
18123 int entry = cache->FindEntry(&key);
18124 if (entry != kNotFound) {
18125 cache->set(EntryToIndex(entry), *k);
18126 cache->set(EntryToIndex(entry) + 1, *value);
18127 return cache;
18128 }
18129 }
18130
Ben Murdochb8a8cc12014-11-26 15:28:44 +000018131 cache = EnsureCapacity(cache, 1, &key);
Steve Blocka7e24c12009-10-30 11:49:00 +000018132 int entry = cache->FindInsertionEntry(key.Hash());
Emily Bernierd0a1eb72015-03-24 16:35:39 -040018133 Handle<Object> k =
18134 isolate->factory()->NewNumber(static_cast<double>(key.Hash()));
Ben Murdochb8a8cc12014-11-26 15:28:44 +000018135 cache->set(EntryToIndex(entry), *k);
Emily Bernierd0a1eb72015-03-24 16:35:39 -040018136 cache->set(EntryToIndex(entry) + 1, Smi::FromInt(kHashGenerations));
Steve Blocka7e24c12009-10-30 11:49:00 +000018137 cache->ElementAdded();
18138 return cache;
18139}
18140
18141
Ben Murdochb8a8cc12014-11-26 15:28:44 +000018142Handle<CompilationCacheTable> CompilationCacheTable::PutRegExp(
18143 Handle<CompilationCacheTable> cache, Handle<String> src,
18144 JSRegExp::Flags flags, Handle<FixedArray> value) {
Steve Blocka7e24c12009-10-30 11:49:00 +000018145 RegExpKey key(src, flags);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000018146 cache = EnsureCapacity(cache, 1, &key);
Steve Blocka7e24c12009-10-30 11:49:00 +000018147 int entry = cache->FindInsertionEntry(key.Hash());
Steve Block3ce2e202009-11-05 08:53:23 +000018148 // We store the value in the key slot, and compare the search key
18149 // to the stored value with a custon IsMatch function during lookups.
Ben Murdochb8a8cc12014-11-26 15:28:44 +000018150 cache->set(EntryToIndex(entry), *value);
18151 cache->set(EntryToIndex(entry) + 1, *value);
Steve Blocka7e24c12009-10-30 11:49:00 +000018152 cache->ElementAdded();
18153 return cache;
18154}
18155
18156
Emily Bernierd0a1eb72015-03-24 16:35:39 -040018157void CompilationCacheTable::Age() {
18158 DisallowHeapAllocation no_allocation;
18159 Object* the_hole_value = GetHeap()->the_hole_value();
18160 for (int entry = 0, size = Capacity(); entry < size; entry++) {
18161 int entry_index = EntryToIndex(entry);
18162 int value_index = entry_index + 1;
18163
18164 if (get(entry_index)->IsNumber()) {
18165 Smi* count = Smi::cast(get(value_index));
18166 count = Smi::FromInt(count->value() - 1);
18167 if (count->value() == 0) {
18168 NoWriteBarrierSet(this, entry_index, the_hole_value);
18169 NoWriteBarrierSet(this, value_index, the_hole_value);
18170 ElementRemoved();
18171 } else {
18172 NoWriteBarrierSet(this, value_index, count);
18173 }
18174 } else if (get(entry_index)->IsFixedArray()) {
18175 SharedFunctionInfo* info = SharedFunctionInfo::cast(get(value_index));
18176 if (info->code()->kind() != Code::FUNCTION || info->code()->IsOld()) {
18177 NoWriteBarrierSet(this, entry_index, the_hole_value);
18178 NoWriteBarrierSet(this, value_index, the_hole_value);
18179 ElementRemoved();
18180 }
18181 }
18182 }
18183}
18184
18185
Ben Murdochb0fe1622011-05-05 13:52:32 +010018186void CompilationCacheTable::Remove(Object* value) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000018187 DisallowHeapAllocation no_allocation;
Ben Murdoch3ef787d2012-04-12 10:51:47 +010018188 Object* the_hole_value = GetHeap()->the_hole_value();
Ben Murdochb0fe1622011-05-05 13:52:32 +010018189 for (int entry = 0, size = Capacity(); entry < size; entry++) {
18190 int entry_index = EntryToIndex(entry);
18191 int value_index = entry_index + 1;
18192 if (get(value_index) == value) {
Ben Murdoch3ef787d2012-04-12 10:51:47 +010018193 NoWriteBarrierSet(this, entry_index, the_hole_value);
18194 NoWriteBarrierSet(this, value_index, the_hole_value);
Ben Murdochb0fe1622011-05-05 13:52:32 +010018195 ElementRemoved();
18196 }
18197 }
18198 return;
18199}
18200
18201
Ben Murdochb8a8cc12014-11-26 15:28:44 +000018202// StringsKey used for HashTable where key is array of internalized strings.
18203class StringsKey : public HashTableKey {
Steve Blocka7e24c12009-10-30 11:49:00 +000018204 public:
Ben Murdochb8a8cc12014-11-26 15:28:44 +000018205 explicit StringsKey(Handle<FixedArray> strings) : strings_(strings) { }
Steve Blocka7e24c12009-10-30 11:49:00 +000018206
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000018207 bool IsMatch(Object* strings) override {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000018208 FixedArray* o = FixedArray::cast(strings);
18209 int len = strings_->length();
Steve Blocka7e24c12009-10-30 11:49:00 +000018210 if (o->length() != len) return false;
18211 for (int i = 0; i < len; i++) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000018212 if (o->get(i) != strings_->get(i)) return false;
Steve Blocka7e24c12009-10-30 11:49:00 +000018213 }
18214 return true;
18215 }
18216
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000018217 uint32_t Hash() override { return HashForObject(*strings_); }
Steve Blocka7e24c12009-10-30 11:49:00 +000018218
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000018219 uint32_t HashForObject(Object* obj) override {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000018220 FixedArray* strings = FixedArray::cast(obj);
18221 int len = strings->length();
Steve Blocka7e24c12009-10-30 11:49:00 +000018222 uint32_t hash = 0;
18223 for (int i = 0; i < len; i++) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000018224 hash ^= String::cast(strings->get(i))->Hash();
Steve Blocka7e24c12009-10-30 11:49:00 +000018225 }
18226 return hash;
18227 }
18228
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000018229 Handle<Object> AsHandle(Isolate* isolate) override { return strings_; }
Steve Blocka7e24c12009-10-30 11:49:00 +000018230
18231 private:
Ben Murdochb8a8cc12014-11-26 15:28:44 +000018232 Handle<FixedArray> strings_;
Steve Blocka7e24c12009-10-30 11:49:00 +000018233};
18234
18235
Ben Murdochb8a8cc12014-11-26 15:28:44 +000018236template<typename Derived, typename Shape, typename Key>
18237Handle<Derived> Dictionary<Derived, Shape, Key>::New(
18238 Isolate* isolate,
18239 int at_least_space_for,
18240 PretenureFlag pretenure) {
18241 DCHECK(0 <= at_least_space_for);
18242 Handle<Derived> dict = DerivedHashTable::New(isolate,
18243 at_least_space_for,
18244 USE_DEFAULT_MINIMUM_CAPACITY,
18245 pretenure);
18246
John Reck59135872010-11-02 12:39:01 -070018247 // Initialize the next enumeration index.
Ben Murdochb8a8cc12014-11-26 15:28:44 +000018248 dict->SetNextEnumerationIndex(PropertyDetails::kInitialIndex);
18249 return dict;
Steve Blocka7e24c12009-10-30 11:49:00 +000018250}
18251
18252
Emily Bernierd0a1eb72015-03-24 16:35:39 -040018253template <typename Derived, typename Shape, typename Key>
18254Handle<FixedArray> Dictionary<Derived, Shape, Key>::BuildIterationIndicesArray(
Ben Murdochb8a8cc12014-11-26 15:28:44 +000018255 Handle<Derived> dictionary) {
18256 Factory* factory = dictionary->GetIsolate()->factory();
18257 int length = dictionary->NumberOfElements();
Steve Blocka7e24c12009-10-30 11:49:00 +000018258
Ben Murdochb8a8cc12014-11-26 15:28:44 +000018259 Handle<FixedArray> iteration_order = factory->NewFixedArray(length);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000018260 Handle<FixedArray> enumeration_order = factory->NewFixedArray(length);
Steve Blocka7e24c12009-10-30 11:49:00 +000018261
Emily Bernierd0a1eb72015-03-24 16:35:39 -040018262 // Fill both the iteration order array and the enumeration order array
18263 // with property details.
Ben Murdochb8a8cc12014-11-26 15:28:44 +000018264 int capacity = dictionary->Capacity();
Steve Blocka7e24c12009-10-30 11:49:00 +000018265 int pos = 0;
18266 for (int i = 0; i < capacity; i++) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000018267 if (dictionary->IsKey(dictionary->KeyAt(i))) {
18268 int index = dictionary->DetailsAt(i).dictionary_index();
Emily Bernierd0a1eb72015-03-24 16:35:39 -040018269 iteration_order->set(pos, Smi::FromInt(i));
18270 enumeration_order->set(pos, Smi::FromInt(index));
18271 pos++;
Steve Blocka7e24c12009-10-30 11:49:00 +000018272 }
18273 }
Emily Bernierd0a1eb72015-03-24 16:35:39 -040018274 DCHECK(pos == length);
Steve Blocka7e24c12009-10-30 11:49:00 +000018275
18276 // Sort the arrays wrt. enumeration order.
Ben Murdochb8a8cc12014-11-26 15:28:44 +000018277 iteration_order->SortPairs(*enumeration_order, enumeration_order->length());
Emily Bernierd0a1eb72015-03-24 16:35:39 -040018278 return iteration_order;
18279}
Steve Blocka7e24c12009-10-30 11:49:00 +000018280
Emily Bernierd0a1eb72015-03-24 16:35:39 -040018281
18282template <typename Derived, typename Shape, typename Key>
18283Handle<FixedArray>
18284Dictionary<Derived, Shape, Key>::GenerateNewEnumerationIndices(
18285 Handle<Derived> dictionary) {
18286 int length = dictionary->NumberOfElements();
18287
18288 Handle<FixedArray> iteration_order = BuildIterationIndicesArray(dictionary);
18289 DCHECK(iteration_order->length() == length);
18290
18291 // Iterate over the dictionary using the enumeration order and update
18292 // the dictionary with new enumeration indices.
Steve Blocka7e24c12009-10-30 11:49:00 +000018293 for (int i = 0; i < length; i++) {
18294 int index = Smi::cast(iteration_order->get(i))->value();
Emily Bernierd0a1eb72015-03-24 16:35:39 -040018295 DCHECK(dictionary->IsKey(dictionary->KeyAt(index)));
Steve Blocka7e24c12009-10-30 11:49:00 +000018296
Emily Bernierd0a1eb72015-03-24 16:35:39 -040018297 int enum_index = PropertyDetails::kInitialIndex + i;
18298
18299 PropertyDetails details = dictionary->DetailsAt(index);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000018300 PropertyDetails new_details = details.set_index(enum_index);
Emily Bernierd0a1eb72015-03-24 16:35:39 -040018301 dictionary->DetailsAtPut(index, new_details);
Steve Blocka7e24c12009-10-30 11:49:00 +000018302 }
18303
18304 // Set the next enumeration index.
Ben Murdochb8a8cc12014-11-26 15:28:44 +000018305 dictionary->SetNextEnumerationIndex(PropertyDetails::kInitialIndex+length);
Emily Bernierd0a1eb72015-03-24 16:35:39 -040018306 return iteration_order;
Steve Blocka7e24c12009-10-30 11:49:00 +000018307}
18308
Ben Murdochb8a8cc12014-11-26 15:28:44 +000018309
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000018310template <typename Derived, typename Shape, typename Key>
18311void Dictionary<Derived, Shape, Key>::SetRequiresCopyOnCapacityChange() {
18312 DCHECK_EQ(0, DerivedHashTable::NumberOfElements());
18313 DCHECK_EQ(0, DerivedHashTable::NumberOfDeletedElements());
18314 // Make sure that HashTable::EnsureCapacity will create a copy.
18315 DerivedHashTable::SetNumberOfDeletedElements(DerivedHashTable::Capacity());
18316 DCHECK(!DerivedHashTable::HasSufficientCapacity(1));
18317}
18318
18319
18320template <typename Derived, typename Shape, typename Key>
Ben Murdochb8a8cc12014-11-26 15:28:44 +000018321Handle<Derived> Dictionary<Derived, Shape, Key>::EnsureCapacity(
18322 Handle<Derived> dictionary, int n, Key key) {
Steve Blocka7e24c12009-10-30 11:49:00 +000018323 // Check whether there are enough enumeration indices to add n elements.
18324 if (Shape::kIsEnumerable &&
Ben Murdochb8a8cc12014-11-26 15:28:44 +000018325 !PropertyDetails::IsValidIndex(dictionary->NextEnumerationIndex() + n)) {
Steve Blocka7e24c12009-10-30 11:49:00 +000018326 // If not, we generate new indices for the properties.
Ben Murdochb8a8cc12014-11-26 15:28:44 +000018327 GenerateNewEnumerationIndices(dictionary);
Steve Blocka7e24c12009-10-30 11:49:00 +000018328 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +000018329 return DerivedHashTable::EnsureCapacity(dictionary, n, key);
Steve Blocka7e24c12009-10-30 11:49:00 +000018330}
18331
18332
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000018333template <typename Derived, typename Shape, typename Key>
Ben Murdochb8a8cc12014-11-26 15:28:44 +000018334Handle<Object> Dictionary<Derived, Shape, Key>::DeleteProperty(
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000018335 Handle<Derived> dictionary, int entry) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000018336 Factory* factory = dictionary->GetIsolate()->factory();
18337 PropertyDetails details = dictionary->DetailsAt(entry);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000018338 if (!details.IsConfigurable()) return factory->false_value();
Ben Murdochb8a8cc12014-11-26 15:28:44 +000018339
18340 dictionary->SetEntry(
18341 entry, factory->the_hole_value(), factory->the_hole_value());
18342 dictionary->ElementRemoved();
18343 return factory->true_value();
Steve Blocka7e24c12009-10-30 11:49:00 +000018344}
18345
18346
Ben Murdochb8a8cc12014-11-26 15:28:44 +000018347template<typename Derived, typename Shape, typename Key>
18348Handle<Derived> Dictionary<Derived, Shape, Key>::AtPut(
18349 Handle<Derived> dictionary, Key key, Handle<Object> value) {
18350 int entry = dictionary->FindEntry(key);
Steve Blocka7e24c12009-10-30 11:49:00 +000018351
18352 // If the entry is present set the value;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000018353 if (entry != Dictionary::kNotFound) {
18354 dictionary->ValueAtPut(entry, *value);
18355 return dictionary;
Steve Blocka7e24c12009-10-30 11:49:00 +000018356 }
18357
18358 // Check whether the dictionary should be extended.
Ben Murdochb8a8cc12014-11-26 15:28:44 +000018359 dictionary = EnsureCapacity(dictionary, 1, key);
18360#ifdef DEBUG
18361 USE(Shape::AsHandle(dictionary->GetIsolate(), key));
18362#endif
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000018363 PropertyDetails details = PropertyDetails::Empty();
Steve Blocka7e24c12009-10-30 11:49:00 +000018364
Ben Murdochb8a8cc12014-11-26 15:28:44 +000018365 AddEntry(dictionary, key, value, details, dictionary->Hash(key));
18366 return dictionary;
Steve Blocka7e24c12009-10-30 11:49:00 +000018367}
18368
18369
Ben Murdochb8a8cc12014-11-26 15:28:44 +000018370template<typename Derived, typename Shape, typename Key>
18371Handle<Derived> Dictionary<Derived, Shape, Key>::Add(
18372 Handle<Derived> dictionary,
18373 Key key,
18374 Handle<Object> value,
18375 PropertyDetails details) {
Steve Blocka7e24c12009-10-30 11:49:00 +000018376 // Valdate key is absent.
Ben Murdochb8a8cc12014-11-26 15:28:44 +000018377 SLOW_DCHECK((dictionary->FindEntry(key) == Dictionary::kNotFound));
Steve Blocka7e24c12009-10-30 11:49:00 +000018378 // Check whether the dictionary should be extended.
Ben Murdochb8a8cc12014-11-26 15:28:44 +000018379 dictionary = EnsureCapacity(dictionary, 1, key);
Ben Murdochc7cc0282012-03-05 14:35:55 +000018380
Ben Murdochb8a8cc12014-11-26 15:28:44 +000018381 AddEntry(dictionary, key, value, details, dictionary->Hash(key));
18382 return dictionary;
Steve Blocka7e24c12009-10-30 11:49:00 +000018383}
18384
18385
18386// Add a key, value pair to the dictionary.
Ben Murdochb8a8cc12014-11-26 15:28:44 +000018387template<typename Derived, typename Shape, typename Key>
18388void Dictionary<Derived, Shape, Key>::AddEntry(
18389 Handle<Derived> dictionary,
18390 Key key,
18391 Handle<Object> value,
18392 PropertyDetails details,
18393 uint32_t hash) {
Steve Blocka7e24c12009-10-30 11:49:00 +000018394 // Compute the key object.
Ben Murdochb8a8cc12014-11-26 15:28:44 +000018395 Handle<Object> k = Shape::AsHandle(dictionary->GetIsolate(), key);
Steve Blocka7e24c12009-10-30 11:49:00 +000018396
Ben Murdochb8a8cc12014-11-26 15:28:44 +000018397 uint32_t entry = dictionary->FindInsertionEntry(hash);
Steve Blocka7e24c12009-10-30 11:49:00 +000018398 // Insert element at empty or deleted entry
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000018399 if (details.dictionary_index() == 0 && Shape::kIsEnumerable) {
Steve Blocka7e24c12009-10-30 11:49:00 +000018400 // Assign an enumeration index to the property and update
18401 // SetNextEnumerationIndex.
Ben Murdochb8a8cc12014-11-26 15:28:44 +000018402 int index = dictionary->NextEnumerationIndex();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000018403 details = details.set_index(index);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000018404 dictionary->SetNextEnumerationIndex(index + 1);
Steve Blocka7e24c12009-10-30 11:49:00 +000018405 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +000018406 dictionary->SetEntry(entry, k, value, details);
18407 DCHECK((dictionary->KeyAt(entry)->IsNumber() ||
18408 dictionary->KeyAt(entry)->IsName()));
18409 dictionary->ElementAdded();
Steve Blocka7e24c12009-10-30 11:49:00 +000018410}
18411
18412
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000018413void SeededNumberDictionary::UpdateMaxNumberKey(uint32_t key,
18414 bool used_as_prototype) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000018415 DisallowHeapAllocation no_allocation;
Steve Blocka7e24c12009-10-30 11:49:00 +000018416 // If the dictionary requires slow elements an element has already
18417 // been added at a high index.
18418 if (requires_slow_elements()) return;
18419 // Check if this index is high enough that we should require slow
18420 // elements.
18421 if (key > kRequiresSlowElementsLimit) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000018422 if (used_as_prototype) {
18423 // TODO(verwaest): Remove this hack.
18424 TypeFeedbackVector::ClearAllKeyedStoreICs(GetIsolate());
18425 }
Steve Blocka7e24c12009-10-30 11:49:00 +000018426 set_requires_slow_elements();
18427 return;
18428 }
18429 // Update max key value.
18430 Object* max_index_object = get(kMaxNumberKeyIndex);
18431 if (!max_index_object->IsSmi() || max_number_key() < key) {
18432 FixedArray::set(kMaxNumberKeyIndex,
Leon Clarke4515c472010-02-03 11:58:03 +000018433 Smi::FromInt(key << kRequiresSlowElementsTagSize));
Steve Blocka7e24c12009-10-30 11:49:00 +000018434 }
18435}
18436
18437
Ben Murdochb8a8cc12014-11-26 15:28:44 +000018438Handle<SeededNumberDictionary> SeededNumberDictionary::AddNumberEntry(
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000018439 Handle<SeededNumberDictionary> dictionary, uint32_t key,
18440 Handle<Object> value, PropertyDetails details, bool used_as_prototype) {
18441 dictionary->UpdateMaxNumberKey(key, used_as_prototype);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000018442 SLOW_DCHECK(dictionary->FindEntry(key) == kNotFound);
18443 return Add(dictionary, key, value, details);
Steve Blocka7e24c12009-10-30 11:49:00 +000018444}
18445
18446
Ben Murdochb8a8cc12014-11-26 15:28:44 +000018447Handle<UnseededNumberDictionary> UnseededNumberDictionary::AddNumberEntry(
18448 Handle<UnseededNumberDictionary> dictionary,
18449 uint32_t key,
18450 Handle<Object> value) {
18451 SLOW_DCHECK(dictionary->FindEntry(key) == kNotFound);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000018452 return Add(dictionary, key, value, PropertyDetails::Empty());
Ben Murdochc7cc0282012-03-05 14:35:55 +000018453}
18454
18455
Ben Murdochb8a8cc12014-11-26 15:28:44 +000018456Handle<SeededNumberDictionary> SeededNumberDictionary::AtNumberPut(
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000018457 Handle<SeededNumberDictionary> dictionary, uint32_t key,
18458 Handle<Object> value, bool used_as_prototype) {
18459 dictionary->UpdateMaxNumberKey(key, used_as_prototype);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000018460 return AtPut(dictionary, key, value);
Steve Blocka7e24c12009-10-30 11:49:00 +000018461}
18462
18463
Ben Murdochb8a8cc12014-11-26 15:28:44 +000018464Handle<UnseededNumberDictionary> UnseededNumberDictionary::AtNumberPut(
18465 Handle<UnseededNumberDictionary> dictionary,
18466 uint32_t key,
18467 Handle<Object> value) {
18468 return AtPut(dictionary, key, value);
Ben Murdochc7cc0282012-03-05 14:35:55 +000018469}
18470
18471
Ben Murdoch3ef787d2012-04-12 10:51:47 +010018472Handle<SeededNumberDictionary> SeededNumberDictionary::Set(
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000018473 Handle<SeededNumberDictionary> dictionary, uint32_t key,
18474 Handle<Object> value, PropertyDetails details, bool used_as_prototype) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000018475 int entry = dictionary->FindEntry(key);
18476 if (entry == kNotFound) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000018477 return AddNumberEntry(dictionary, key, value, details, used_as_prototype);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000018478 }
18479 // Preserve enumeration index.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000018480 details = details.set_index(dictionary->DetailsAt(entry).dictionary_index());
Ben Murdochb8a8cc12014-11-26 15:28:44 +000018481 Handle<Object> object_key =
18482 SeededNumberDictionaryShape::AsHandle(dictionary->GetIsolate(), key);
18483 dictionary->SetEntry(entry, object_key, value, details);
18484 return dictionary;
Ben Murdoch3ef787d2012-04-12 10:51:47 +010018485}
18486
18487
18488Handle<UnseededNumberDictionary> UnseededNumberDictionary::Set(
18489 Handle<UnseededNumberDictionary> dictionary,
Ben Murdochb8a8cc12014-11-26 15:28:44 +000018490 uint32_t key,
Ben Murdoch3ef787d2012-04-12 10:51:47 +010018491 Handle<Object> value) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000018492 int entry = dictionary->FindEntry(key);
18493 if (entry == kNotFound) return AddNumberEntry(dictionary, key, value);
18494 Handle<Object> object_key =
18495 UnseededNumberDictionaryShape::AsHandle(dictionary->GetIsolate(), key);
18496 dictionary->SetEntry(entry, object_key, value);
18497 return dictionary;
Ben Murdochc7cc0282012-03-05 14:35:55 +000018498}
18499
18500
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000018501template <typename Derived, typename Shape, typename Key>
Ben Murdochb8a8cc12014-11-26 15:28:44 +000018502int Dictionary<Derived, Shape, Key>::NumberOfElementsFilterAttributes(
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000018503 PropertyFilter filter) {
18504 int capacity = this->Capacity();
Steve Blocka7e24c12009-10-30 11:49:00 +000018505 int result = 0;
18506 for (int i = 0; i < capacity; i++) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000018507 Object* k = this->KeyAt(i);
18508 if (this->IsKey(k) && !k->FilterKey(filter)) {
18509 if (this->IsDeleted(i)) continue;
18510 PropertyDetails details = this->DetailsAt(i);
Steve Blocka7e24c12009-10-30 11:49:00 +000018511 PropertyAttributes attr = details.attributes();
18512 if ((attr & filter) == 0) result++;
18513 }
18514 }
18515 return result;
18516}
18517
18518
Emily Bernierd0a1eb72015-03-24 16:35:39 -040018519template <typename Derived, typename Shape, typename Key>
18520bool Dictionary<Derived, Shape, Key>::HasComplexElements() {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000018521 int capacity = this->Capacity();
Emily Bernierd0a1eb72015-03-24 16:35:39 -040018522 for (int i = 0; i < capacity; i++) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000018523 Object* k = this->KeyAt(i);
18524 if (this->IsKey(k) && !k->FilterKey(ALL_PROPERTIES)) {
18525 if (this->IsDeleted(i)) continue;
18526 PropertyDetails details = this->DetailsAt(i);
18527 if (details.type() == ACCESSOR_CONSTANT) return true;
Emily Bernierd0a1eb72015-03-24 16:35:39 -040018528 PropertyAttributes attr = details.attributes();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000018529 if (attr & ALL_ATTRIBUTES_MASK) return true;
Emily Bernierd0a1eb72015-03-24 16:35:39 -040018530 }
18531 }
18532 return false;
18533}
18534
18535
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000018536template <typename Dictionary>
Ben Murdochb8a8cc12014-11-26 15:28:44 +000018537struct EnumIndexComparator {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000018538 explicit EnumIndexComparator(Dictionary* dict) : dict(dict) {}
Ben Murdochb8a8cc12014-11-26 15:28:44 +000018539 bool operator() (Smi* a, Smi* b) {
18540 PropertyDetails da(dict->DetailsAt(a->value()));
18541 PropertyDetails db(dict->DetailsAt(b->value()));
18542 return da.dictionary_index() < db.dictionary_index();
18543 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000018544 Dictionary* dict;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000018545};
18546
18547
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000018548template <typename Derived, typename Shape, typename Key>
18549void Dictionary<Derived, Shape, Key>::CopyEnumKeysTo(FixedArray* storage) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000018550 int length = storage->length();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000018551 int capacity = this->Capacity();
Ben Murdochb8a8cc12014-11-26 15:28:44 +000018552 int properties = 0;
Steve Blocka7e24c12009-10-30 11:49:00 +000018553 for (int i = 0; i < capacity; i++) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000018554 Object* k = this->KeyAt(i);
18555 if (this->IsKey(k) && !k->IsSymbol()) {
18556 PropertyDetails details = this->DetailsAt(i);
18557 if (details.IsDontEnum() || this->IsDeleted(i)) continue;
18558 storage->set(properties, Smi::FromInt(i));
18559 properties++;
18560 if (properties == length) break;
18561 }
Steve Blocka7e24c12009-10-30 11:49:00 +000018562 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +000018563 CHECK_EQ(length, properties);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000018564 EnumIndexComparator<Derived> cmp(static_cast<Derived*>(this));
Ben Murdochb8a8cc12014-11-26 15:28:44 +000018565 Smi** start = reinterpret_cast<Smi**>(storage->GetFirstElementAddress());
18566 std::sort(start, start + length, cmp);
18567 for (int i = 0; i < length; i++) {
18568 int index = Smi::cast(storage->get(i))->value();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000018569 storage->set(i, this->KeyAt(index));
Ben Murdochb8a8cc12014-11-26 15:28:44 +000018570 }
Steve Blocka7e24c12009-10-30 11:49:00 +000018571}
18572
18573
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000018574template <typename Derived, typename Shape, typename Key>
18575int Dictionary<Derived, Shape, Key>::CopyKeysTo(
18576 FixedArray* storage, int index, PropertyFilter filter,
Ben Murdochb8a8cc12014-11-26 15:28:44 +000018577 typename Dictionary<Derived, Shape, Key>::SortMode sort_mode) {
18578 DCHECK(storage->length() >= NumberOfElementsFilterAttributes(filter));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000018579 int start_index = index;
18580 int capacity = this->Capacity();
Steve Blocka7e24c12009-10-30 11:49:00 +000018581 for (int i = 0; i < capacity; i++) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000018582 Object* k = this->KeyAt(i);
18583 if (!this->IsKey(k) || k->FilterKey(filter)) continue;
18584 if (this->IsDeleted(i)) continue;
18585 PropertyDetails details = this->DetailsAt(i);
18586 PropertyAttributes attr = details.attributes();
18587 if ((attr & filter) != 0) continue;
18588 storage->set(index++, k);
Steve Blocka7e24c12009-10-30 11:49:00 +000018589 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +000018590 if (sort_mode == Dictionary::SORTED) {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000018591 storage->SortPairs(storage, index);
18592 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +000018593 DCHECK(storage->length() >= index);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000018594 return index - start_index;
18595}
18596
18597
18598template <typename Derived, typename Shape, typename Key>
18599void Dictionary<Derived, Shape, Key>::CollectKeysTo(
18600 Handle<Dictionary<Derived, Shape, Key> > dictionary, KeyAccumulator* keys,
18601 PropertyFilter filter) {
18602 int capacity = dictionary->Capacity();
18603 Handle<FixedArray> array =
18604 keys->isolate()->factory()->NewFixedArray(dictionary->NumberOfElements());
18605 int array_size = 0;
18606
18607 {
18608 DisallowHeapAllocation no_gc;
18609 Dictionary<Derived, Shape, Key>* raw_dict = *dictionary;
18610 for (int i = 0; i < capacity; i++) {
18611 Object* k = raw_dict->KeyAt(i);
18612 if (!raw_dict->IsKey(k) || k->FilterKey(filter)) continue;
18613 if (raw_dict->IsDeleted(i)) continue;
18614 PropertyDetails details = raw_dict->DetailsAt(i);
18615 if ((details.attributes() & filter) != 0) continue;
18616 if (filter & ONLY_ALL_CAN_READ) {
18617 if (details.kind() != kAccessor) continue;
18618 Object* accessors = raw_dict->ValueAt(i);
18619 if (accessors->IsPropertyCell()) {
18620 accessors = PropertyCell::cast(accessors)->value();
18621 }
18622 if (!accessors->IsAccessorInfo()) continue;
18623 if (!AccessorInfo::cast(accessors)->all_can_read()) continue;
18624 }
18625 array->set(array_size++, Smi::FromInt(i));
18626 }
18627
18628 EnumIndexComparator<Derived> cmp(static_cast<Derived*>(raw_dict));
18629 Smi** start = reinterpret_cast<Smi**>(array->GetFirstElementAddress());
18630 std::sort(start, start + array_size, cmp);
18631 }
18632
18633 for (int i = 0; i < array_size; i++) {
18634 int index = Smi::cast(array->get(i))->value();
Ben Murdoch097c5b22016-05-18 11:27:45 +010018635 keys->AddKey(dictionary->KeyAt(index), DO_NOT_CONVERT);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000018636 }
Steve Blocka7e24c12009-10-30 11:49:00 +000018637}
18638
18639
18640// Backwards lookup (slow).
Ben Murdochb8a8cc12014-11-26 15:28:44 +000018641template<typename Derived, typename Shape, typename Key>
18642Object* Dictionary<Derived, Shape, Key>::SlowReverseLookup(Object* value) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000018643 int capacity = this->Capacity();
Steve Blocka7e24c12009-10-30 11:49:00 +000018644 for (int i = 0; i < capacity; i++) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000018645 Object* k = this->KeyAt(i);
18646 if (this->IsKey(k)) {
18647 Object* e = this->ValueAt(i);
18648 // TODO(dcarney): this should be templatized.
Ben Murdochb8a8cc12014-11-26 15:28:44 +000018649 if (e->IsPropertyCell()) {
18650 e = PropertyCell::cast(e)->value();
Steve Blocka7e24c12009-10-30 11:49:00 +000018651 }
18652 if (e == value) return k;
18653 }
18654 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +000018655 Heap* heap = Dictionary::GetHeap();
Steve Block44f0eee2011-05-26 01:26:41 +010018656 return heap->undefined_value();
Steve Blocka7e24c12009-10-30 11:49:00 +000018657}
18658
18659
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000018660Object* ObjectHashTable::Lookup(Isolate* isolate, Handle<Object> key,
18661 int32_t hash) {
18662 DisallowHeapAllocation no_gc;
18663 DCHECK(IsKey(*key));
18664
18665 int entry = FindEntry(isolate, key, hash);
18666 if (entry == kNotFound) return isolate->heap()->the_hole_value();
18667 return get(EntryToIndex(entry) + 1);
18668}
18669
18670
Ben Murdochb8a8cc12014-11-26 15:28:44 +000018671Object* ObjectHashTable::Lookup(Handle<Object> key) {
18672 DisallowHeapAllocation no_gc;
18673 DCHECK(IsKey(*key));
Ben Murdoch3ef787d2012-04-12 10:51:47 +010018674
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000018675 Isolate* isolate = GetIsolate();
18676
Ben Murdoch69a99ed2011-11-30 16:03:39 +000018677 // If the object does not have an identity hash, it was never used as a key.
Ben Murdochb8a8cc12014-11-26 15:28:44 +000018678 Object* hash = key->GetHash();
18679 if (hash->IsUndefined()) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000018680 return isolate->heap()->the_hole_value();
Ben Murdoch3ef787d2012-04-12 10:51:47 +010018681 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000018682 return Lookup(isolate, key, Smi::cast(hash)->value());
18683}
18684
18685
18686Object* ObjectHashTable::Lookup(Handle<Object> key, int32_t hash) {
18687 return Lookup(GetIsolate(), key, hash);
Ben Murdoch69a99ed2011-11-30 16:03:39 +000018688}
18689
18690
Ben Murdochb8a8cc12014-11-26 15:28:44 +000018691Handle<ObjectHashTable> ObjectHashTable::Put(Handle<ObjectHashTable> table,
18692 Handle<Object> key,
18693 Handle<Object> value) {
18694 DCHECK(table->IsKey(*key));
18695 DCHECK(!value->IsTheHole());
18696
18697 Isolate* isolate = table->GetIsolate();
Ben Murdoch69a99ed2011-11-30 16:03:39 +000018698 // Make sure the key object has an identity hash code.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000018699 int32_t hash = Object::GetOrCreateHash(isolate, key)->value();
Ben Murdoch69a99ed2011-11-30 16:03:39 +000018700
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000018701 return Put(table, key, value, hash);
18702}
18703
18704
18705Handle<ObjectHashTable> ObjectHashTable::Put(Handle<ObjectHashTable> table,
18706 Handle<Object> key,
18707 Handle<Object> value,
18708 int32_t hash) {
18709 DCHECK(table->IsKey(*key));
18710 DCHECK(!value->IsTheHole());
18711
18712 Isolate* isolate = table->GetIsolate();
18713
18714 int entry = table->FindEntry(isolate, key, hash);
Ben Murdoch69a99ed2011-11-30 16:03:39 +000018715
18716 // Key is already in table, just overwrite value.
18717 if (entry != kNotFound) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000018718 table->set(EntryToIndex(entry) + 1, *value);
18719 return table;
Ben Murdoch69a99ed2011-11-30 16:03:39 +000018720 }
18721
Ben Murdoch097c5b22016-05-18 11:27:45 +010018722 // Rehash if more than 25% of the entries are deleted entries.
18723 // TODO(jochen): Consider to shrink the fixed array in place.
18724 if ((table->NumberOfDeletedElements() << 1) > table->NumberOfElements()) {
18725 table->Rehash(isolate->factory()->undefined_value());
18726 }
18727
Ben Murdoch69a99ed2011-11-30 16:03:39 +000018728 // Check whether the hash table should be extended.
Ben Murdochb8a8cc12014-11-26 15:28:44 +000018729 table = EnsureCapacity(table, 1, key);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000018730 table->AddEntry(table->FindInsertionEntry(hash), *key, *value);
Ben Murdoch69a99ed2011-11-30 16:03:39 +000018731 return table;
18732}
18733
18734
Ben Murdochb8a8cc12014-11-26 15:28:44 +000018735Handle<ObjectHashTable> ObjectHashTable::Remove(Handle<ObjectHashTable> table,
18736 Handle<Object> key,
18737 bool* was_present) {
18738 DCHECK(table->IsKey(*key));
18739
18740 Object* hash = key->GetHash();
18741 if (hash->IsUndefined()) {
18742 *was_present = false;
18743 return table;
18744 }
18745
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000018746 return Remove(table, key, was_present, Smi::cast(hash)->value());
18747}
18748
18749
18750Handle<ObjectHashTable> ObjectHashTable::Remove(Handle<ObjectHashTable> table,
18751 Handle<Object> key,
18752 bool* was_present,
18753 int32_t hash) {
18754 DCHECK(table->IsKey(*key));
18755
18756 int entry = table->FindEntry(table->GetIsolate(), key, hash);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000018757 if (entry == kNotFound) {
18758 *was_present = false;
18759 return table;
18760 }
18761
18762 *was_present = true;
18763 table->RemoveEntry(entry);
18764 return Shrink(table, key);
18765}
18766
18767
Ben Murdoch3ef787d2012-04-12 10:51:47 +010018768void ObjectHashTable::AddEntry(int entry, Object* key, Object* value) {
Ben Murdoch69a99ed2011-11-30 16:03:39 +000018769 set(EntryToIndex(entry), key);
18770 set(EntryToIndex(entry) + 1, value);
18771 ElementAdded();
18772}
18773
18774
Ben Murdoch3ef787d2012-04-12 10:51:47 +010018775void ObjectHashTable::RemoveEntry(int entry) {
18776 set_the_hole(EntryToIndex(entry));
18777 set_the_hole(EntryToIndex(entry) + 1);
Ben Murdoch69a99ed2011-11-30 16:03:39 +000018778 ElementRemoved();
18779}
18780
18781
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000018782Object* WeakHashTable::Lookup(Handle<HeapObject> key) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000018783 DisallowHeapAllocation no_gc;
18784 DCHECK(IsKey(*key));
18785 int entry = FindEntry(key);
18786 if (entry == kNotFound) return GetHeap()->the_hole_value();
18787 return get(EntryToValueIndex(entry));
18788}
18789
18790
18791Handle<WeakHashTable> WeakHashTable::Put(Handle<WeakHashTable> table,
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000018792 Handle<HeapObject> key,
18793 Handle<HeapObject> value) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000018794 DCHECK(table->IsKey(*key));
18795 int entry = table->FindEntry(key);
18796 // Key is already in table, just overwrite value.
18797 if (entry != kNotFound) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000018798 table->set(EntryToValueIndex(entry), *value);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000018799 return table;
18800 }
18801
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000018802 Handle<WeakCell> key_cell = key->GetIsolate()->factory()->NewWeakCell(key);
18803
Ben Murdochb8a8cc12014-11-26 15:28:44 +000018804 // Check whether the hash table should be extended.
18805 table = EnsureCapacity(table, 1, key, TENURED);
18806
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000018807 table->AddEntry(table->FindInsertionEntry(table->Hash(key)), key_cell, value);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000018808 return table;
18809}
18810
18811
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000018812void WeakHashTable::AddEntry(int entry, Handle<WeakCell> key_cell,
18813 Handle<HeapObject> value) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000018814 DisallowHeapAllocation no_allocation;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000018815 set(EntryToIndex(entry), *key_cell);
18816 set(EntryToValueIndex(entry), *value);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000018817 ElementAdded();
18818}
18819
18820
18821template<class Derived, class Iterator, int entrysize>
18822Handle<Derived> OrderedHashTable<Derived, Iterator, entrysize>::Allocate(
18823 Isolate* isolate, int capacity, PretenureFlag pretenure) {
18824 // Capacity must be a power of two, since we depend on being able
18825 // to divide and multiple by 2 (kLoadFactor) to derive capacity
18826 // from number of buckets. If we decide to change kLoadFactor
18827 // to something other than 2, capacity should be stored as another
18828 // field of this object.
18829 capacity = base::bits::RoundUpToPowerOfTwo32(Max(kMinCapacity, capacity));
18830 if (capacity > kMaxCapacity) {
18831 v8::internal::Heap::FatalProcessOutOfMemory("invalid table size", true);
18832 }
18833 int num_buckets = capacity / kLoadFactor;
18834 Handle<FixedArray> backing_store = isolate->factory()->NewFixedArray(
18835 kHashTableStartIndex + num_buckets + (capacity * kEntrySize), pretenure);
18836 backing_store->set_map_no_write_barrier(
18837 isolate->heap()->ordered_hash_table_map());
18838 Handle<Derived> table = Handle<Derived>::cast(backing_store);
18839 for (int i = 0; i < num_buckets; ++i) {
18840 table->set(kHashTableStartIndex + i, Smi::FromInt(kNotFound));
18841 }
18842 table->SetNumberOfBuckets(num_buckets);
18843 table->SetNumberOfElements(0);
18844 table->SetNumberOfDeletedElements(0);
18845 return table;
18846}
18847
18848
18849template<class Derived, class Iterator, int entrysize>
18850Handle<Derived> OrderedHashTable<Derived, Iterator, entrysize>::EnsureGrowable(
18851 Handle<Derived> table) {
18852 DCHECK(!table->IsObsolete());
18853
18854 int nof = table->NumberOfElements();
18855 int nod = table->NumberOfDeletedElements();
18856 int capacity = table->Capacity();
18857 if ((nof + nod) < capacity) return table;
18858 // Don't need to grow if we can simply clear out deleted entries instead.
18859 // Note that we can't compact in place, though, so we always allocate
18860 // a new table.
18861 return Rehash(table, (nod < (capacity >> 1)) ? capacity << 1 : capacity);
18862}
18863
18864
18865template<class Derived, class Iterator, int entrysize>
18866Handle<Derived> OrderedHashTable<Derived, Iterator, entrysize>::Shrink(
18867 Handle<Derived> table) {
18868 DCHECK(!table->IsObsolete());
18869
18870 int nof = table->NumberOfElements();
18871 int capacity = table->Capacity();
18872 if (nof >= (capacity >> 2)) return table;
18873 return Rehash(table, capacity / 2);
18874}
18875
18876
18877template<class Derived, class Iterator, int entrysize>
18878Handle<Derived> OrderedHashTable<Derived, Iterator, entrysize>::Clear(
18879 Handle<Derived> table) {
18880 DCHECK(!table->IsObsolete());
18881
18882 Handle<Derived> new_table =
18883 Allocate(table->GetIsolate(),
18884 kMinCapacity,
18885 table->GetHeap()->InNewSpace(*table) ? NOT_TENURED : TENURED);
18886
18887 table->SetNextTable(*new_table);
Emily Bernierd0a1eb72015-03-24 16:35:39 -040018888 table->SetNumberOfDeletedElements(kClearedTableSentinel);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000018889
18890 return new_table;
18891}
18892
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000018893template <class Derived, class Iterator, int entrysize>
18894bool OrderedHashTable<Derived, Iterator, entrysize>::HasKey(
18895 Handle<Derived> table, Handle<Object> key) {
18896 int entry = table->KeyToFirstEntry(*key);
18897 // Walk the chain in the bucket to find the key.
18898 while (entry != kNotFound) {
18899 Object* candidate_key = table->KeyAt(entry);
18900 if (candidate_key->SameValueZero(*key)) return true;
18901 entry = table->NextChainEntry(entry);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000018902 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000018903 return false;
18904}
18905
18906
18907Handle<OrderedHashSet> OrderedHashSet::Add(Handle<OrderedHashSet> table,
18908 Handle<Object> key) {
18909 int hash = Object::GetOrCreateHash(table->GetIsolate(), key)->value();
18910 int entry = table->HashToEntry(hash);
18911 // Walk the chain of the bucket and try finding the key.
18912 while (entry != kNotFound) {
18913 Object* candidate_key = table->KeyAt(entry);
18914 // Do not add if we have the key already
18915 if (candidate_key->SameValueZero(*key)) return table;
18916 entry = table->NextChainEntry(entry);
18917 }
18918
18919 table = OrderedHashSet::EnsureGrowable(table);
18920 // Read the existing bucket values.
18921 int bucket = table->HashToBucket(hash);
18922 int previous_entry = table->HashToEntry(hash);
18923 int nof = table->NumberOfElements();
18924 // Insert a new entry at the end,
18925 int new_entry = nof + table->NumberOfDeletedElements();
18926 int new_index = table->EntryToIndex(new_entry);
18927 table->set(new_index, *key);
18928 table->set(new_index + kChainOffset, Smi::FromInt(previous_entry));
18929 // and point the bucket to the new entry.
18930 table->set(kHashTableStartIndex + bucket, Smi::FromInt(new_entry));
18931 table->SetNumberOfElements(nof + 1);
18932 return table;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000018933}
18934
18935
18936template<class Derived, class Iterator, int entrysize>
18937Handle<Derived> OrderedHashTable<Derived, Iterator, entrysize>::Rehash(
18938 Handle<Derived> table, int new_capacity) {
18939 DCHECK(!table->IsObsolete());
18940
18941 Handle<Derived> new_table =
18942 Allocate(table->GetIsolate(),
18943 new_capacity,
18944 table->GetHeap()->InNewSpace(*table) ? NOT_TENURED : TENURED);
18945 int nof = table->NumberOfElements();
18946 int nod = table->NumberOfDeletedElements();
18947 int new_buckets = new_table->NumberOfBuckets();
18948 int new_entry = 0;
18949 int removed_holes_index = 0;
18950
18951 for (int old_entry = 0; old_entry < (nof + nod); ++old_entry) {
18952 Object* key = table->KeyAt(old_entry);
18953 if (key->IsTheHole()) {
18954 table->SetRemovedIndexAt(removed_holes_index++, old_entry);
18955 continue;
18956 }
18957
18958 Object* hash = key->GetHash();
18959 int bucket = Smi::cast(hash)->value() & (new_buckets - 1);
18960 Object* chain_entry = new_table->get(kHashTableStartIndex + bucket);
18961 new_table->set(kHashTableStartIndex + bucket, Smi::FromInt(new_entry));
18962 int new_index = new_table->EntryToIndex(new_entry);
18963 int old_index = table->EntryToIndex(old_entry);
18964 for (int i = 0; i < entrysize; ++i) {
18965 Object* value = table->get(old_index + i);
18966 new_table->set(new_index + i, value);
18967 }
18968 new_table->set(new_index + kChainOffset, chain_entry);
18969 ++new_entry;
18970 }
18971
18972 DCHECK_EQ(nod, removed_holes_index);
18973
18974 new_table->SetNumberOfElements(nof);
18975 table->SetNextTable(*new_table);
18976
18977 return new_table;
18978}
18979
18980
Ben Murdochb8a8cc12014-11-26 15:28:44 +000018981template Handle<OrderedHashSet>
18982OrderedHashTable<OrderedHashSet, JSSetIterator, 1>::Allocate(
18983 Isolate* isolate, int capacity, PretenureFlag pretenure);
18984
18985template Handle<OrderedHashSet>
18986OrderedHashTable<OrderedHashSet, JSSetIterator, 1>::EnsureGrowable(
18987 Handle<OrderedHashSet> table);
18988
18989template Handle<OrderedHashSet>
18990OrderedHashTable<OrderedHashSet, JSSetIterator, 1>::Shrink(
18991 Handle<OrderedHashSet> table);
18992
18993template Handle<OrderedHashSet>
18994OrderedHashTable<OrderedHashSet, JSSetIterator, 1>::Clear(
18995 Handle<OrderedHashSet> table);
18996
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000018997template bool OrderedHashTable<OrderedHashSet, JSSetIterator, 1>::HasKey(
18998 Handle<OrderedHashSet> table, Handle<Object> key);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000018999
19000
19001template Handle<OrderedHashMap>
19002OrderedHashTable<OrderedHashMap, JSMapIterator, 2>::Allocate(
19003 Isolate* isolate, int capacity, PretenureFlag pretenure);
19004
19005template Handle<OrderedHashMap>
19006OrderedHashTable<OrderedHashMap, JSMapIterator, 2>::EnsureGrowable(
19007 Handle<OrderedHashMap> table);
19008
19009template Handle<OrderedHashMap>
19010OrderedHashTable<OrderedHashMap, JSMapIterator, 2>::Shrink(
19011 Handle<OrderedHashMap> table);
19012
19013template Handle<OrderedHashMap>
19014OrderedHashTable<OrderedHashMap, JSMapIterator, 2>::Clear(
19015 Handle<OrderedHashMap> table);
19016
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000019017template bool OrderedHashTable<OrderedHashMap, JSMapIterator, 2>::HasKey(
19018 Handle<OrderedHashMap> table, Handle<Object> key);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000019019
19020
19021template<class Derived, class TableType>
19022void OrderedHashTableIterator<Derived, TableType>::Transition() {
19023 DisallowHeapAllocation no_allocation;
19024 TableType* table = TableType::cast(this->table());
19025 if (!table->IsObsolete()) return;
19026
19027 int index = Smi::cast(this->index())->value();
19028 while (table->IsObsolete()) {
19029 TableType* next_table = table->NextTable();
19030
19031 if (index > 0) {
19032 int nod = table->NumberOfDeletedElements();
19033
Emily Bernierd0a1eb72015-03-24 16:35:39 -040019034 if (nod == TableType::kClearedTableSentinel) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000019035 index = 0;
19036 } else {
19037 int old_index = index;
19038 for (int i = 0; i < nod; ++i) {
19039 int removed_index = table->RemovedIndexAt(i);
19040 if (removed_index >= old_index) break;
19041 --index;
19042 }
19043 }
19044 }
19045
19046 table = next_table;
19047 }
19048
19049 set_table(table);
19050 set_index(Smi::FromInt(index));
19051}
19052
19053
19054template<class Derived, class TableType>
19055bool OrderedHashTableIterator<Derived, TableType>::HasMore() {
19056 DisallowHeapAllocation no_allocation;
19057 if (this->table()->IsUndefined()) return false;
19058
19059 Transition();
19060
19061 TableType* table = TableType::cast(this->table());
19062 int index = Smi::cast(this->index())->value();
19063 int used_capacity = table->UsedCapacity();
19064
19065 while (index < used_capacity && table->KeyAt(index)->IsTheHole()) {
19066 index++;
19067 }
19068
19069 set_index(Smi::FromInt(index));
19070
19071 if (index < used_capacity) return true;
19072
19073 set_table(GetHeap()->undefined_value());
19074 return false;
19075}
19076
19077
19078template<class Derived, class TableType>
19079Smi* OrderedHashTableIterator<Derived, TableType>::Next(JSArray* value_array) {
19080 DisallowHeapAllocation no_allocation;
19081 if (HasMore()) {
19082 FixedArray* array = FixedArray::cast(value_array->elements());
19083 static_cast<Derived*>(this)->PopulateValueArray(array);
19084 MoveNext();
19085 return Smi::cast(kind());
19086 }
19087 return Smi::FromInt(0);
19088}
19089
19090
19091template Smi*
19092OrderedHashTableIterator<JSSetIterator, OrderedHashSet>::Next(
19093 JSArray* value_array);
19094
19095template bool
19096OrderedHashTableIterator<JSSetIterator, OrderedHashSet>::HasMore();
19097
19098template void
19099OrderedHashTableIterator<JSSetIterator, OrderedHashSet>::MoveNext();
19100
19101template Object*
19102OrderedHashTableIterator<JSSetIterator, OrderedHashSet>::CurrentKey();
19103
19104template void
19105OrderedHashTableIterator<JSSetIterator, OrderedHashSet>::Transition();
19106
19107
19108template Smi*
19109OrderedHashTableIterator<JSMapIterator, OrderedHashMap>::Next(
19110 JSArray* value_array);
19111
19112template bool
19113OrderedHashTableIterator<JSMapIterator, OrderedHashMap>::HasMore();
19114
19115template void
19116OrderedHashTableIterator<JSMapIterator, OrderedHashMap>::MoveNext();
19117
19118template Object*
19119OrderedHashTableIterator<JSMapIterator, OrderedHashMap>::CurrentKey();
19120
19121template void
19122OrderedHashTableIterator<JSMapIterator, OrderedHashMap>::Transition();
19123
19124
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000019125void JSSet::Initialize(Handle<JSSet> set, Isolate* isolate) {
19126 Handle<OrderedHashSet> table = isolate->factory()->NewOrderedHashSet();
19127 set->set_table(*table);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000019128}
19129
19130
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000019131void JSSet::Clear(Handle<JSSet> set) {
19132 Handle<OrderedHashSet> table(OrderedHashSet::cast(set->table()));
19133 table = OrderedHashSet::Clear(table);
19134 set->set_table(*table);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000019135}
19136
19137
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000019138void JSMap::Initialize(Handle<JSMap> map, Isolate* isolate) {
19139 Handle<OrderedHashMap> table = isolate->factory()->NewOrderedHashMap();
19140 map->set_table(*table);
19141}
19142
19143
19144void JSMap::Clear(Handle<JSMap> map) {
19145 Handle<OrderedHashMap> table(OrderedHashMap::cast(map->table()));
19146 table = OrderedHashMap::Clear(table);
19147 map->set_table(*table);
19148}
19149
19150
19151void JSWeakCollection::Initialize(Handle<JSWeakCollection> weak_collection,
19152 Isolate* isolate) {
19153 Handle<ObjectHashTable> table = ObjectHashTable::New(isolate, 0);
19154 weak_collection->set_table(*table);
19155}
19156
19157
19158void JSWeakCollection::Set(Handle<JSWeakCollection> weak_collection,
19159 Handle<Object> key, Handle<Object> value,
19160 int32_t hash) {
19161 DCHECK(key->IsJSReceiver() || key->IsSymbol());
19162 Handle<ObjectHashTable> table(
19163 ObjectHashTable::cast(weak_collection->table()));
19164 DCHECK(table->IsKey(*key));
19165 Handle<ObjectHashTable> new_table =
19166 ObjectHashTable::Put(table, key, value, hash);
19167 weak_collection->set_table(*new_table);
19168 if (*table != *new_table) {
19169 // Zap the old table since we didn't record slots for its elements.
19170 table->FillWithHoles(0, table->length());
Ben Murdochb8a8cc12014-11-26 15:28:44 +000019171 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000019172}
19173
19174
19175bool JSWeakCollection::Delete(Handle<JSWeakCollection> weak_collection,
19176 Handle<Object> key, int32_t hash) {
19177 DCHECK(key->IsJSReceiver() || key->IsSymbol());
19178 Handle<ObjectHashTable> table(
19179 ObjectHashTable::cast(weak_collection->table()));
19180 DCHECK(table->IsKey(*key));
19181 bool was_present = false;
19182 Handle<ObjectHashTable> new_table =
19183 ObjectHashTable::Remove(table, key, &was_present, hash);
19184 weak_collection->set_table(*new_table);
19185 if (*table != *new_table) {
19186 // Zap the old table since we didn't record slots for its elements.
19187 table->FillWithHoles(0, table->length());
19188 }
19189 return was_present;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000019190}
19191
Ben Murdoch097c5b22016-05-18 11:27:45 +010019192// Check if there is a break point at this code offset.
19193bool DebugInfo::HasBreakPoint(int code_offset) {
19194 // Get the break point info object for this code offset.
19195 Object* break_point_info = GetBreakPointInfo(code_offset);
Steve Blocka7e24c12009-10-30 11:49:00 +000019196
19197 // If there is no break point info object or no break points in the break
Ben Murdoch097c5b22016-05-18 11:27:45 +010019198 // point info object there is no break point at this code offset.
Steve Blocka7e24c12009-10-30 11:49:00 +000019199 if (break_point_info->IsUndefined()) return false;
19200 return BreakPointInfo::cast(break_point_info)->GetBreakPointCount() > 0;
19201}
19202
Ben Murdoch097c5b22016-05-18 11:27:45 +010019203// Get the break point info object for this code offset.
19204Object* DebugInfo::GetBreakPointInfo(int code_offset) {
19205 // Find the index of the break point info object for this code offset.
19206 int index = GetBreakPointInfoIndex(code_offset);
Steve Blocka7e24c12009-10-30 11:49:00 +000019207
19208 // Return the break point info object if any.
Ben Murdoch8b112d22011-06-08 16:22:53 +010019209 if (index == kNoBreakPointInfo) return GetHeap()->undefined_value();
Steve Blocka7e24c12009-10-30 11:49:00 +000019210 return BreakPointInfo::cast(break_points()->get(index));
19211}
19212
Ben Murdoch097c5b22016-05-18 11:27:45 +010019213// Clear a break point at the specified code offset.
19214void DebugInfo::ClearBreakPoint(Handle<DebugInfo> debug_info, int code_offset,
Steve Blocka7e24c12009-10-30 11:49:00 +000019215 Handle<Object> break_point_object) {
Ben Murdoch097c5b22016-05-18 11:27:45 +010019216 Handle<Object> break_point_info(debug_info->GetBreakPointInfo(code_offset),
Ben Murdochb8a8cc12014-11-26 15:28:44 +000019217 debug_info->GetIsolate());
Steve Blocka7e24c12009-10-30 11:49:00 +000019218 if (break_point_info->IsUndefined()) return;
19219 BreakPointInfo::ClearBreakPoint(
19220 Handle<BreakPointInfo>::cast(break_point_info),
19221 break_point_object);
19222}
19223
Ben Murdoch097c5b22016-05-18 11:27:45 +010019224void DebugInfo::SetBreakPoint(Handle<DebugInfo> debug_info, int code_offset,
19225 int source_position, int statement_position,
Steve Blocka7e24c12009-10-30 11:49:00 +000019226 Handle<Object> break_point_object) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000019227 Isolate* isolate = debug_info->GetIsolate();
Ben Murdoch097c5b22016-05-18 11:27:45 +010019228 Handle<Object> break_point_info(debug_info->GetBreakPointInfo(code_offset),
Ben Murdochb8a8cc12014-11-26 15:28:44 +000019229 isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +000019230 if (!break_point_info->IsUndefined()) {
19231 BreakPointInfo::SetBreakPoint(
19232 Handle<BreakPointInfo>::cast(break_point_info),
19233 break_point_object);
19234 return;
19235 }
19236
Ben Murdoch097c5b22016-05-18 11:27:45 +010019237 // Adding a new break point for a code offset which did not have any
Steve Blocka7e24c12009-10-30 11:49:00 +000019238 // break points before. Try to find a free slot.
19239 int index = kNoBreakPointInfo;
19240 for (int i = 0; i < debug_info->break_points()->length(); i++) {
19241 if (debug_info->break_points()->get(i)->IsUndefined()) {
19242 index = i;
19243 break;
19244 }
19245 }
19246 if (index == kNoBreakPointInfo) {
19247 // No free slot - extend break point info array.
19248 Handle<FixedArray> old_break_points =
19249 Handle<FixedArray>(FixedArray::cast(debug_info->break_points()));
Steve Blocka7e24c12009-10-30 11:49:00 +000019250 Handle<FixedArray> new_break_points =
Steve Block44f0eee2011-05-26 01:26:41 +010019251 isolate->factory()->NewFixedArray(
19252 old_break_points->length() +
Ben Murdochb8a8cc12014-11-26 15:28:44 +000019253 DebugInfo::kEstimatedNofBreakPointsInFunction);
Kristian Monsen0d5e1162010-09-30 15:31:59 +010019254
19255 debug_info->set_break_points(*new_break_points);
Steve Blocka7e24c12009-10-30 11:49:00 +000019256 for (int i = 0; i < old_break_points->length(); i++) {
19257 new_break_points->set(i, old_break_points->get(i));
19258 }
19259 index = old_break_points->length();
19260 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +000019261 DCHECK(index != kNoBreakPointInfo);
Steve Blocka7e24c12009-10-30 11:49:00 +000019262
19263 // Allocate new BreakPointInfo object and set the break point.
Steve Block44f0eee2011-05-26 01:26:41 +010019264 Handle<BreakPointInfo> new_break_point_info = Handle<BreakPointInfo>::cast(
19265 isolate->factory()->NewStruct(BREAK_POINT_INFO_TYPE));
Ben Murdoch097c5b22016-05-18 11:27:45 +010019266 new_break_point_info->set_code_offset(code_offset);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000019267 new_break_point_info->set_source_position(source_position);
19268 new_break_point_info->set_statement_position(statement_position);
Steve Block44f0eee2011-05-26 01:26:41 +010019269 new_break_point_info->set_break_point_objects(
19270 isolate->heap()->undefined_value());
Steve Blocka7e24c12009-10-30 11:49:00 +000019271 BreakPointInfo::SetBreakPoint(new_break_point_info, break_point_object);
19272 debug_info->break_points()->set(index, *new_break_point_info);
19273}
19274
Ben Murdoch097c5b22016-05-18 11:27:45 +010019275// Get the break point objects for a code offset.
19276Handle<Object> DebugInfo::GetBreakPointObjects(int code_offset) {
19277 Object* break_point_info = GetBreakPointInfo(code_offset);
Steve Blocka7e24c12009-10-30 11:49:00 +000019278 if (break_point_info->IsUndefined()) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000019279 return GetIsolate()->factory()->undefined_value();
Steve Blocka7e24c12009-10-30 11:49:00 +000019280 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000019281 return Handle<Object>(
19282 BreakPointInfo::cast(break_point_info)->break_point_objects(),
19283 GetIsolate());
Steve Blocka7e24c12009-10-30 11:49:00 +000019284}
19285
19286
19287// Get the total number of break points.
19288int DebugInfo::GetBreakPointCount() {
19289 if (break_points()->IsUndefined()) return 0;
19290 int count = 0;
19291 for (int i = 0; i < break_points()->length(); i++) {
19292 if (!break_points()->get(i)->IsUndefined()) {
19293 BreakPointInfo* break_point_info =
19294 BreakPointInfo::cast(break_points()->get(i));
19295 count += break_point_info->GetBreakPointCount();
19296 }
19297 }
19298 return count;
19299}
19300
19301
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000019302Handle<Object> DebugInfo::FindBreakPointInfo(
19303 Handle<DebugInfo> debug_info, Handle<Object> break_point_object) {
19304 Isolate* isolate = debug_info->GetIsolate();
19305 if (!debug_info->break_points()->IsUndefined()) {
19306 for (int i = 0; i < debug_info->break_points()->length(); i++) {
19307 if (!debug_info->break_points()->get(i)->IsUndefined()) {
19308 Handle<BreakPointInfo> break_point_info = Handle<BreakPointInfo>(
19309 BreakPointInfo::cast(debug_info->break_points()->get(i)), isolate);
19310 if (BreakPointInfo::HasBreakPointObject(break_point_info,
19311 break_point_object)) {
19312 return break_point_info;
19313 }
Steve Blocka7e24c12009-10-30 11:49:00 +000019314 }
19315 }
19316 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000019317 return isolate->factory()->undefined_value();
Steve Blocka7e24c12009-10-30 11:49:00 +000019318}
19319
19320
19321// Find the index of the break point info object for the specified code
19322// position.
Ben Murdoch097c5b22016-05-18 11:27:45 +010019323int DebugInfo::GetBreakPointInfoIndex(int code_offset) {
Steve Blocka7e24c12009-10-30 11:49:00 +000019324 if (break_points()->IsUndefined()) return kNoBreakPointInfo;
19325 for (int i = 0; i < break_points()->length(); i++) {
19326 if (!break_points()->get(i)->IsUndefined()) {
19327 BreakPointInfo* break_point_info =
19328 BreakPointInfo::cast(break_points()->get(i));
Ben Murdoch097c5b22016-05-18 11:27:45 +010019329 if (break_point_info->code_offset() == code_offset) {
Steve Blocka7e24c12009-10-30 11:49:00 +000019330 return i;
19331 }
19332 }
19333 }
19334 return kNoBreakPointInfo;
19335}
19336
19337
19338// Remove the specified break point object.
19339void BreakPointInfo::ClearBreakPoint(Handle<BreakPointInfo> break_point_info,
19340 Handle<Object> break_point_object) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000019341 Isolate* isolate = break_point_info->GetIsolate();
Steve Blocka7e24c12009-10-30 11:49:00 +000019342 // If there are no break points just ignore.
19343 if (break_point_info->break_point_objects()->IsUndefined()) return;
19344 // If there is a single break point clear it if it is the same.
19345 if (!break_point_info->break_point_objects()->IsFixedArray()) {
19346 if (break_point_info->break_point_objects() == *break_point_object) {
Steve Block44f0eee2011-05-26 01:26:41 +010019347 break_point_info->set_break_point_objects(
19348 isolate->heap()->undefined_value());
Steve Blocka7e24c12009-10-30 11:49:00 +000019349 }
19350 return;
19351 }
19352 // If there are multiple break points shrink the array
Ben Murdochb8a8cc12014-11-26 15:28:44 +000019353 DCHECK(break_point_info->break_point_objects()->IsFixedArray());
Steve Blocka7e24c12009-10-30 11:49:00 +000019354 Handle<FixedArray> old_array =
19355 Handle<FixedArray>(
19356 FixedArray::cast(break_point_info->break_point_objects()));
19357 Handle<FixedArray> new_array =
Steve Block44f0eee2011-05-26 01:26:41 +010019358 isolate->factory()->NewFixedArray(old_array->length() - 1);
Steve Blocka7e24c12009-10-30 11:49:00 +000019359 int found_count = 0;
19360 for (int i = 0; i < old_array->length(); i++) {
19361 if (old_array->get(i) == *break_point_object) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000019362 DCHECK(found_count == 0);
Steve Blocka7e24c12009-10-30 11:49:00 +000019363 found_count++;
19364 } else {
19365 new_array->set(i - found_count, old_array->get(i));
19366 }
19367 }
19368 // If the break point was found in the list change it.
19369 if (found_count > 0) break_point_info->set_break_point_objects(*new_array);
19370}
19371
19372
19373// Add the specified break point object.
19374void BreakPointInfo::SetBreakPoint(Handle<BreakPointInfo> break_point_info,
19375 Handle<Object> break_point_object) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000019376 Isolate* isolate = break_point_info->GetIsolate();
19377
Steve Blocka7e24c12009-10-30 11:49:00 +000019378 // If there was no break point objects before just set it.
19379 if (break_point_info->break_point_objects()->IsUndefined()) {
19380 break_point_info->set_break_point_objects(*break_point_object);
19381 return;
19382 }
19383 // If the break point object is the same as before just ignore.
19384 if (break_point_info->break_point_objects() == *break_point_object) return;
19385 // If there was one break point object before replace with array.
19386 if (!break_point_info->break_point_objects()->IsFixedArray()) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000019387 Handle<FixedArray> array = isolate->factory()->NewFixedArray(2);
Steve Blocka7e24c12009-10-30 11:49:00 +000019388 array->set(0, break_point_info->break_point_objects());
19389 array->set(1, *break_point_object);
19390 break_point_info->set_break_point_objects(*array);
19391 return;
19392 }
19393 // If there was more than one break point before extend array.
19394 Handle<FixedArray> old_array =
19395 Handle<FixedArray>(
19396 FixedArray::cast(break_point_info->break_point_objects()));
19397 Handle<FixedArray> new_array =
Ben Murdochb8a8cc12014-11-26 15:28:44 +000019398 isolate->factory()->NewFixedArray(old_array->length() + 1);
Steve Blocka7e24c12009-10-30 11:49:00 +000019399 for (int i = 0; i < old_array->length(); i++) {
19400 // If the break point was there before just ignore.
19401 if (old_array->get(i) == *break_point_object) return;
19402 new_array->set(i, old_array->get(i));
19403 }
19404 // Add the new break point.
19405 new_array->set(old_array->length(), *break_point_object);
19406 break_point_info->set_break_point_objects(*new_array);
19407}
19408
19409
19410bool BreakPointInfo::HasBreakPointObject(
19411 Handle<BreakPointInfo> break_point_info,
19412 Handle<Object> break_point_object) {
19413 // No break point.
19414 if (break_point_info->break_point_objects()->IsUndefined()) return false;
Ben Murdoch69a99ed2011-11-30 16:03:39 +000019415 // Single break point.
Steve Blocka7e24c12009-10-30 11:49:00 +000019416 if (!break_point_info->break_point_objects()->IsFixedArray()) {
19417 return break_point_info->break_point_objects() == *break_point_object;
19418 }
19419 // Multiple break points.
19420 FixedArray* array = FixedArray::cast(break_point_info->break_point_objects());
19421 for (int i = 0; i < array->length(); i++) {
19422 if (array->get(i) == *break_point_object) {
19423 return true;
19424 }
19425 }
19426 return false;
19427}
19428
19429
19430// Get the number of break points.
19431int BreakPointInfo::GetBreakPointCount() {
19432 // No break point.
19433 if (break_point_objects()->IsUndefined()) return 0;
Ben Murdoch69a99ed2011-11-30 16:03:39 +000019434 // Single break point.
Steve Blocka7e24c12009-10-30 11:49:00 +000019435 if (!break_point_objects()->IsFixedArray()) return 1;
19436 // Multiple break points.
19437 return FixedArray::cast(break_point_objects())->length();
19438}
Steve Blocka7e24c12009-10-30 11:49:00 +000019439
19440
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000019441// static
19442MaybeHandle<JSDate> JSDate::New(Handle<JSFunction> constructor,
19443 Handle<JSReceiver> new_target, double tv) {
19444 Isolate* const isolate = constructor->GetIsolate();
19445 Handle<JSObject> result;
19446 ASSIGN_RETURN_ON_EXCEPTION(isolate, result,
19447 JSObject::New(constructor, new_target), JSDate);
19448 if (-DateCache::kMaxTimeInMs <= tv && tv <= DateCache::kMaxTimeInMs) {
19449 tv = DoubleToInteger(tv) + 0.0;
19450 } else {
19451 tv = std::numeric_limits<double>::quiet_NaN();
19452 }
19453 Handle<Object> value = isolate->factory()->NewNumber(tv);
19454 Handle<JSDate>::cast(result)->SetValue(*value, std::isnan(tv));
19455 return Handle<JSDate>::cast(result);
19456}
19457
19458
19459// static
19460double JSDate::CurrentTimeValue(Isolate* isolate) {
19461 if (FLAG_log_timer_events || FLAG_prof_cpp) LOG(isolate, CurrentTimeEvent());
19462
19463 // According to ECMA-262, section 15.9.1, page 117, the precision of
19464 // the number in a Date object representing a particular instant in
19465 // time is milliseconds. Therefore, we floor the result of getting
19466 // the OS time.
19467 return Floor(FLAG_verify_predictable
19468 ? isolate->heap()->MonotonicallyIncreasingTimeInMs()
19469 : base::OS::TimeCurrentMillis());
19470}
19471
19472
19473// static
Ben Murdochb8a8cc12014-11-26 15:28:44 +000019474Object* JSDate::GetField(Object* object, Smi* index) {
Ben Murdoch3ef787d2012-04-12 10:51:47 +010019475 return JSDate::cast(object)->DoGetField(
19476 static_cast<FieldIndex>(index->value()));
19477}
19478
19479
19480Object* JSDate::DoGetField(FieldIndex index) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000019481 DCHECK(index != kDateValue);
Ben Murdoch3ef787d2012-04-12 10:51:47 +010019482
19483 DateCache* date_cache = GetIsolate()->date_cache();
19484
19485 if (index < kFirstUncachedField) {
19486 Object* stamp = cache_stamp();
19487 if (stamp != date_cache->stamp() && stamp->IsSmi()) {
19488 // Since the stamp is not NaN, the value is also not NaN.
19489 int64_t local_time_ms =
19490 date_cache->ToLocal(static_cast<int64_t>(value()->Number()));
Ben Murdochb8a8cc12014-11-26 15:28:44 +000019491 SetCachedFields(local_time_ms, date_cache);
Ben Murdoch3ef787d2012-04-12 10:51:47 +010019492 }
19493 switch (index) {
19494 case kYear: return year();
19495 case kMonth: return month();
19496 case kDay: return day();
19497 case kWeekday: return weekday();
19498 case kHour: return hour();
19499 case kMinute: return min();
19500 case kSecond: return sec();
19501 default: UNREACHABLE();
19502 }
19503 }
19504
19505 if (index >= kFirstUTCField) {
19506 return GetUTCField(index, value()->Number(), date_cache);
19507 }
19508
19509 double time = value()->Number();
Ben Murdochb8a8cc12014-11-26 15:28:44 +000019510 if (std::isnan(time)) return GetIsolate()->heap()->nan_value();
Ben Murdoch3ef787d2012-04-12 10:51:47 +010019511
19512 int64_t local_time_ms = date_cache->ToLocal(static_cast<int64_t>(time));
19513 int days = DateCache::DaysFromTime(local_time_ms);
19514
19515 if (index == kDays) return Smi::FromInt(days);
19516
19517 int time_in_day_ms = DateCache::TimeInDay(local_time_ms, days);
19518 if (index == kMillisecond) return Smi::FromInt(time_in_day_ms % 1000);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000019519 DCHECK(index == kTimeInDay);
Ben Murdoch3ef787d2012-04-12 10:51:47 +010019520 return Smi::FromInt(time_in_day_ms);
19521}
19522
19523
19524Object* JSDate::GetUTCField(FieldIndex index,
19525 double value,
19526 DateCache* date_cache) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000019527 DCHECK(index >= kFirstUTCField);
Ben Murdoch3ef787d2012-04-12 10:51:47 +010019528
Ben Murdochb8a8cc12014-11-26 15:28:44 +000019529 if (std::isnan(value)) return GetIsolate()->heap()->nan_value();
Ben Murdoch3ef787d2012-04-12 10:51:47 +010019530
19531 int64_t time_ms = static_cast<int64_t>(value);
19532
19533 if (index == kTimezoneOffset) {
19534 return Smi::FromInt(date_cache->TimezoneOffset(time_ms));
19535 }
19536
19537 int days = DateCache::DaysFromTime(time_ms);
19538
19539 if (index == kWeekdayUTC) return Smi::FromInt(date_cache->Weekday(days));
19540
19541 if (index <= kDayUTC) {
19542 int year, month, day;
19543 date_cache->YearMonthDayFromDays(days, &year, &month, &day);
19544 if (index == kYearUTC) return Smi::FromInt(year);
19545 if (index == kMonthUTC) return Smi::FromInt(month);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000019546 DCHECK(index == kDayUTC);
Ben Murdoch3ef787d2012-04-12 10:51:47 +010019547 return Smi::FromInt(day);
19548 }
19549
19550 int time_in_day_ms = DateCache::TimeInDay(time_ms, days);
19551 switch (index) {
19552 case kHourUTC: return Smi::FromInt(time_in_day_ms / (60 * 60 * 1000));
19553 case kMinuteUTC: return Smi::FromInt((time_in_day_ms / (60 * 1000)) % 60);
19554 case kSecondUTC: return Smi::FromInt((time_in_day_ms / 1000) % 60);
19555 case kMillisecondUTC: return Smi::FromInt(time_in_day_ms % 1000);
19556 case kDaysUTC: return Smi::FromInt(days);
19557 case kTimeInDayUTC: return Smi::FromInt(time_in_day_ms);
19558 default: UNREACHABLE();
19559 }
19560
19561 UNREACHABLE();
19562 return NULL;
19563}
19564
19565
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000019566// static
19567Handle<Object> JSDate::SetValue(Handle<JSDate> date, double v) {
19568 Isolate* const isolate = date->GetIsolate();
19569 Handle<Object> value = isolate->factory()->NewNumber(v);
19570 bool value_is_nan = std::isnan(v);
19571 date->SetValue(*value, value_is_nan);
19572 return value;
19573}
19574
19575
Ben Murdoch3ef787d2012-04-12 10:51:47 +010019576void JSDate::SetValue(Object* value, bool is_value_nan) {
19577 set_value(value);
19578 if (is_value_nan) {
19579 HeapNumber* nan = GetIsolate()->heap()->nan_value();
19580 set_cache_stamp(nan, SKIP_WRITE_BARRIER);
19581 set_year(nan, SKIP_WRITE_BARRIER);
19582 set_month(nan, SKIP_WRITE_BARRIER);
19583 set_day(nan, SKIP_WRITE_BARRIER);
19584 set_hour(nan, SKIP_WRITE_BARRIER);
19585 set_min(nan, SKIP_WRITE_BARRIER);
19586 set_sec(nan, SKIP_WRITE_BARRIER);
19587 set_weekday(nan, SKIP_WRITE_BARRIER);
19588 } else {
19589 set_cache_stamp(Smi::FromInt(DateCache::kInvalidStamp), SKIP_WRITE_BARRIER);
19590 }
19591}
19592
19593
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000019594// static
19595MaybeHandle<Object> JSDate::ToPrimitive(Handle<JSReceiver> receiver,
19596 Handle<Object> hint) {
19597 Isolate* const isolate = receiver->GetIsolate();
19598 if (hint->IsString()) {
19599 Handle<String> hint_string = Handle<String>::cast(hint);
19600 if (hint_string->Equals(isolate->heap()->number_string())) {
19601 return JSReceiver::OrdinaryToPrimitive(receiver,
19602 OrdinaryToPrimitiveHint::kNumber);
19603 }
19604 if (hint_string->Equals(isolate->heap()->default_string()) ||
19605 hint_string->Equals(isolate->heap()->string_string())) {
19606 return JSReceiver::OrdinaryToPrimitive(receiver,
19607 OrdinaryToPrimitiveHint::kString);
19608 }
19609 }
19610 THROW_NEW_ERROR(isolate, NewTypeError(MessageTemplate::kInvalidHint, hint),
19611 Object);
19612}
19613
19614
Ben Murdochb8a8cc12014-11-26 15:28:44 +000019615void JSDate::SetCachedFields(int64_t local_time_ms, DateCache* date_cache) {
Ben Murdoch3ef787d2012-04-12 10:51:47 +010019616 int days = DateCache::DaysFromTime(local_time_ms);
19617 int time_in_day_ms = DateCache::TimeInDay(local_time_ms, days);
19618 int year, month, day;
19619 date_cache->YearMonthDayFromDays(days, &year, &month, &day);
19620 int weekday = date_cache->Weekday(days);
19621 int hour = time_in_day_ms / (60 * 60 * 1000);
19622 int min = (time_in_day_ms / (60 * 1000)) % 60;
19623 int sec = (time_in_day_ms / 1000) % 60;
19624 set_cache_stamp(date_cache->stamp());
19625 set_year(Smi::FromInt(year), SKIP_WRITE_BARRIER);
19626 set_month(Smi::FromInt(month), SKIP_WRITE_BARRIER);
19627 set_day(Smi::FromInt(day), SKIP_WRITE_BARRIER);
19628 set_weekday(Smi::FromInt(weekday), SKIP_WRITE_BARRIER);
19629 set_hour(Smi::FromInt(hour), SKIP_WRITE_BARRIER);
19630 set_min(Smi::FromInt(min), SKIP_WRITE_BARRIER);
19631 set_sec(Smi::FromInt(sec), SKIP_WRITE_BARRIER);
19632}
19633
Ben Murdochb8a8cc12014-11-26 15:28:44 +000019634
19635void JSArrayBuffer::Neuter() {
Emily Bernierd0a1eb72015-03-24 16:35:39 -040019636 CHECK(is_neuterable());
19637 CHECK(is_external());
Ben Murdochb8a8cc12014-11-26 15:28:44 +000019638 set_backing_store(NULL);
19639 set_byte_length(Smi::FromInt(0));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000019640 set_was_neutered(true);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000019641}
19642
19643
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000019644void JSArrayBuffer::Setup(Handle<JSArrayBuffer> array_buffer, Isolate* isolate,
19645 bool is_external, void* data, size_t allocated_length,
19646 SharedFlag shared) {
19647 DCHECK(array_buffer->GetInternalFieldCount() ==
19648 v8::ArrayBuffer::kInternalFieldCount);
19649 for (int i = 0; i < v8::ArrayBuffer::kInternalFieldCount; i++) {
19650 array_buffer->SetInternalField(i, Smi::FromInt(0));
Ben Murdochb8a8cc12014-11-26 15:28:44 +000019651 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000019652 array_buffer->set_bit_field(0);
19653 array_buffer->set_is_external(is_external);
19654 array_buffer->set_is_neuterable(shared == SharedFlag::kNotShared);
19655 array_buffer->set_is_shared(shared == SharedFlag::kShared);
19656
19657 Handle<Object> byte_length =
19658 isolate->factory()->NewNumberFromSize(allocated_length);
19659 CHECK(byte_length->IsSmi() || byte_length->IsHeapNumber());
19660 array_buffer->set_byte_length(*byte_length);
19661 // Initialize backing store at last to avoid handling of |JSArrayBuffers| that
19662 // are currently being constructed in the |ArrayBufferTracker|. The
19663 // registration method below handles the case of registering a buffer that has
19664 // already been promoted.
19665 array_buffer->set_backing_store(data);
19666
19667 if (data && !is_external) {
19668 isolate->heap()->RegisterNewArrayBuffer(*array_buffer);
19669 }
19670}
19671
19672
19673bool JSArrayBuffer::SetupAllocatingData(Handle<JSArrayBuffer> array_buffer,
19674 Isolate* isolate,
19675 size_t allocated_length,
19676 bool initialize, SharedFlag shared) {
19677 void* data;
19678 CHECK(isolate->array_buffer_allocator() != NULL);
19679 // Prevent creating array buffers when serializing.
19680 DCHECK(!isolate->serializer_enabled());
19681 if (allocated_length != 0) {
19682 if (initialize) {
19683 data = isolate->array_buffer_allocator()->Allocate(allocated_length);
19684 } else {
19685 data = isolate->array_buffer_allocator()->AllocateUninitialized(
19686 allocated_length);
19687 }
19688 if (data == NULL) return false;
19689 } else {
19690 data = NULL;
19691 }
19692
19693 JSArrayBuffer::Setup(array_buffer, isolate, false, data, allocated_length,
19694 shared);
19695 return true;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000019696}
19697
19698
19699Handle<JSArrayBuffer> JSTypedArray::MaterializeArrayBuffer(
19700 Handle<JSTypedArray> typed_array) {
19701
19702 Handle<Map> map(typed_array->map());
19703 Isolate* isolate = typed_array->GetIsolate();
19704
19705 DCHECK(IsFixedTypedArrayElementsKind(map->elements_kind()));
19706
Ben Murdochb8a8cc12014-11-26 15:28:44 +000019707 Handle<FixedTypedArrayBase> fixed_typed_array(
19708 FixedTypedArrayBase::cast(typed_array->elements()));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000019709
19710 Handle<JSArrayBuffer> buffer(JSArrayBuffer::cast(typed_array->buffer()),
19711 isolate);
19712 void* backing_store =
19713 isolate->array_buffer_allocator()->AllocateUninitialized(
19714 fixed_typed_array->DataSize());
19715 buffer->set_is_external(false);
19716 DCHECK(buffer->byte_length()->IsSmi() ||
19717 buffer->byte_length()->IsHeapNumber());
19718 DCHECK(NumberToInt32(buffer->byte_length()) == fixed_typed_array->DataSize());
19719 // Initialize backing store at last to avoid handling of |JSArrayBuffers| that
19720 // are currently being constructed in the |ArrayBufferTracker|. The
19721 // registration method below handles the case of registering a buffer that has
19722 // already been promoted.
19723 buffer->set_backing_store(backing_store);
19724 isolate->heap()->RegisterNewArrayBuffer(*buffer);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000019725 memcpy(buffer->backing_store(),
19726 fixed_typed_array->DataPtr(),
19727 fixed_typed_array->DataSize());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000019728 Handle<FixedTypedArrayBase> new_elements =
19729 isolate->factory()->NewFixedTypedArrayWithExternalPointer(
Ben Murdochb8a8cc12014-11-26 15:28:44 +000019730 fixed_typed_array->length(), typed_array->type(),
19731 static_cast<uint8_t*>(buffer->backing_store()));
19732
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000019733 typed_array->set_elements(*new_elements);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000019734
19735 return buffer;
19736}
19737
19738
19739Handle<JSArrayBuffer> JSTypedArray::GetBuffer() {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000019740 Handle<JSArrayBuffer> array_buffer(JSArrayBuffer::cast(buffer()),
19741 GetIsolate());
19742 if (array_buffer->was_neutered() ||
19743 array_buffer->backing_store() != nullptr) {
19744 return array_buffer;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000019745 }
19746 Handle<JSTypedArray> self(this);
19747 return MaterializeArrayBuffer(self);
19748}
19749
19750
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000019751Handle<PropertyCell> PropertyCell::InvalidateEntry(
19752 Handle<GlobalDictionary> dictionary, int entry) {
19753 Isolate* isolate = dictionary->GetIsolate();
19754 // Swap with a copy.
19755 DCHECK(dictionary->ValueAt(entry)->IsPropertyCell());
19756 Handle<PropertyCell> cell(PropertyCell::cast(dictionary->ValueAt(entry)));
19757 auto new_cell = isolate->factory()->NewPropertyCell();
19758 new_cell->set_value(cell->value());
19759 dictionary->ValueAtPut(entry, *new_cell);
19760 bool is_the_hole = cell->value()->IsTheHole();
19761 // Cell is officially mutable henceforth.
19762 PropertyDetails details = cell->property_details();
19763 details = details.set_cell_type(is_the_hole ? PropertyCellType::kInvalidated
19764 : PropertyCellType::kMutable);
19765 new_cell->set_property_details(details);
19766 // Old cell is ready for invalidation.
19767 if (is_the_hole) {
19768 cell->set_value(isolate->heap()->undefined_value());
19769 } else {
19770 cell->set_value(isolate->heap()->the_hole_value());
19771 }
19772 details = details.set_cell_type(PropertyCellType::kInvalidated);
19773 cell->set_property_details(details);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000019774 cell->dependent_code()->DeoptimizeDependentCodeGroup(
19775 isolate, DependentCode::kPropertyCellChangedGroup);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000019776 return new_cell;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000019777}
19778
19779
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000019780PropertyCellConstantType PropertyCell::GetConstantType() {
19781 if (value()->IsSmi()) return PropertyCellConstantType::kSmi;
19782 return PropertyCellConstantType::kStableMap;
19783}
19784
19785
19786static bool RemainsConstantType(Handle<PropertyCell> cell,
19787 Handle<Object> value) {
19788 // TODO(dcarney): double->smi and smi->double transition from kConstant
19789 if (cell->value()->IsSmi() && value->IsSmi()) {
19790 return true;
19791 } else if (cell->value()->IsHeapObject() && value->IsHeapObject()) {
19792 return HeapObject::cast(cell->value())->map() ==
19793 HeapObject::cast(*value)->map() &&
19794 HeapObject::cast(*value)->map()->is_stable();
Emily Bernierd0a1eb72015-03-24 16:35:39 -040019795 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000019796 return false;
19797}
19798
19799
19800PropertyCellType PropertyCell::UpdatedType(Handle<PropertyCell> cell,
19801 Handle<Object> value,
19802 PropertyDetails details) {
19803 PropertyCellType type = details.cell_type();
19804 DCHECK(!value->IsTheHole());
19805 if (cell->value()->IsTheHole()) {
19806 switch (type) {
19807 // Only allow a cell to transition once into constant state.
19808 case PropertyCellType::kUninitialized:
19809 if (value->IsUndefined()) return PropertyCellType::kUndefined;
19810 return PropertyCellType::kConstant;
19811 case PropertyCellType::kInvalidated:
19812 return PropertyCellType::kMutable;
19813 default:
19814 UNREACHABLE();
19815 return PropertyCellType::kMutable;
19816 }
19817 }
19818 switch (type) {
19819 case PropertyCellType::kUndefined:
19820 return PropertyCellType::kConstant;
19821 case PropertyCellType::kConstant:
19822 if (*value == cell->value()) return PropertyCellType::kConstant;
19823 // Fall through.
19824 case PropertyCellType::kConstantType:
19825 if (RemainsConstantType(cell, value)) {
19826 return PropertyCellType::kConstantType;
19827 }
19828 // Fall through.
19829 case PropertyCellType::kMutable:
19830 return PropertyCellType::kMutable;
19831 }
19832 UNREACHABLE();
19833 return PropertyCellType::kMutable;
19834}
19835
19836
19837void PropertyCell::UpdateCell(Handle<GlobalDictionary> dictionary, int entry,
19838 Handle<Object> value, PropertyDetails details) {
19839 DCHECK(!value->IsTheHole());
19840 DCHECK(dictionary->ValueAt(entry)->IsPropertyCell());
19841 Handle<PropertyCell> cell(PropertyCell::cast(dictionary->ValueAt(entry)));
19842 const PropertyDetails original_details = cell->property_details();
19843 // Data accesses could be cached in ics or optimized code.
19844 bool invalidate =
19845 original_details.kind() == kData && details.kind() == kAccessor;
19846 int index = original_details.dictionary_index();
19847 PropertyCellType old_type = original_details.cell_type();
19848 // Preserve the enumeration index unless the property was deleted or never
19849 // initialized.
19850 if (cell->value()->IsTheHole()) {
19851 index = dictionary->NextEnumerationIndex();
19852 dictionary->SetNextEnumerationIndex(index + 1);
19853 // Negative lookup cells must be invalidated.
19854 invalidate = true;
19855 }
19856 DCHECK(index > 0);
19857 details = details.set_index(index);
19858
19859 PropertyCellType new_type = UpdatedType(cell, value, original_details);
19860 if (invalidate) cell = PropertyCell::InvalidateEntry(dictionary, entry);
19861
19862 // Install new property details and cell value.
19863 details = details.set_cell_type(new_type);
19864 cell->set_property_details(details);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000019865 cell->set_value(*value);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000019866
19867 // Deopt when transitioning from a constant type.
19868 if (!invalidate && (old_type != new_type ||
19869 original_details.IsReadOnly() != details.IsReadOnly())) {
19870 Isolate* isolate = dictionary->GetIsolate();
19871 cell->dependent_code()->DeoptimizeDependentCodeGroup(
19872 isolate, DependentCode::kPropertyCellChangedGroup);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000019873 }
19874}
19875
19876
19877// static
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000019878void PropertyCell::SetValueWithInvalidation(Handle<PropertyCell> cell,
19879 Handle<Object> new_value) {
19880 if (cell->value() != *new_value) {
19881 cell->set_value(*new_value);
19882 Isolate* isolate = cell->GetIsolate();
19883 cell->dependent_code()->DeoptimizeDependentCodeGroup(
19884 isolate, DependentCode::kPropertyCellChangedGroup);
19885 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +000019886}
19887
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000019888} // namespace internal
19889} // namespace v8