blob: addf97a0e41d5afec575890fcf92036bd4c019ca [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 Murdochda12d292016-06-02 14:46:10 +010011#include "src/objects-inl.h"
12
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013#include "src/accessors.h"
14#include "src/allocation-site-scopes.h"
Ben Murdochda12d292016-06-02 14:46:10 +010015#include "src/api-arguments.h"
Ben Murdoch097c5b22016-05-18 11:27:45 +010016#include "src/api-natives.h"
Ben Murdochc5610432016-08-08 18:44:38 +010017#include "src/api.h"
Ben Murdochb8a8cc12014-11-26 15:28:44 +000018#include "src/base/bits.h"
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000019#include "src/base/utils/random-number-generator.h"
Ben Murdochb8a8cc12014-11-26 15:28:44 +000020#include "src/bootstrapper.h"
21#include "src/code-stubs.h"
22#include "src/codegen.h"
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000023#include "src/compilation-dependencies.h"
24#include "src/compiler.h"
Ben Murdochc5610432016-08-08 18:44:38 +010025#include "src/counters-inl.h"
26#include "src/counters.h"
Ben Murdochb8a8cc12014-11-26 15:28:44 +000027#include "src/date.h"
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000028#include "src/debug/debug.h"
Ben Murdochb8a8cc12014-11-26 15:28:44 +000029#include "src/deoptimizer.h"
30#include "src/elements.h"
31#include "src/execution.h"
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000032#include "src/field-index-inl.h"
Ben Murdoch097c5b22016-05-18 11:27:45 +010033#include "src/field-index.h"
34#include "src/field-type.h"
Ben Murdochc5610432016-08-08 18:44:38 +010035#include "src/frames-inl.h"
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000036#include "src/full-codegen/full-codegen.h"
Ben Murdochb8a8cc12014-11-26 15:28:44 +000037#include "src/ic/ic.h"
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000038#include "src/identity-map.h"
Ben Murdochda12d292016-06-02 14:46:10 +010039#include "src/interpreter/bytecode-array-iterator.h"
40#include "src/interpreter/interpreter.h"
Ben Murdoch097c5b22016-05-18 11:27:45 +010041#include "src/interpreter/source-position-table.h"
Ben Murdochb8a8cc12014-11-26 15:28:44 +000042#include "src/isolate-inl.h"
Ben Murdochda12d292016-06-02 14:46:10 +010043#include "src/keys.h"
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000044#include "src/list.h"
Ben Murdochb8a8cc12014-11-26 15:28:44 +000045#include "src/log.h"
46#include "src/lookup.h"
47#include "src/macro-assembler.h"
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000048#include "src/messages.h"
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000049#include "src/objects-body-descriptors-inl.h"
50#include "src/profiler/cpu-profiler.h"
51#include "src/property-descriptor.h"
Ben Murdochb8a8cc12014-11-26 15:28:44 +000052#include "src/prototype.h"
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000053#include "src/regexp/jsregexp.h"
Ben Murdochb8a8cc12014-11-26 15:28:44 +000054#include "src/safepoint-table.h"
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000055#include "src/string-builder.h"
Ben Murdochb8a8cc12014-11-26 15:28:44 +000056#include "src/string-search.h"
57#include "src/string-stream.h"
58#include "src/utils.h"
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000059#include "src/zone.h"
Steve Blocka7e24c12009-10-30 11:49:00 +000060
61#ifdef ENABLE_DISASSEMBLER
Ben Murdochb8a8cc12014-11-26 15:28:44 +000062#include "src/disasm.h"
63#include "src/disassembler.h"
Steve Blocka7e24c12009-10-30 11:49:00 +000064#endif
65
Steve Blocka7e24c12009-10-30 11:49:00 +000066namespace v8 {
67namespace internal {
68
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000069std::ostream& operator<<(std::ostream& os, InstanceType instance_type) {
70 switch (instance_type) {
71#define WRITE_TYPE(TYPE) \
72 case TYPE: \
73 return os << #TYPE;
74 INSTANCE_TYPE_LIST(WRITE_TYPE)
75#undef WRITE_TYPE
76 }
77 UNREACHABLE();
78 return os << "UNKNOWN"; // Keep the compiler happy.
79}
80
Ben Murdoch097c5b22016-05-18 11:27:45 +010081Handle<FieldType> Object::OptimalType(Isolate* isolate,
82 Representation representation) {
83 if (representation.IsNone()) return FieldType::None(isolate);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000084 if (FLAG_track_field_types) {
85 if (representation.IsHeapObject() && IsHeapObject()) {
86 // We can track only JavaScript objects with stable maps.
87 Handle<Map> map(HeapObject::cast(this)->map(), isolate);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000088 if (map->is_stable() && map->IsJSReceiverMap()) {
Ben Murdoch097c5b22016-05-18 11:27:45 +010089 return FieldType::Class(map, isolate);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000090 }
91 }
92 }
Ben Murdoch097c5b22016-05-18 11:27:45 +010093 return FieldType::Any(isolate);
Ben Murdoch3ef787d2012-04-12 10:51:47 +010094}
95
Steve Blocka7e24c12009-10-30 11:49:00 +000096
Ben Murdochb8a8cc12014-11-26 15:28:44 +000097MaybeHandle<JSReceiver> Object::ToObject(Isolate* isolate,
98 Handle<Object> object,
99 Handle<Context> native_context) {
100 if (object->IsJSReceiver()) return Handle<JSReceiver>::cast(object);
101 Handle<JSFunction> constructor;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000102 if (object->IsSmi()) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000103 constructor = handle(native_context->number_function(), isolate);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000104 } else {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000105 int constructor_function_index =
106 Handle<HeapObject>::cast(object)->map()->GetConstructorFunctionIndex();
107 if (constructor_function_index == Map::kNoConstructorFunctionIndex) {
Ben Murdoch097c5b22016-05-18 11:27:45 +0100108 THROW_NEW_ERROR(isolate,
109 NewTypeError(MessageTemplate::kUndefinedOrNullToObject),
110 JSReceiver);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000111 }
112 constructor = handle(
113 JSFunction::cast(native_context->get(constructor_function_index)),
114 isolate);
John Reck59135872010-11-02 12:39:01 -0700115 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000116 Handle<JSObject> result = isolate->factory()->NewJSObject(constructor);
117 Handle<JSValue>::cast(result)->set_value(*object);
Steve Blocka7e24c12009-10-30 11:49:00 +0000118 return result;
119}
120
Ben Murdochda12d292016-06-02 14:46:10 +0100121// ES6 section 9.2.1.2, OrdinaryCallBindThis for sloppy callee.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000122// static
Ben Murdochda12d292016-06-02 14:46:10 +0100123MaybeHandle<JSReceiver> Object::ConvertReceiver(Isolate* isolate,
124 Handle<Object> object) {
125 if (object->IsJSReceiver()) return Handle<JSReceiver>::cast(object);
126 if (*object == isolate->heap()->null_value() ||
127 *object == isolate->heap()->undefined_value()) {
Ben Murdochc5610432016-08-08 18:44:38 +0100128 return isolate->global_proxy();
Ben Murdochda12d292016-06-02 14:46:10 +0100129 }
130 return Object::ToObject(isolate, object);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000131}
132
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000133// static
134MaybeHandle<Object> Object::ToNumber(Handle<Object> input) {
135 while (true) {
136 if (input->IsNumber()) {
137 return input;
138 }
139 if (input->IsString()) {
140 return String::ToNumber(Handle<String>::cast(input));
141 }
142 if (input->IsOddball()) {
143 return Oddball::ToNumber(Handle<Oddball>::cast(input));
144 }
145 Isolate* const isolate = Handle<HeapObject>::cast(input)->GetIsolate();
146 if (input->IsSymbol()) {
147 THROW_NEW_ERROR(isolate, NewTypeError(MessageTemplate::kSymbolToNumber),
148 Object);
149 }
150 if (input->IsSimd128Value()) {
151 THROW_NEW_ERROR(isolate, NewTypeError(MessageTemplate::kSimdToNumber),
152 Object);
153 }
154 ASSIGN_RETURN_ON_EXCEPTION(
155 isolate, input, JSReceiver::ToPrimitive(Handle<JSReceiver>::cast(input),
156 ToPrimitiveHint::kNumber),
157 Object);
158 }
159}
160
161
162// static
163MaybeHandle<Object> Object::ToInteger(Isolate* isolate, Handle<Object> input) {
164 ASSIGN_RETURN_ON_EXCEPTION(isolate, input, ToNumber(input), Object);
165 return isolate->factory()->NewNumber(DoubleToInteger(input->Number()));
166}
167
168
169// static
170MaybeHandle<Object> Object::ToInt32(Isolate* isolate, Handle<Object> input) {
171 ASSIGN_RETURN_ON_EXCEPTION(isolate, input, ToNumber(input), Object);
172 return isolate->factory()->NewNumberFromInt(DoubleToInt32(input->Number()));
173}
174
175
176// static
177MaybeHandle<Object> Object::ToUint32(Isolate* isolate, Handle<Object> input) {
178 ASSIGN_RETURN_ON_EXCEPTION(isolate, input, ToNumber(input), Object);
179 return isolate->factory()->NewNumberFromUint(DoubleToUint32(input->Number()));
180}
181
182
183// static
Ben Murdochda12d292016-06-02 14:46:10 +0100184MaybeHandle<Name> Object::ConvertToName(Isolate* isolate,
185 Handle<Object> input) {
186 ASSIGN_RETURN_ON_EXCEPTION(
187 isolate, input, Object::ToPrimitive(input, ToPrimitiveHint::kString),
188 Name);
189 if (input->IsName()) return Handle<Name>::cast(input);
190 return ToString(isolate, input);
191}
192
193// static
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000194MaybeHandle<String> Object::ToString(Isolate* isolate, Handle<Object> input) {
195 while (true) {
196 if (input->IsString()) {
197 return Handle<String>::cast(input);
198 }
199 if (input->IsOddball()) {
200 return handle(Handle<Oddball>::cast(input)->to_string(), isolate);
201 }
202 if (input->IsNumber()) {
203 return isolate->factory()->NumberToString(input);
204 }
205 if (input->IsSymbol()) {
206 THROW_NEW_ERROR(isolate, NewTypeError(MessageTemplate::kSymbolToString),
207 String);
208 }
209 if (input->IsSimd128Value()) {
210 return Simd128Value::ToString(Handle<Simd128Value>::cast(input));
211 }
212 ASSIGN_RETURN_ON_EXCEPTION(
213 isolate, input, JSReceiver::ToPrimitive(Handle<JSReceiver>::cast(input),
214 ToPrimitiveHint::kString),
215 String);
216 }
217}
218
219
220// static
221MaybeHandle<Object> Object::ToLength(Isolate* isolate, Handle<Object> input) {
222 ASSIGN_RETURN_ON_EXCEPTION(isolate, input, ToNumber(input), Object);
223 double len = DoubleToInteger(input->Number());
224 if (len <= 0.0) {
225 len = 0.0;
226 } else if (len >= kMaxSafeInteger) {
227 len = kMaxSafeInteger;
228 }
229 return isolate->factory()->NewNumber(len);
230}
231
232
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000233bool Object::BooleanValue() {
234 if (IsBoolean()) return IsTrue();
235 if (IsSmi()) return Smi::cast(this)->value() != 0;
236 if (IsUndefined() || IsNull()) return false;
Ben Murdochda12d292016-06-02 14:46:10 +0100237 if (IsUndetectable()) return false; // Undetectable object is false.
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000238 if (IsString()) return String::cast(this)->length() != 0;
239 if (IsHeapNumber()) return HeapNumber::cast(this)->HeapNumberBooleanValue();
240 return true;
Steve Blocka7e24c12009-10-30 11:49:00 +0000241}
242
243
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000244namespace {
245
246// TODO(bmeurer): Maybe we should introduce a marker interface Number,
247// where we put all these methods at some point?
248ComparisonResult NumberCompare(double x, double y) {
249 if (std::isnan(x) || std::isnan(y)) {
250 return ComparisonResult::kUndefined;
251 } else if (x < y) {
252 return ComparisonResult::kLessThan;
253 } else if (x > y) {
254 return ComparisonResult::kGreaterThan;
255 } else {
256 return ComparisonResult::kEqual;
Steve Blocka7e24c12009-10-30 11:49:00 +0000257 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000258}
259
260
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000261bool NumberEquals(double x, double y) {
262 // Must check explicitly for NaN's on Windows, but -0 works fine.
263 if (std::isnan(x)) return false;
264 if (std::isnan(y)) return false;
265 return x == y;
266}
267
268
269bool NumberEquals(const Object* x, const Object* y) {
270 return NumberEquals(x->Number(), y->Number());
271}
272
273
274bool NumberEquals(Handle<Object> x, Handle<Object> y) {
275 return NumberEquals(*x, *y);
276}
277
278} // namespace
279
280
281// static
Ben Murdoch097c5b22016-05-18 11:27:45 +0100282Maybe<ComparisonResult> Object::Compare(Handle<Object> x, Handle<Object> y) {
283 // ES6 section 7.2.11 Abstract Relational Comparison step 3 and 4.
284 if (!Object::ToPrimitive(x, ToPrimitiveHint::kNumber).ToHandle(&x) ||
285 !Object::ToPrimitive(y, ToPrimitiveHint::kNumber).ToHandle(&y)) {
286 return Nothing<ComparisonResult>();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000287 }
288 if (x->IsString() && y->IsString()) {
289 // ES6 section 7.2.11 Abstract Relational Comparison step 5.
290 return Just(
291 String::Compare(Handle<String>::cast(x), Handle<String>::cast(y)));
292 }
293 // ES6 section 7.2.11 Abstract Relational Comparison step 6.
Ben Murdoch097c5b22016-05-18 11:27:45 +0100294 if (!Object::ToNumber(x).ToHandle(&x) || !Object::ToNumber(y).ToHandle(&y)) {
295 return Nothing<ComparisonResult>();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000296 }
297 return Just(NumberCompare(x->Number(), y->Number()));
298}
299
300
301// static
302Maybe<bool> Object::Equals(Handle<Object> x, Handle<Object> y) {
Ben Murdochda12d292016-06-02 14:46:10 +0100303 // This is the generic version of Abstract Equality Comparison; a version in
304 // JavaScript land is available in the EqualStub and NotEqualStub. Whenever
305 // you change something functionality wise in here, remember to update the
306 // TurboFan code stubs as well.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000307 while (true) {
308 if (x->IsNumber()) {
309 if (y->IsNumber()) {
310 return Just(NumberEquals(x, y));
311 } else if (y->IsBoolean()) {
312 return Just(NumberEquals(*x, Handle<Oddball>::cast(y)->to_number()));
313 } else if (y->IsString()) {
314 return Just(NumberEquals(x, String::ToNumber(Handle<String>::cast(y))));
Ben Murdochda12d292016-06-02 14:46:10 +0100315 } else if (y->IsJSReceiver()) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000316 if (!JSReceiver::ToPrimitive(Handle<JSReceiver>::cast(y))
317 .ToHandle(&y)) {
318 return Nothing<bool>();
319 }
320 } else {
321 return Just(false);
322 }
323 } else if (x->IsString()) {
324 if (y->IsString()) {
325 return Just(
326 String::Equals(Handle<String>::cast(x), Handle<String>::cast(y)));
327 } else if (y->IsNumber()) {
328 x = String::ToNumber(Handle<String>::cast(x));
329 return Just(NumberEquals(x, y));
330 } else if (y->IsBoolean()) {
331 x = String::ToNumber(Handle<String>::cast(x));
332 return Just(NumberEquals(*x, Handle<Oddball>::cast(y)->to_number()));
Ben Murdochda12d292016-06-02 14:46:10 +0100333 } else if (y->IsJSReceiver()) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000334 if (!JSReceiver::ToPrimitive(Handle<JSReceiver>::cast(y))
335 .ToHandle(&y)) {
336 return Nothing<bool>();
337 }
338 } else {
339 return Just(false);
340 }
341 } else if (x->IsBoolean()) {
342 if (y->IsOddball()) {
343 return Just(x.is_identical_to(y));
344 } else if (y->IsNumber()) {
345 return Just(NumberEquals(Handle<Oddball>::cast(x)->to_number(), *y));
346 } else if (y->IsString()) {
347 y = String::ToNumber(Handle<String>::cast(y));
348 return Just(NumberEquals(Handle<Oddball>::cast(x)->to_number(), *y));
Ben Murdochda12d292016-06-02 14:46:10 +0100349 } else if (y->IsJSReceiver()) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000350 if (!JSReceiver::ToPrimitive(Handle<JSReceiver>::cast(y))
351 .ToHandle(&y)) {
352 return Nothing<bool>();
353 }
354 x = Oddball::ToNumber(Handle<Oddball>::cast(x));
355 } else {
356 return Just(false);
357 }
358 } else if (x->IsSymbol()) {
359 if (y->IsSymbol()) {
360 return Just(x.is_identical_to(y));
Ben Murdochda12d292016-06-02 14:46:10 +0100361 } else if (y->IsJSReceiver()) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000362 if (!JSReceiver::ToPrimitive(Handle<JSReceiver>::cast(y))
363 .ToHandle(&y)) {
364 return Nothing<bool>();
365 }
366 } else {
367 return Just(false);
368 }
369 } else if (x->IsSimd128Value()) {
370 if (y->IsSimd128Value()) {
371 return Just(Simd128Value::Equals(Handle<Simd128Value>::cast(x),
372 Handle<Simd128Value>::cast(y)));
Ben Murdochda12d292016-06-02 14:46:10 +0100373 } else if (y->IsJSReceiver()) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000374 if (!JSReceiver::ToPrimitive(Handle<JSReceiver>::cast(y))
375 .ToHandle(&y)) {
376 return Nothing<bool>();
377 }
378 } else {
379 return Just(false);
380 }
Ben Murdochda12d292016-06-02 14:46:10 +0100381 } else if (x->IsJSReceiver()) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000382 if (y->IsJSReceiver()) {
383 return Just(x.is_identical_to(y));
Ben Murdochda12d292016-06-02 14:46:10 +0100384 } else if (y->IsUndetectable()) {
385 return Just(x->IsUndetectable());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000386 } else if (y->IsBoolean()) {
387 y = Oddball::ToNumber(Handle<Oddball>::cast(y));
388 } else if (!JSReceiver::ToPrimitive(Handle<JSReceiver>::cast(x))
389 .ToHandle(&x)) {
390 return Nothing<bool>();
391 }
392 } else {
Ben Murdochda12d292016-06-02 14:46:10 +0100393 return Just(x->IsUndetectable() && y->IsUndetectable());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000394 }
395 }
396}
397
398
399bool Object::StrictEquals(Object* that) {
400 if (this->IsNumber()) {
401 if (!that->IsNumber()) return false;
402 return NumberEquals(this, that);
403 } else if (this->IsString()) {
404 if (!that->IsString()) return false;
405 return String::cast(this)->Equals(String::cast(that));
406 } else if (this->IsSimd128Value()) {
407 if (!that->IsSimd128Value()) return false;
408 return Simd128Value::cast(this)->Equals(Simd128Value::cast(that));
409 }
410 return this == that;
411}
412
413
414// static
415Handle<String> Object::TypeOf(Isolate* isolate, Handle<Object> object) {
416 if (object->IsNumber()) return isolate->factory()->number_string();
Ben Murdoch097c5b22016-05-18 11:27:45 +0100417 if (object->IsOddball()) return handle(Oddball::cast(*object)->type_of());
Ben Murdochda12d292016-06-02 14:46:10 +0100418 if (object->IsUndetectable()) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000419 return isolate->factory()->undefined_string();
420 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000421 if (object->IsString()) return isolate->factory()->string_string();
422 if (object->IsSymbol()) return isolate->factory()->symbol_string();
423 if (object->IsString()) return isolate->factory()->string_string();
424#define SIMD128_TYPE(TYPE, Type, type, lane_count, lane_type) \
425 if (object->Is##Type()) return isolate->factory()->type##_string();
426 SIMD128_TYPES(SIMD128_TYPE)
427#undef SIMD128_TYPE
428 if (object->IsCallable()) return isolate->factory()->function_string();
429 return isolate->factory()->object_string();
430}
431
432
433// static
434MaybeHandle<Object> Object::Multiply(Isolate* isolate, Handle<Object> lhs,
Ben Murdoch097c5b22016-05-18 11:27:45 +0100435 Handle<Object> rhs) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000436 if (!lhs->IsNumber() || !rhs->IsNumber()) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000437 ASSIGN_RETURN_ON_EXCEPTION(isolate, lhs, Object::ToNumber(lhs), Object);
438 ASSIGN_RETURN_ON_EXCEPTION(isolate, rhs, Object::ToNumber(rhs), Object);
439 }
440 return isolate->factory()->NewNumber(lhs->Number() * rhs->Number());
441}
442
443
444// static
445MaybeHandle<Object> Object::Divide(Isolate* isolate, Handle<Object> lhs,
Ben Murdoch097c5b22016-05-18 11:27:45 +0100446 Handle<Object> rhs) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000447 if (!lhs->IsNumber() || !rhs->IsNumber()) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000448 ASSIGN_RETURN_ON_EXCEPTION(isolate, lhs, Object::ToNumber(lhs), Object);
449 ASSIGN_RETURN_ON_EXCEPTION(isolate, rhs, Object::ToNumber(rhs), Object);
450 }
451 return isolate->factory()->NewNumber(lhs->Number() / rhs->Number());
452}
453
454
455// static
456MaybeHandle<Object> Object::Modulus(Isolate* isolate, Handle<Object> lhs,
Ben Murdoch097c5b22016-05-18 11:27:45 +0100457 Handle<Object> rhs) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000458 if (!lhs->IsNumber() || !rhs->IsNumber()) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000459 ASSIGN_RETURN_ON_EXCEPTION(isolate, lhs, Object::ToNumber(lhs), Object);
460 ASSIGN_RETURN_ON_EXCEPTION(isolate, rhs, Object::ToNumber(rhs), Object);
461 }
462 return isolate->factory()->NewNumber(modulo(lhs->Number(), rhs->Number()));
463}
464
465
466// static
467MaybeHandle<Object> Object::Add(Isolate* isolate, Handle<Object> lhs,
Ben Murdoch097c5b22016-05-18 11:27:45 +0100468 Handle<Object> rhs) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000469 if (lhs->IsNumber() && rhs->IsNumber()) {
470 return isolate->factory()->NewNumber(lhs->Number() + rhs->Number());
471 } else if (lhs->IsString() && rhs->IsString()) {
472 return isolate->factory()->NewConsString(Handle<String>::cast(lhs),
473 Handle<String>::cast(rhs));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000474 }
475 ASSIGN_RETURN_ON_EXCEPTION(isolate, lhs, Object::ToPrimitive(lhs), Object);
476 ASSIGN_RETURN_ON_EXCEPTION(isolate, rhs, Object::ToPrimitive(rhs), Object);
477 if (lhs->IsString() || rhs->IsString()) {
478 ASSIGN_RETURN_ON_EXCEPTION(isolate, rhs, Object::ToString(isolate, rhs),
479 Object);
480 ASSIGN_RETURN_ON_EXCEPTION(isolate, lhs, Object::ToString(isolate, lhs),
481 Object);
482 return isolate->factory()->NewConsString(Handle<String>::cast(lhs),
483 Handle<String>::cast(rhs));
484 }
485 ASSIGN_RETURN_ON_EXCEPTION(isolate, rhs, Object::ToNumber(rhs), Object);
486 ASSIGN_RETURN_ON_EXCEPTION(isolate, lhs, Object::ToNumber(lhs), Object);
487 return isolate->factory()->NewNumber(lhs->Number() + rhs->Number());
488}
489
490
491// static
492MaybeHandle<Object> Object::Subtract(Isolate* isolate, Handle<Object> lhs,
Ben Murdoch097c5b22016-05-18 11:27:45 +0100493 Handle<Object> rhs) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000494 if (!lhs->IsNumber() || !rhs->IsNumber()) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000495 ASSIGN_RETURN_ON_EXCEPTION(isolate, lhs, Object::ToNumber(lhs), Object);
496 ASSIGN_RETURN_ON_EXCEPTION(isolate, rhs, Object::ToNumber(rhs), Object);
497 }
498 return isolate->factory()->NewNumber(lhs->Number() - rhs->Number());
499}
500
501
502// static
503MaybeHandle<Object> Object::ShiftLeft(Isolate* isolate, Handle<Object> lhs,
Ben Murdoch097c5b22016-05-18 11:27:45 +0100504 Handle<Object> rhs) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000505 if (!lhs->IsNumber() || !rhs->IsNumber()) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000506 ASSIGN_RETURN_ON_EXCEPTION(isolate, lhs, Object::ToNumber(lhs), Object);
507 ASSIGN_RETURN_ON_EXCEPTION(isolate, rhs, Object::ToNumber(rhs), Object);
508 }
509 return isolate->factory()->NewNumberFromInt(NumberToInt32(*lhs)
510 << (NumberToUint32(*rhs) & 0x1F));
511}
512
513
514// static
515MaybeHandle<Object> Object::ShiftRight(Isolate* isolate, Handle<Object> lhs,
Ben Murdoch097c5b22016-05-18 11:27:45 +0100516 Handle<Object> rhs) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000517 if (!lhs->IsNumber() || !rhs->IsNumber()) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000518 ASSIGN_RETURN_ON_EXCEPTION(isolate, lhs, Object::ToNumber(lhs), Object);
519 ASSIGN_RETURN_ON_EXCEPTION(isolate, rhs, Object::ToNumber(rhs), Object);
520 }
521 return isolate->factory()->NewNumberFromInt(NumberToInt32(*lhs) >>
522 (NumberToUint32(*rhs) & 0x1F));
523}
524
525
526// static
527MaybeHandle<Object> Object::ShiftRightLogical(Isolate* isolate,
528 Handle<Object> lhs,
Ben Murdoch097c5b22016-05-18 11:27:45 +0100529 Handle<Object> rhs) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000530 if (!lhs->IsNumber() || !rhs->IsNumber()) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000531 ASSIGN_RETURN_ON_EXCEPTION(isolate, lhs, Object::ToNumber(lhs), Object);
532 ASSIGN_RETURN_ON_EXCEPTION(isolate, rhs, Object::ToNumber(rhs), Object);
533 }
534 return isolate->factory()->NewNumberFromUint(NumberToUint32(*lhs) >>
535 (NumberToUint32(*rhs) & 0x1F));
536}
537
538
539// static
540MaybeHandle<Object> Object::BitwiseAnd(Isolate* isolate, Handle<Object> lhs,
Ben Murdoch097c5b22016-05-18 11:27:45 +0100541 Handle<Object> rhs) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000542 if (!lhs->IsNumber() || !rhs->IsNumber()) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000543 ASSIGN_RETURN_ON_EXCEPTION(isolate, lhs, Object::ToNumber(lhs), Object);
544 ASSIGN_RETURN_ON_EXCEPTION(isolate, rhs, Object::ToNumber(rhs), Object);
545 }
546 return isolate->factory()->NewNumberFromInt(NumberToInt32(*lhs) &
547 NumberToInt32(*rhs));
548}
549
550
551// static
552MaybeHandle<Object> Object::BitwiseOr(Isolate* isolate, Handle<Object> lhs,
Ben Murdoch097c5b22016-05-18 11:27:45 +0100553 Handle<Object> rhs) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000554 if (!lhs->IsNumber() || !rhs->IsNumber()) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000555 ASSIGN_RETURN_ON_EXCEPTION(isolate, lhs, Object::ToNumber(lhs), Object);
556 ASSIGN_RETURN_ON_EXCEPTION(isolate, rhs, Object::ToNumber(rhs), Object);
557 }
558 return isolate->factory()->NewNumberFromInt(NumberToInt32(*lhs) |
559 NumberToInt32(*rhs));
560}
561
562
563// static
564MaybeHandle<Object> Object::BitwiseXor(Isolate* isolate, Handle<Object> lhs,
Ben Murdoch097c5b22016-05-18 11:27:45 +0100565 Handle<Object> rhs) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000566 if (!lhs->IsNumber() || !rhs->IsNumber()) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000567 ASSIGN_RETURN_ON_EXCEPTION(isolate, lhs, Object::ToNumber(lhs), Object);
568 ASSIGN_RETURN_ON_EXCEPTION(isolate, rhs, Object::ToNumber(rhs), Object);
569 }
570 return isolate->factory()->NewNumberFromInt(NumberToInt32(*lhs) ^
571 NumberToInt32(*rhs));
572}
573
Ben Murdochc5610432016-08-08 18:44:38 +0100574// static
575MaybeHandle<Object> Object::OrdinaryHasInstance(Isolate* isolate,
576 Handle<Object> callable,
577 Handle<Object> object) {
578 // The {callable} must have a [[Call]] internal method.
579 if (!callable->IsCallable()) return isolate->factory()->false_value();
580
581 // Check if {callable} is a bound function, and if so retrieve its
582 // [[BoundTargetFunction]] and use that instead of {callable}.
583 if (callable->IsJSBoundFunction()) {
584 Handle<Object> bound_callable(
585 Handle<JSBoundFunction>::cast(callable)->bound_target_function(),
586 isolate);
587 return Object::InstanceOf(isolate, object, bound_callable);
588 }
589
590 // If {object} is not a receiver, return false.
591 if (!object->IsJSReceiver()) return isolate->factory()->false_value();
592
593 // Get the "prototype" of {callable}; raise an error if it's not a receiver.
594 Handle<Object> prototype;
595 ASSIGN_RETURN_ON_EXCEPTION(
596 isolate, prototype,
597 Object::GetProperty(callable, isolate->factory()->prototype_string()),
598 Object);
599 if (!prototype->IsJSReceiver()) {
600 THROW_NEW_ERROR(
601 isolate,
602 NewTypeError(MessageTemplate::kInstanceofNonobjectProto, prototype),
603 Object);
604 }
605
606 // Return whether or not {prototype} is in the prototype chain of {object}.
607 Maybe<bool> result = JSReceiver::HasInPrototypeChain(
608 isolate, Handle<JSReceiver>::cast(object), prototype);
609 if (result.IsNothing()) return MaybeHandle<Object>();
610 return isolate->factory()->ToBoolean(result.FromJust());
611}
612
613// static
614MaybeHandle<Object> Object::InstanceOf(Isolate* isolate, Handle<Object> object,
615 Handle<Object> callable) {
616 if (FLAG_harmony_instanceof) {
617 // The {callable} must be a receiver.
618 if (!callable->IsJSReceiver()) {
619 THROW_NEW_ERROR(
620 isolate, NewTypeError(MessageTemplate::kNonObjectInInstanceOfCheck),
621 Object);
622 }
623
624 // Lookup the @@hasInstance method on {callable}.
625 Handle<Object> inst_of_handler;
626 ASSIGN_RETURN_ON_EXCEPTION(
627 isolate, inst_of_handler,
628 JSReceiver::GetMethod(Handle<JSReceiver>::cast(callable),
629 isolate->factory()->has_instance_symbol()),
630 Object);
631 if (!inst_of_handler->IsUndefined()) {
632 // Call the {inst_of_handler} on the {callable}.
633 Handle<Object> result;
634 ASSIGN_RETURN_ON_EXCEPTION(
635 isolate, result,
636 Execution::Call(isolate, inst_of_handler, callable, 1, &object),
637 Object);
638 return isolate->factory()->ToBoolean(result->BooleanValue());
639 }
640 }
641
642 // The {callable} must have a [[Call]] internal method.
643 if (!callable->IsCallable()) {
644 THROW_NEW_ERROR(
645 isolate, NewTypeError(MessageTemplate::kNonCallableInInstanceOfCheck),
646 Object);
647 }
648
649 // Fall back to OrdinaryHasInstance with {callable} and {object}.
650 Handle<Object> result;
651 ASSIGN_RETURN_ON_EXCEPTION(
652 isolate, result,
653 JSReceiver::OrdinaryHasInstance(isolate, callable, object), Object);
654 return result;
655}
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000656
657Maybe<bool> Object::IsArray(Handle<Object> object) {
658 if (object->IsJSArray()) return Just(true);
659 if (object->IsJSProxy()) {
660 Handle<JSProxy> proxy = Handle<JSProxy>::cast(object);
661 Isolate* isolate = proxy->GetIsolate();
662 if (proxy->IsRevoked()) {
663 isolate->Throw(*isolate->factory()->NewTypeError(
664 MessageTemplate::kProxyRevoked,
665 isolate->factory()->NewStringFromAsciiChecked("IsArray")));
666 return Nothing<bool>();
667 }
668 return Object::IsArray(handle(proxy->target(), isolate));
669 }
670 return Just(false);
671}
672
673
674bool Object::IsPromise(Handle<Object> object) {
675 if (!object->IsJSObject()) return false;
676 auto js_object = Handle<JSObject>::cast(object);
677 // Promises can't have access checks.
678 if (js_object->map()->is_access_check_needed()) return false;
679 auto isolate = js_object->GetIsolate();
680 // TODO(dcarney): this should just be read from the symbol registry so as not
681 // to be context dependent.
Ben Murdochc5610432016-08-08 18:44:38 +0100682 auto key = isolate->factory()->promise_state_symbol();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000683 // Shouldn't be possible to throw here.
684 return JSObject::HasRealNamedProperty(js_object, key).FromJust();
685}
686
687
688// static
689MaybeHandle<Object> Object::GetMethod(Handle<JSReceiver> receiver,
690 Handle<Name> name) {
691 Handle<Object> func;
692 Isolate* isolate = receiver->GetIsolate();
693 ASSIGN_RETURN_ON_EXCEPTION(isolate, func,
694 JSReceiver::GetProperty(receiver, name), Object);
695 if (func->IsNull() || func->IsUndefined()) {
696 return isolate->factory()->undefined_value();
697 }
698 if (!func->IsCallable()) {
699 THROW_NEW_ERROR(isolate, NewTypeError(MessageTemplate::kPropertyNotFunction,
700 func, name, receiver),
701 Object);
702 }
703 return func;
704}
705
706
707// static
708MaybeHandle<FixedArray> Object::CreateListFromArrayLike(
709 Isolate* isolate, Handle<Object> object, ElementTypes element_types) {
710 // 1. ReturnIfAbrupt(object).
711 // 2. (default elementTypes -- not applicable.)
712 // 3. If Type(obj) is not Object, throw a TypeError exception.
713 if (!object->IsJSReceiver()) {
714 THROW_NEW_ERROR(isolate,
715 NewTypeError(MessageTemplate::kCalledOnNonObject,
716 isolate->factory()->NewStringFromAsciiChecked(
717 "CreateListFromArrayLike")),
718 FixedArray);
719 }
720 // 4. Let len be ? ToLength(? Get(obj, "length")).
Ben Murdochda12d292016-06-02 14:46:10 +0100721 Handle<JSReceiver> receiver = Handle<JSReceiver>::cast(object);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000722 Handle<Object> raw_length_obj;
723 ASSIGN_RETURN_ON_EXCEPTION(
724 isolate, raw_length_obj,
Ben Murdochda12d292016-06-02 14:46:10 +0100725 JSReceiver::GetProperty(receiver, isolate->factory()->length_string()),
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000726 FixedArray);
727 Handle<Object> raw_length_number;
728 ASSIGN_RETURN_ON_EXCEPTION(isolate, raw_length_number,
729 Object::ToLength(isolate, raw_length_obj),
730 FixedArray);
731 uint32_t len;
732 if (!raw_length_number->ToUint32(&len) ||
733 len > static_cast<uint32_t>(FixedArray::kMaxLength)) {
734 THROW_NEW_ERROR(isolate,
735 NewRangeError(MessageTemplate::kInvalidArrayLength),
736 FixedArray);
737 }
738 // 5. Let list be an empty List.
739 Handle<FixedArray> list = isolate->factory()->NewFixedArray(len);
740 // 6. Let index be 0.
741 // 7. Repeat while index < len:
742 for (uint32_t index = 0; index < len; ++index) {
743 // 7a. Let indexName be ToString(index).
744 // 7b. Let next be ? Get(obj, indexName).
745 Handle<Object> next;
Ben Murdochda12d292016-06-02 14:46:10 +0100746 ASSIGN_RETURN_ON_EXCEPTION(isolate, next,
747 JSReceiver::GetElement(isolate, receiver, index),
748 FixedArray);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000749 switch (element_types) {
750 case ElementTypes::kAll:
751 // Nothing to do.
752 break;
753 case ElementTypes::kStringAndSymbol: {
754 // 7c. If Type(next) is not an element of elementTypes, throw a
755 // TypeError exception.
756 if (!next->IsName()) {
757 THROW_NEW_ERROR(isolate,
758 NewTypeError(MessageTemplate::kNotPropertyName, next),
759 FixedArray);
760 }
761 // 7d. Append next as the last element of list.
762 // Internalize on the fly so we can use pointer identity later.
763 next = isolate->factory()->InternalizeName(Handle<Name>::cast(next));
764 break;
765 }
766 }
767 list->set(index, *next);
768 // 7e. Set index to index + 1. (See loop header.)
769 }
770 // 8. Return list.
771 return list;
772}
773
774
775// static
776Maybe<bool> JSReceiver::HasProperty(LookupIterator* it) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000777 for (; it->IsFound(); it->Next()) {
778 switch (it->state()) {
779 case LookupIterator::NOT_FOUND:
780 case LookupIterator::TRANSITION:
781 UNREACHABLE();
782 case LookupIterator::JSPROXY:
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000783 return JSProxy::HasProperty(it->isolate(), it->GetHolder<JSProxy>(),
784 it->GetName());
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000785 case LookupIterator::INTERCEPTOR: {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000786 Maybe<PropertyAttributes> result =
787 JSObject::GetPropertyAttributesWithInterceptor(it);
Ben Murdochda12d292016-06-02 14:46:10 +0100788 if (result.IsNothing()) return Nothing<bool>();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000789 if (result.FromJust() != ABSENT) return Just(true);
790 break;
791 }
792 case LookupIterator::ACCESS_CHECK: {
793 if (it->HasAccess()) break;
794 Maybe<PropertyAttributes> result =
795 JSObject::GetPropertyAttributesWithFailedAccessCheck(it);
Ben Murdochda12d292016-06-02 14:46:10 +0100796 if (result.IsNothing()) return Nothing<bool>();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000797 return Just(result.FromJust() != ABSENT);
798 }
799 case LookupIterator::INTEGER_INDEXED_EXOTIC:
800 // TypedArray out-of-bounds access.
801 return Just(false);
802 case LookupIterator::ACCESSOR:
803 case LookupIterator::DATA:
804 return Just(true);
805 }
806 }
807 return Just(false);
808}
809
810
811// static
Ben Murdoch097c5b22016-05-18 11:27:45 +0100812MaybeHandle<Object> Object::GetProperty(LookupIterator* it) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000813 for (; it->IsFound(); it->Next()) {
814 switch (it->state()) {
815 case LookupIterator::NOT_FOUND:
816 case LookupIterator::TRANSITION:
817 UNREACHABLE();
Ben Murdochda12d292016-06-02 14:46:10 +0100818 case LookupIterator::JSPROXY: {
819 bool was_found;
820 MaybeHandle<Object> result =
821 JSProxy::GetProperty(it->isolate(), it->GetHolder<JSProxy>(),
822 it->GetName(), it->GetReceiver(), &was_found);
823 if (!was_found) it->NotFound();
824 return result;
825 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000826 case LookupIterator::INTERCEPTOR: {
827 bool done;
828 Handle<Object> result;
829 ASSIGN_RETURN_ON_EXCEPTION(
830 it->isolate(), result,
831 JSObject::GetPropertyWithInterceptor(it, &done), Object);
832 if (done) return result;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000833 break;
834 }
835 case LookupIterator::ACCESS_CHECK:
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000836 if (it->HasAccess()) break;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000837 return JSObject::GetPropertyWithFailedAccessCheck(it);
838 case LookupIterator::ACCESSOR:
Ben Murdoch097c5b22016-05-18 11:27:45 +0100839 return GetPropertyWithAccessor(it);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000840 case LookupIterator::INTEGER_INDEXED_EXOTIC:
Ben Murdoch097c5b22016-05-18 11:27:45 +0100841 return ReadAbsentProperty(it);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000842 case LookupIterator::DATA:
843 return it->GetDataValue();
Ben Murdoch8b112d22011-06-08 16:22:53 +0100844 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000845 }
Ben Murdoch097c5b22016-05-18 11:27:45 +0100846 return ReadAbsentProperty(it);
Steve Blocka7e24c12009-10-30 11:49:00 +0000847}
848
849
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000850// static
851MaybeHandle<Object> JSProxy::GetProperty(Isolate* isolate,
852 Handle<JSProxy> proxy,
853 Handle<Name> name,
Ben Murdochda12d292016-06-02 14:46:10 +0100854 Handle<Object> receiver,
855 bool* was_found) {
856 *was_found = true;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000857 if (receiver->IsJSGlobalObject()) {
858 THROW_NEW_ERROR(
859 isolate,
860 NewTypeError(MessageTemplate::kReadGlobalReferenceThroughProxy, name),
861 Object);
862 }
863
864 DCHECK(!name->IsPrivate());
Ben Murdochc5610432016-08-08 18:44:38 +0100865 STACK_CHECK(isolate, MaybeHandle<Object>());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000866 Handle<Name> trap_name = isolate->factory()->get_string();
867 // 1. Assert: IsPropertyKey(P) is true.
868 // 2. Let handler be the value of the [[ProxyHandler]] internal slot of O.
869 Handle<Object> handler(proxy->handler(), isolate);
870 // 3. If handler is null, throw a TypeError exception.
871 // 4. Assert: Type(handler) is Object.
872 if (proxy->IsRevoked()) {
873 THROW_NEW_ERROR(isolate,
874 NewTypeError(MessageTemplate::kProxyRevoked, trap_name),
875 Object);
876 }
877 // 5. Let target be the value of the [[ProxyTarget]] internal slot of O.
878 Handle<JSReceiver> target(proxy->target(), isolate);
879 // 6. Let trap be ? GetMethod(handler, "get").
880 Handle<Object> trap;
881 ASSIGN_RETURN_ON_EXCEPTION(
882 isolate, trap,
883 Object::GetMethod(Handle<JSReceiver>::cast(handler), trap_name), Object);
884 // 7. If trap is undefined, then
885 if (trap->IsUndefined()) {
886 // 7.a Return target.[[Get]](P, Receiver).
887 LookupIterator it =
888 LookupIterator::PropertyOrElement(isolate, receiver, name, target);
Ben Murdochda12d292016-06-02 14:46:10 +0100889 MaybeHandle<Object> result = Object::GetProperty(&it);
890 *was_found = it.IsFound();
891 return result;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000892 }
893 // 8. Let trapResult be ? Call(trap, handler, «target, P, Receiver»).
894 Handle<Object> trap_result;
895 Handle<Object> args[] = {target, name, receiver};
896 ASSIGN_RETURN_ON_EXCEPTION(
897 isolate, trap_result,
898 Execution::Call(isolate, trap, handler, arraysize(args), args), Object);
899 // 9. Let targetDesc be ? target.[[GetOwnProperty]](P).
900 PropertyDescriptor target_desc;
901 Maybe<bool> target_found =
902 JSReceiver::GetOwnPropertyDescriptor(isolate, target, name, &target_desc);
903 MAYBE_RETURN_NULL(target_found);
904 // 10. If targetDesc is not undefined, then
905 if (target_found.FromJust()) {
906 // 10.a. If IsDataDescriptor(targetDesc) and targetDesc.[[Configurable]] is
907 // false and targetDesc.[[Writable]] is false, then
908 // 10.a.i. If SameValue(trapResult, targetDesc.[[Value]]) is false,
909 // throw a TypeError exception.
910 bool inconsistent = PropertyDescriptor::IsDataDescriptor(&target_desc) &&
911 !target_desc.configurable() &&
912 !target_desc.writable() &&
913 !trap_result->SameValue(*target_desc.value());
914 if (inconsistent) {
915 THROW_NEW_ERROR(
916 isolate, NewTypeError(MessageTemplate::kProxyGetNonConfigurableData,
917 name, target_desc.value(), trap_result),
918 Object);
919 }
920 // 10.b. If IsAccessorDescriptor(targetDesc) and targetDesc.[[Configurable]]
921 // is false and targetDesc.[[Get]] is undefined, then
922 // 10.b.i. If trapResult is not undefined, throw a TypeError exception.
923 inconsistent = PropertyDescriptor::IsAccessorDescriptor(&target_desc) &&
924 !target_desc.configurable() &&
925 target_desc.get()->IsUndefined() &&
926 !trap_result->IsUndefined();
927 if (inconsistent) {
928 THROW_NEW_ERROR(
929 isolate,
930 NewTypeError(MessageTemplate::kProxyGetNonConfigurableAccessor, name,
931 trap_result),
932 Object);
933 }
934 }
935 // 11. Return trap_result
936 return trap_result;
937}
938
939
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000940Handle<Object> JSReceiver::GetDataProperty(LookupIterator* it) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000941 for (; it->IsFound(); it->Next()) {
942 switch (it->state()) {
943 case LookupIterator::INTERCEPTOR:
944 case LookupIterator::NOT_FOUND:
945 case LookupIterator::TRANSITION:
946 UNREACHABLE();
947 case LookupIterator::ACCESS_CHECK:
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000948 // Support calling this method without an active context, but refuse
949 // access to access-checked objects in that case.
950 if (it->isolate()->context() != nullptr && it->HasAccess()) continue;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000951 // Fall through.
952 case LookupIterator::JSPROXY:
953 it->NotFound();
954 return it->isolate()->factory()->undefined_value();
955 case LookupIterator::ACCESSOR:
Ben Murdoch097c5b22016-05-18 11:27:45 +0100956 // TODO(verwaest): For now this doesn't call into AccessorInfo, since
957 // clients don't need it. Update once relevant.
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000958 it->NotFound();
959 return it->isolate()->factory()->undefined_value();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000960 case LookupIterator::INTEGER_INDEXED_EXOTIC:
961 return it->isolate()->factory()->undefined_value();
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000962 case LookupIterator::DATA:
963 return it->GetDataValue();
964 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000965 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000966 return it->isolate()->factory()->undefined_value();
967}
Steve Blocka7e24c12009-10-30 11:49:00 +0000968
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000969
970bool Object::ToInt32(int32_t* value) {
971 if (IsSmi()) {
972 *value = Smi::cast(this)->value();
973 return true;
974 }
975 if (IsHeapNumber()) {
976 double num = HeapNumber::cast(this)->value();
977 if (FastI2D(FastD2I(num)) == num) {
978 *value = FastD2I(num);
979 return true;
980 }
981 }
982 return false;
983}
984
985
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000986bool FunctionTemplateInfo::IsTemplateFor(Object* object) {
987 if (!object->IsHeapObject()) return false;
988 return IsTemplateFor(HeapObject::cast(object)->map());
989}
990
991
992bool FunctionTemplateInfo::IsTemplateFor(Map* map) {
993 // There is a constraint on the object; check.
994 if (!map->IsJSObjectMap()) return false;
995 // Fetch the constructor function of the object.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000996 Object* cons_obj = map->GetConstructor();
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000997 if (!cons_obj->IsJSFunction()) return false;
998 JSFunction* fun = JSFunction::cast(cons_obj);
999 // Iterate through the chain of inheriting function templates to
1000 // see if the required one occurs.
1001 for (Object* type = fun->shared()->function_data();
1002 type->IsFunctionTemplateInfo();
1003 type = FunctionTemplateInfo::cast(type)->parent_template()) {
1004 if (type == this) return true;
1005 }
1006 // Didn't find the required type in the inheritance chain.
1007 return false;
1008}
1009
1010
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001011// TODO(dcarney): CallOptimization duplicates this logic, merge.
1012Object* FunctionTemplateInfo::GetCompatibleReceiver(Isolate* isolate,
1013 Object* receiver) {
1014 // API calls are only supported with JSObject receivers.
1015 if (!receiver->IsJSObject()) return isolate->heap()->null_value();
1016 Object* recv_type = this->signature();
1017 // No signature, return holder.
1018 if (recv_type->IsUndefined()) return receiver;
1019 FunctionTemplateInfo* signature = FunctionTemplateInfo::cast(recv_type);
1020 // Check the receiver.
Ben Murdoch097c5b22016-05-18 11:27:45 +01001021 for (PrototypeIterator iter(isolate, JSObject::cast(receiver),
1022 PrototypeIterator::START_AT_RECEIVER,
1023 PrototypeIterator::END_AT_NON_HIDDEN);
1024 !iter.IsAtEnd(); iter.Advance()) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001025 if (signature->IsTemplateFor(iter.GetCurrent())) return iter.GetCurrent();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001026 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001027 return isolate->heap()->null_value();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001028}
1029
1030
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001031// static
1032MaybeHandle<JSObject> JSObject::New(Handle<JSFunction> constructor,
1033 Handle<JSReceiver> new_target,
1034 Handle<AllocationSite> site) {
1035 // If called through new, new.target can be:
1036 // - a subclass of constructor,
1037 // - a proxy wrapper around constructor, or
1038 // - the constructor itself.
1039 // If called through Reflect.construct, it's guaranteed to be a constructor.
1040 Isolate* const isolate = constructor->GetIsolate();
1041 DCHECK(constructor->IsConstructor());
1042 DCHECK(new_target->IsConstructor());
1043 DCHECK(!constructor->has_initial_map() ||
1044 constructor->initial_map()->instance_type() != JS_FUNCTION_TYPE);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001045
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001046 Handle<Map> initial_map;
1047 ASSIGN_RETURN_ON_EXCEPTION(
1048 isolate, initial_map,
1049 JSFunction::GetDerivedMap(isolate, constructor, new_target), JSObject);
1050 Handle<JSObject> result =
1051 isolate->factory()->NewJSObjectFromMap(initial_map, NOT_TENURED, site);
1052 isolate->counters()->constructed_objects()->Increment();
1053 isolate->counters()->constructed_objects_runtime()->Increment();
1054 return result;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001055}
1056
Ben Murdochda12d292016-06-02 14:46:10 +01001057void JSObject::EnsureWritableFastElements(Handle<JSObject> object) {
Ben Murdoch097c5b22016-05-18 11:27:45 +01001058 DCHECK(object->HasFastSmiOrObjectElements() ||
1059 object->HasFastStringWrapperElements());
Ben Murdochda12d292016-06-02 14:46:10 +01001060 FixedArray* raw_elems = FixedArray::cast(object->elements());
1061 Heap* heap = object->GetHeap();
1062 if (raw_elems->map() != heap->fixed_cow_array_map()) return;
1063 Isolate* isolate = heap->isolate();
1064 Handle<FixedArray> elems(raw_elems, isolate);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001065 Handle<FixedArray> writable_elems = isolate->factory()->CopyFixedArrayWithMap(
1066 elems, isolate->factory()->fixed_array_map());
1067 object->set_elements(*writable_elems);
1068 isolate->counters()->cow_arrays_converted()->Increment();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001069}
1070
1071
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001072// ES6 9.5.1
1073// static
1074MaybeHandle<Object> JSProxy::GetPrototype(Handle<JSProxy> proxy) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001075 Isolate* isolate = proxy->GetIsolate();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001076 Handle<String> trap_name = isolate->factory()->getPrototypeOf_string();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001077
Ben Murdochc5610432016-08-08 18:44:38 +01001078 STACK_CHECK(isolate, MaybeHandle<Object>());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001079
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001080 // 1. Let handler be the value of the [[ProxyHandler]] internal slot.
1081 // 2. If handler is null, throw a TypeError exception.
1082 // 3. Assert: Type(handler) is Object.
1083 // 4. Let target be the value of the [[ProxyTarget]] internal slot.
1084 if (proxy->IsRevoked()) {
1085 THROW_NEW_ERROR(isolate,
1086 NewTypeError(MessageTemplate::kProxyRevoked, trap_name),
1087 Object);
1088 }
1089 Handle<JSReceiver> target(proxy->target(), isolate);
1090 Handle<JSReceiver> handler(JSReceiver::cast(proxy->handler()), isolate);
1091
1092 // 5. Let trap be ? GetMethod(handler, "getPrototypeOf").
1093 Handle<Object> trap;
1094 ASSIGN_RETURN_ON_EXCEPTION(isolate, trap, GetMethod(handler, trap_name),
1095 Object);
1096 // 6. If trap is undefined, then return target.[[GetPrototypeOf]]().
1097 if (trap->IsUndefined()) {
Ben Murdoch097c5b22016-05-18 11:27:45 +01001098 return JSReceiver::GetPrototype(isolate, target);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001099 }
1100 // 7. Let handlerProto be ? Call(trap, handler, «target»).
1101 Handle<Object> argv[] = {target};
1102 Handle<Object> handler_proto;
1103 ASSIGN_RETURN_ON_EXCEPTION(
1104 isolate, handler_proto,
1105 Execution::Call(isolate, trap, handler, arraysize(argv), argv), Object);
1106 // 8. If Type(handlerProto) is neither Object nor Null, throw a TypeError.
1107 if (!(handler_proto->IsJSReceiver() || handler_proto->IsNull())) {
1108 THROW_NEW_ERROR(isolate,
1109 NewTypeError(MessageTemplate::kProxyGetPrototypeOfInvalid),
1110 Object);
1111 }
1112 // 9. Let extensibleTarget be ? IsExtensible(target).
1113 Maybe<bool> is_extensible = JSReceiver::IsExtensible(target);
1114 MAYBE_RETURN_NULL(is_extensible);
1115 // 10. If extensibleTarget is true, return handlerProto.
1116 if (is_extensible.FromJust()) return handler_proto;
1117 // 11. Let targetProto be ? target.[[GetPrototypeOf]]().
1118 Handle<Object> target_proto;
1119 ASSIGN_RETURN_ON_EXCEPTION(isolate, target_proto,
Ben Murdoch097c5b22016-05-18 11:27:45 +01001120 JSReceiver::GetPrototype(isolate, target), Object);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001121 // 12. If SameValue(handlerProto, targetProto) is false, throw a TypeError.
1122 if (!handler_proto->SameValue(*target_proto)) {
1123 THROW_NEW_ERROR(
1124 isolate,
1125 NewTypeError(MessageTemplate::kProxyGetPrototypeOfNonExtensible),
1126 Object);
1127 }
1128 // 13. Return handlerProto.
1129 return handler_proto;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001130}
1131
Ben Murdoch097c5b22016-05-18 11:27:45 +01001132MaybeHandle<Object> Object::GetPropertyWithAccessor(LookupIterator* it) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001133 Isolate* isolate = it->isolate();
1134 Handle<Object> structure = it->GetAccessors();
1135 Handle<Object> receiver = it->GetReceiver();
1136
1137 // We should never get here to initialize a const with the hole value since a
1138 // const declaration would conflict with the getter.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001139 DCHECK(!structure->IsForeign());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001140
1141 // API style callbacks.
Steve Blocka7e24c12009-10-30 11:49:00 +00001142 if (structure->IsAccessorInfo()) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001143 Handle<JSObject> holder = it->GetHolder<JSObject>();
1144 Handle<Name> name = it->GetName();
Ben Murdoch097c5b22016-05-18 11:27:45 +01001145 Handle<AccessorInfo> info = Handle<AccessorInfo>::cast(structure);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001146 if (!info->IsCompatibleReceiver(*receiver)) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001147 THROW_NEW_ERROR(isolate,
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001148 NewTypeError(MessageTemplate::kIncompatibleMethodReceiver,
1149 name, receiver),
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001150 Object);
Steve Blocka7e24c12009-10-30 11:49:00 +00001151 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001152
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001153 v8::AccessorNameGetterCallback call_fun =
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001154 v8::ToCData<v8::AccessorNameGetterCallback>(info->getter());
1155 if (call_fun == nullptr) return isolate->factory()->undefined_value();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001156
Ben Murdochda12d292016-06-02 14:46:10 +01001157 if (info->is_sloppy() && !receiver->IsJSReceiver()) {
1158 ASSIGN_RETURN_ON_EXCEPTION(isolate, receiver,
1159 Object::ConvertReceiver(isolate, receiver),
1160 Object);
1161 }
1162
Ben Murdoch097c5b22016-05-18 11:27:45 +01001163 PropertyCallbackArguments args(isolate, info->data(), *receiver, *holder,
1164 Object::DONT_THROW);
Ben Murdochda12d292016-06-02 14:46:10 +01001165 Handle<Object> result = args.Call(call_fun, name);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001166 RETURN_EXCEPTION_IF_SCHEDULED_EXCEPTION(isolate, Object);
Ben Murdochda12d292016-06-02 14:46:10 +01001167 if (result.is_null()) return ReadAbsentProperty(isolate, receiver, name);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001168 // Rebox handle before return.
Ben Murdochda12d292016-06-02 14:46:10 +01001169 return handle(*result, isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00001170 }
1171
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001172 // Regular accessor.
1173 Handle<Object> getter(AccessorPair::cast(*structure)->getter(), isolate);
Ben Murdoch097c5b22016-05-18 11:27:45 +01001174 if (getter->IsFunctionTemplateInfo()) {
1175 auto result = Builtins::InvokeApiFunction(
1176 Handle<FunctionTemplateInfo>::cast(getter), receiver, 0, nullptr);
1177 if (isolate->has_pending_exception()) {
1178 return MaybeHandle<Object>();
1179 }
1180 Handle<Object> return_value;
1181 if (result.ToHandle(&return_value)) {
1182 return_value->VerifyApiCallResultType();
1183 return handle(*return_value, isolate);
1184 }
1185 } else if (getter->IsCallable()) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001186 // TODO(rossberg): nicer would be to cast to some JSCallable here...
1187 return Object::GetPropertyWithDefinedGetter(
1188 receiver, Handle<JSReceiver>::cast(getter));
1189 }
1190 // Getter is not a function.
Ben Murdoch097c5b22016-05-18 11:27:45 +01001191 return ReadAbsentProperty(isolate, receiver, it->GetName());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001192}
1193
Ben Murdochc5610432016-08-08 18:44:38 +01001194// static
1195Address AccessorInfo::redirect(Isolate* isolate, Address address,
1196 AccessorComponent component) {
1197 ApiFunction fun(address);
1198 DCHECK_EQ(ACCESSOR_GETTER, component);
1199 ExternalReference::Type type = ExternalReference::DIRECT_GETTER_CALL;
1200 return ExternalReference(&fun, type, isolate).address();
1201}
1202
1203Address AccessorInfo::redirected_getter() const {
1204 Address accessor = v8::ToCData<Address>(getter());
1205 if (accessor == nullptr) return nullptr;
1206 return redirect(GetIsolate(), accessor, ACCESSOR_GETTER);
1207}
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001208
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001209bool AccessorInfo::IsCompatibleReceiverMap(Isolate* isolate,
1210 Handle<AccessorInfo> info,
1211 Handle<Map> map) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001212 if (!info->HasExpectedReceiverType()) return true;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001213 if (!map->IsJSObjectMap()) return false;
1214 return FunctionTemplateInfo::cast(info->expected_receiver_type())
1215 ->IsTemplateFor(*map);
1216}
1217
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001218Maybe<bool> Object::SetPropertyWithAccessor(LookupIterator* it,
1219 Handle<Object> value,
1220 ShouldThrow should_throw) {
1221 Isolate* isolate = it->isolate();
1222 Handle<Object> structure = it->GetAccessors();
1223 Handle<Object> receiver = it->GetReceiver();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001224
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001225 // We should never get here to initialize a const with the hole value since a
1226 // const declaration would conflict with the setter.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001227 DCHECK(!structure->IsForeign());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001228
1229 // API style callbacks.
Ben Murdoch097c5b22016-05-18 11:27:45 +01001230 if (structure->IsAccessorInfo()) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001231 Handle<JSObject> holder = it->GetHolder<JSObject>();
1232 Handle<Name> name = it->GetName();
Ben Murdoch097c5b22016-05-18 11:27:45 +01001233 Handle<AccessorInfo> info = Handle<AccessorInfo>::cast(structure);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001234 if (!info->IsCompatibleReceiver(*receiver)) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001235 isolate->Throw(*isolate->factory()->NewTypeError(
1236 MessageTemplate::kIncompatibleMethodReceiver, name, receiver));
1237 return Nothing<bool>();
Steve Blocka7e24c12009-10-30 11:49:00 +00001238 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001239
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001240 v8::AccessorNameSetterCallback call_fun =
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001241 v8::ToCData<v8::AccessorNameSetterCallback>(info->setter());
Ben Murdoch097c5b22016-05-18 11:27:45 +01001242 // TODO(verwaest): We should not get here anymore once all AccessorInfos are
1243 // marked as special_data_property. They cannot both be writable and not
1244 // have a setter.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001245 if (call_fun == nullptr) return Just(true);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001246
Ben Murdochda12d292016-06-02 14:46:10 +01001247 if (info->is_sloppy() && !receiver->IsJSReceiver()) {
1248 ASSIGN_RETURN_ON_EXCEPTION_VALUE(
1249 isolate, receiver, Object::ConvertReceiver(isolate, receiver),
1250 Nothing<bool>());
1251 }
1252
Ben Murdoch097c5b22016-05-18 11:27:45 +01001253 PropertyCallbackArguments args(isolate, info->data(), *receiver, *holder,
1254 should_throw);
Ben Murdochda12d292016-06-02 14:46:10 +01001255 args.Call(call_fun, name, value);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001256 RETURN_VALUE_IF_SCHEDULED_EXCEPTION(isolate, Nothing<bool>());
1257 return Just(true);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001258 }
1259
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001260 // Regular accessor.
1261 Handle<Object> setter(AccessorPair::cast(*structure)->setter(), isolate);
Ben Murdoch097c5b22016-05-18 11:27:45 +01001262 if (setter->IsFunctionTemplateInfo()) {
1263 Handle<Object> argv[] = {value};
1264 auto result =
1265 Builtins::InvokeApiFunction(Handle<FunctionTemplateInfo>::cast(setter),
1266 receiver, arraysize(argv), argv);
1267 if (isolate->has_pending_exception()) {
1268 return Nothing<bool>();
1269 }
1270 return Just(true);
1271 } else if (setter->IsCallable()) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001272 // TODO(rossberg): nicer would be to cast to some JSCallable here...
1273 return SetPropertyWithDefinedSetter(
1274 receiver, Handle<JSReceiver>::cast(setter), value, should_throw);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001275 }
1276
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001277 RETURN_FAILURE(isolate, should_throw,
1278 NewTypeError(MessageTemplate::kNoSetterInCallback,
1279 it->GetName(), it->GetHolder<JSObject>()));
Steve Blocka7e24c12009-10-30 11:49:00 +00001280}
1281
1282
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001283MaybeHandle<Object> Object::GetPropertyWithDefinedGetter(
1284 Handle<Object> receiver,
1285 Handle<JSReceiver> getter) {
1286 Isolate* isolate = getter->GetIsolate();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001287
1288 // Platforms with simulators like arm/arm64 expose a funny issue. If the
1289 // simulator has a separate JS stack pointer from the C++ stack pointer, it
1290 // can miss C++ stack overflows in the stack guard at the start of JavaScript
1291 // functions. It would be very expensive to check the C++ stack pointer at
1292 // that location. The best solution seems to be to break the impasse by
1293 // adding checks at possible recursion points. What's more, we don't put
1294 // this stack check behind the USE_SIMULATOR define in order to keep
1295 // behavior the same between hardware and simulators.
1296 StackLimitCheck check(isolate);
1297 if (check.JsHasOverflowed()) {
1298 isolate->StackOverflow();
1299 return MaybeHandle<Object>();
Steve Blocka7e24c12009-10-30 11:49:00 +00001300 }
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001301
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001302 return Execution::Call(isolate, getter, receiver, 0, NULL);
Steve Blocka7e24c12009-10-30 11:49:00 +00001303}
1304
1305
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001306Maybe<bool> Object::SetPropertyWithDefinedSetter(Handle<Object> receiver,
1307 Handle<JSReceiver> setter,
1308 Handle<Object> value,
1309 ShouldThrow should_throw) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001310 Isolate* isolate = setter->GetIsolate();
1311
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001312 Handle<Object> argv[] = { value };
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001313 RETURN_ON_EXCEPTION_VALUE(isolate, Execution::Call(isolate, setter, receiver,
1314 arraysize(argv), argv),
1315 Nothing<bool>());
1316 return Just(true);
Steve Blocka7e24c12009-10-30 11:49:00 +00001317}
1318
1319
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001320// static
1321bool Object::IsErrorObject(Isolate* isolate, Handle<Object> object) {
1322 if (!object->IsJSObject()) return false;
1323 // Use stack_trace_symbol as proxy for [[ErrorData]].
1324 Handle<Name> symbol = isolate->factory()->stack_trace_symbol();
1325 Maybe<bool> has_stack_trace =
1326 JSReceiver::HasOwnProperty(Handle<JSReceiver>::cast(object), symbol);
1327 DCHECK(!has_stack_trace.IsNothing());
1328 return has_stack_trace.FromJust();
1329}
1330
1331
1332// static
1333bool JSObject::AllCanRead(LookupIterator* it) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001334 // Skip current iteration, it's in state ACCESS_CHECK or INTERCEPTOR, both of
1335 // which have already been checked.
1336 DCHECK(it->state() == LookupIterator::ACCESS_CHECK ||
1337 it->state() == LookupIterator::INTERCEPTOR);
1338 for (it->Next(); it->IsFound(); it->Next()) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001339 if (it->state() == LookupIterator::ACCESSOR) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001340 auto accessors = it->GetAccessors();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001341 if (accessors->IsAccessorInfo()) {
1342 if (AccessorInfo::cast(*accessors)->all_can_read()) return true;
1343 }
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001344 } else if (it->state() == LookupIterator::INTERCEPTOR) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001345 if (it->GetInterceptor()->all_can_read()) return true;
1346 } else if (it->state() == LookupIterator::JSPROXY) {
1347 // Stop lookupiterating. And no, AllCanNotRead.
1348 return false;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001349 }
1350 }
1351 return false;
1352}
1353
1354
1355MaybeHandle<Object> JSObject::GetPropertyWithFailedAccessCheck(
1356 LookupIterator* it) {
1357 Handle<JSObject> checked = it->GetHolder<JSObject>();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001358 while (AllCanRead(it)) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001359 if (it->state() == LookupIterator::ACCESSOR) {
Ben Murdoch097c5b22016-05-18 11:27:45 +01001360 return GetPropertyWithAccessor(it);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001361 }
1362 DCHECK_EQ(LookupIterator::INTERCEPTOR, it->state());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001363 bool done;
1364 Handle<Object> result;
1365 ASSIGN_RETURN_ON_EXCEPTION(it->isolate(), result,
1366 GetPropertyWithInterceptor(it, &done), Object);
1367 if (done) return result;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001368 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001369
1370 // Cross-Origin [[Get]] of Well-Known Symbols does not throw, and returns
1371 // undefined.
1372 Handle<Name> name = it->GetName();
1373 if (name->IsSymbol() && Symbol::cast(*name)->is_well_known_symbol()) {
1374 return it->factory()->undefined_value();
1375 }
1376
1377 it->isolate()->ReportFailedAccessCheck(checked);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001378 RETURN_EXCEPTION_IF_SCHEDULED_EXCEPTION(it->isolate(), Object);
1379 return it->factory()->undefined_value();
1380}
1381
1382
1383Maybe<PropertyAttributes> JSObject::GetPropertyAttributesWithFailedAccessCheck(
1384 LookupIterator* it) {
1385 Handle<JSObject> checked = it->GetHolder<JSObject>();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001386 while (AllCanRead(it)) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001387 if (it->state() == LookupIterator::ACCESSOR) {
Ben Murdoch097c5b22016-05-18 11:27:45 +01001388 return Just(it->property_attributes());
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001389 }
1390 DCHECK_EQ(LookupIterator::INTERCEPTOR, it->state());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001391 auto result = GetPropertyAttributesWithInterceptor(it);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001392 if (it->isolate()->has_scheduled_exception()) break;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001393 if (result.IsJust() && result.FromJust() != ABSENT) return result;
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001394 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001395 it->isolate()->ReportFailedAccessCheck(checked);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001396 RETURN_VALUE_IF_SCHEDULED_EXCEPTION(it->isolate(),
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001397 Nothing<PropertyAttributes>());
1398 return Just(ABSENT);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001399}
1400
1401
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001402// static
1403bool JSObject::AllCanWrite(LookupIterator* it) {
1404 for (; it->IsFound() && it->state() != LookupIterator::JSPROXY; it->Next()) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001405 if (it->state() == LookupIterator::ACCESSOR) {
1406 Handle<Object> accessors = it->GetAccessors();
1407 if (accessors->IsAccessorInfo()) {
1408 if (AccessorInfo::cast(*accessors)->all_can_write()) return true;
1409 }
1410 }
1411 }
1412 return false;
1413}
1414
1415
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001416Maybe<bool> JSObject::SetPropertyWithFailedAccessCheck(
1417 LookupIterator* it, Handle<Object> value, ShouldThrow should_throw) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001418 Handle<JSObject> checked = it->GetHolder<JSObject>();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001419 if (AllCanWrite(it)) {
1420 return SetPropertyWithAccessor(it, value, should_throw);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001421 }
1422
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001423 it->isolate()->ReportFailedAccessCheck(checked);
1424 RETURN_VALUE_IF_SCHEDULED_EXCEPTION(it->isolate(), Nothing<bool>());
1425 return Just(true);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001426}
1427
1428
1429void JSObject::SetNormalizedProperty(Handle<JSObject> object,
1430 Handle<Name> name,
1431 Handle<Object> value,
1432 PropertyDetails details) {
1433 DCHECK(!object->HasFastProperties());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001434 if (!name->IsUniqueName()) {
1435 name = object->GetIsolate()->factory()->InternalizeString(
1436 Handle<String>::cast(name));
1437 }
1438
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001439 if (object->IsJSGlobalObject()) {
1440 Handle<GlobalDictionary> property_dictionary(object->global_dictionary());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001441
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001442 int entry = property_dictionary->FindEntry(name);
1443 if (entry == GlobalDictionary::kNotFound) {
1444 auto cell = object->GetIsolate()->factory()->NewPropertyCell();
1445 cell->set_value(*value);
1446 auto cell_type = value->IsUndefined() ? PropertyCellType::kUndefined
1447 : PropertyCellType::kConstant;
1448 details = details.set_cell_type(cell_type);
1449 value = cell;
1450 property_dictionary =
1451 GlobalDictionary::Add(property_dictionary, name, value, details);
1452 object->set_properties(*property_dictionary);
Steve Blocka7e24c12009-10-30 11:49:00 +00001453 } else {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001454 PropertyCell::UpdateCell(property_dictionary, entry, value, details);
1455 }
1456 } else {
1457 Handle<NameDictionary> property_dictionary(object->property_dictionary());
1458
1459 int entry = property_dictionary->FindEntry(name);
1460 if (entry == NameDictionary::kNotFound) {
1461 property_dictionary =
1462 NameDictionary::Add(property_dictionary, name, value, details);
1463 object->set_properties(*property_dictionary);
1464 } else {
1465 PropertyDetails original_details = property_dictionary->DetailsAt(entry);
1466 int enumeration_index = original_details.dictionary_index();
1467 DCHECK(enumeration_index > 0);
1468 details = details.set_index(enumeration_index);
1469 property_dictionary->SetEntry(entry, name, value, details);
Steve Blocka7e24c12009-10-30 11:49:00 +00001470 }
1471 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001472}
1473
Ben Murdochc5610432016-08-08 18:44:38 +01001474// static
Ben Murdoch097c5b22016-05-18 11:27:45 +01001475Maybe<bool> JSReceiver::HasInPrototypeChain(Isolate* isolate,
1476 Handle<JSReceiver> object,
1477 Handle<Object> proto) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001478 PrototypeIterator iter(isolate, object, PrototypeIterator::START_AT_RECEIVER);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001479 while (true) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001480 if (!iter.AdvanceFollowingProxies()) return Nothing<bool>();
1481 if (iter.IsAtEnd()) return Just(false);
Ben Murdoch097c5b22016-05-18 11:27:45 +01001482 if (PrototypeIterator::GetCurrent(iter).is_identical_to(proto)) {
1483 return Just(true);
1484 }
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001485 }
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001486}
1487
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001488Map* Object::GetRootMap(Isolate* isolate) {
1489 DisallowHeapAllocation no_alloc;
Ben Murdoch8b112d22011-06-08 16:22:53 +01001490 if (IsSmi()) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001491 Context* native_context = isolate->context()->native_context();
1492 return native_context->number_function()->initial_map();
Ben Murdoch8b112d22011-06-08 16:22:53 +01001493 }
1494
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001495 // The object is either a number, a string, a symbol, a boolean, a SIMD value,
Ben Murdoch257744e2011-11-30 15:57:28 +00001496 // a real JS object, or a Harmony proxy.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001497 HeapObject* heap_object = HeapObject::cast(this);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001498 if (heap_object->IsJSReceiver()) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001499 return heap_object->map();
Ben Murdoch8b112d22011-06-08 16:22:53 +01001500 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001501 int constructor_function_index =
1502 heap_object->map()->GetConstructorFunctionIndex();
1503 if (constructor_function_index != Map::kNoConstructorFunctionIndex) {
1504 Context* native_context = isolate->context()->native_context();
1505 JSFunction* constructor_function =
1506 JSFunction::cast(native_context->get(constructor_function_index));
1507 return constructor_function->initial_map();
Steve Blocka7e24c12009-10-30 11:49:00 +00001508 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001509 return isolate->heap()->null_value()->map();
Steve Blocka7e24c12009-10-30 11:49:00 +00001510}
1511
1512
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001513Object* Object::GetHash() {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001514 Object* hash = GetSimpleHash();
1515 if (hash->IsSmi()) return hash;
1516
Ben Murdochda12d292016-06-02 14:46:10 +01001517 DisallowHeapAllocation no_gc;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001518 DCHECK(IsJSReceiver());
Ben Murdochda12d292016-06-02 14:46:10 +01001519 JSReceiver* receiver = JSReceiver::cast(this);
1520 Isolate* isolate = receiver->GetIsolate();
1521 return *JSReceiver::GetIdentityHash(isolate, handle(receiver, isolate));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001522}
1523
1524
1525Object* Object::GetSimpleHash() {
1526 // The object is either a Smi, a HeapNumber, a name, an odd-ball,
1527 // a SIMD value type, a real JS object, or a Harmony proxy.
1528 if (IsSmi()) {
1529 uint32_t hash = ComputeIntegerHash(Smi::cast(this)->value(), kZeroHashSeed);
1530 return Smi::FromInt(hash & Smi::kMaxValue);
1531 }
1532 if (IsHeapNumber()) {
1533 double num = HeapNumber::cast(this)->value();
1534 if (std::isnan(num)) return Smi::FromInt(Smi::kMaxValue);
1535 if (i::IsMinusZero(num)) num = 0;
1536 if (IsSmiDouble(num)) {
1537 return Smi::FromInt(FastD2I(num))->GetHash();
1538 }
1539 uint32_t hash = ComputeLongHash(double_to_uint64(num));
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001540 return Smi::FromInt(hash & Smi::kMaxValue);
1541 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001542 if (IsName()) {
1543 uint32_t hash = Name::cast(this)->Hash();
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001544 return Smi::FromInt(hash);
1545 }
1546 if (IsOddball()) {
1547 uint32_t hash = Oddball::cast(this)->to_string()->Hash();
1548 return Smi::FromInt(hash);
1549 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001550 if (IsSimd128Value()) {
1551 uint32_t hash = Simd128Value::cast(this)->Hash();
1552 return Smi::FromInt(hash & Smi::kMaxValue);
1553 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001554 DCHECK(IsJSReceiver());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001555 JSReceiver* receiver = JSReceiver::cast(this);
1556 return receiver->GetHeap()->undefined_value();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001557}
1558
1559
1560Handle<Smi> Object::GetOrCreateHash(Isolate* isolate, Handle<Object> object) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001561 Handle<Object> hash(object->GetSimpleHash(), isolate);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001562 if (hash->IsSmi()) return Handle<Smi>::cast(hash);
1563
1564 DCHECK(object->IsJSReceiver());
1565 return JSReceiver::GetOrCreateIdentityHash(Handle<JSReceiver>::cast(object));
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001566}
1567
1568
1569bool Object::SameValue(Object* other) {
1570 if (other == this) return true;
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001571
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001572 // The object is either a number, a name, an odd-ball,
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001573 // a real JS object, or a Harmony proxy.
1574 if (IsNumber() && other->IsNumber()) {
1575 double this_value = Number();
1576 double other_value = other->Number();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001577 // SameValue(NaN, NaN) is true.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001578 if (this_value != other_value) {
1579 return std::isnan(this_value) && std::isnan(other_value);
1580 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001581 // SameValue(0.0, -0.0) is false.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001582 return (std::signbit(this_value) == std::signbit(other_value));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001583 }
1584 if (IsString() && other->IsString()) {
1585 return String::cast(this)->Equals(String::cast(other));
1586 }
Ben Murdoch097c5b22016-05-18 11:27:45 +01001587 if (IsFloat32x4() && other->IsFloat32x4()) {
1588 Float32x4* a = Float32x4::cast(this);
1589 Float32x4* b = Float32x4::cast(other);
1590 for (int i = 0; i < 4; i++) {
1591 float x = a->get_lane(i);
1592 float y = b->get_lane(i);
1593 // Implements the ES5 SameValue operation for floating point types.
1594 // http://www.ecma-international.org/ecma-262/6.0/#sec-samevalue
1595 if (x != y && !(std::isnan(x) && std::isnan(y))) return false;
1596 if (std::signbit(x) != std::signbit(y)) return false;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001597 }
Ben Murdoch097c5b22016-05-18 11:27:45 +01001598 return true;
1599 } else if (IsSimd128Value() && other->IsSimd128Value()) {
1600 Simd128Value* a = Simd128Value::cast(this);
1601 Simd128Value* b = Simd128Value::cast(other);
1602 return a->map() == b->map() && a->BitwiseEquals(b);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001603 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001604 return false;
1605}
1606
1607
1608bool Object::SameValueZero(Object* other) {
1609 if (other == this) return true;
1610
1611 // The object is either a number, a name, an odd-ball,
1612 // a real JS object, or a Harmony proxy.
1613 if (IsNumber() && other->IsNumber()) {
1614 double this_value = Number();
1615 double other_value = other->Number();
1616 // +0 == -0 is true
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001617 return this_value == other_value ||
1618 (std::isnan(this_value) && std::isnan(other_value));
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001619 }
1620 if (IsString() && other->IsString()) {
1621 return String::cast(this)->Equals(String::cast(other));
1622 }
Ben Murdoch097c5b22016-05-18 11:27:45 +01001623 if (IsFloat32x4() && other->IsFloat32x4()) {
1624 Float32x4* a = Float32x4::cast(this);
1625 Float32x4* b = Float32x4::cast(other);
1626 for (int i = 0; i < 4; i++) {
1627 float x = a->get_lane(i);
1628 float y = b->get_lane(i);
1629 // Implements the ES6 SameValueZero operation for floating point types.
1630 // http://www.ecma-international.org/ecma-262/6.0/#sec-samevaluezero
1631 if (x != y && !(std::isnan(x) && std::isnan(y))) return false;
1632 // SameValueZero doesn't distinguish between 0 and -0.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001633 }
Ben Murdoch097c5b22016-05-18 11:27:45 +01001634 return true;
1635 } else if (IsSimd128Value() && other->IsSimd128Value()) {
1636 Simd128Value* a = Simd128Value::cast(this);
1637 Simd128Value* b = Simd128Value::cast(other);
1638 return a->map() == b->map() && a->BitwiseEquals(b);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001639 }
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001640 return false;
1641}
1642
1643
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001644MaybeHandle<Object> Object::ArraySpeciesConstructor(
1645 Isolate* isolate, Handle<Object> original_array) {
Ben Murdoch097c5b22016-05-18 11:27:45 +01001646 Handle<Object> default_species = isolate->array_function();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001647 if (!FLAG_harmony_species) {
Ben Murdoch097c5b22016-05-18 11:27:45 +01001648 return default_species;
1649 }
1650 if (original_array->IsJSArray() &&
Ben Murdochda12d292016-06-02 14:46:10 +01001651 Handle<JSArray>::cast(original_array)->HasArrayPrototype(isolate) &&
Ben Murdoch097c5b22016-05-18 11:27:45 +01001652 isolate->IsArraySpeciesLookupChainIntact()) {
1653 return default_species;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001654 }
1655 Handle<Object> constructor = isolate->factory()->undefined_value();
1656 Maybe<bool> is_array = Object::IsArray(original_array);
1657 MAYBE_RETURN_NULL(is_array);
1658 if (is_array.FromJust()) {
1659 ASSIGN_RETURN_ON_EXCEPTION(
1660 isolate, constructor,
1661 Object::GetProperty(original_array,
1662 isolate->factory()->constructor_string()),
1663 Object);
1664 if (constructor->IsConstructor()) {
1665 Handle<Context> constructor_context;
1666 ASSIGN_RETURN_ON_EXCEPTION(
1667 isolate, constructor_context,
1668 JSReceiver::GetFunctionRealm(Handle<JSReceiver>::cast(constructor)),
1669 Object);
Ben Murdochc5610432016-08-08 18:44:38 +01001670 if (*constructor_context != *isolate->native_context() &&
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001671 *constructor == constructor_context->array_function()) {
1672 constructor = isolate->factory()->undefined_value();
1673 }
1674 }
1675 if (constructor->IsJSReceiver()) {
1676 ASSIGN_RETURN_ON_EXCEPTION(
1677 isolate, constructor,
Ben Murdochda12d292016-06-02 14:46:10 +01001678 JSReceiver::GetProperty(Handle<JSReceiver>::cast(constructor),
1679 isolate->factory()->species_symbol()),
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001680 Object);
1681 if (constructor->IsNull()) {
1682 constructor = isolate->factory()->undefined_value();
1683 }
1684 }
1685 }
1686 if (constructor->IsUndefined()) {
Ben Murdoch097c5b22016-05-18 11:27:45 +01001687 return default_species;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001688 } else {
1689 if (!constructor->IsConstructor()) {
1690 THROW_NEW_ERROR(isolate,
1691 NewTypeError(MessageTemplate::kSpeciesNotConstructor),
1692 Object);
1693 }
1694 return constructor;
1695 }
1696}
1697
1698
Ben Murdochb0fe1622011-05-05 13:52:32 +01001699void Object::ShortPrint(FILE* out) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001700 OFStream os(out);
1701 os << Brief(this);
Steve Blocka7e24c12009-10-30 11:49:00 +00001702}
1703
1704
1705void Object::ShortPrint(StringStream* accumulator) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001706 std::ostringstream os;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001707 os << Brief(this);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001708 accumulator->Add(os.str().c_str());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001709}
1710
1711
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001712void Object::ShortPrint(std::ostream& os) { os << Brief(this); }
1713
1714
1715std::ostream& operator<<(std::ostream& os, const Brief& v) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001716 if (v.value->IsSmi()) {
1717 Smi::cast(v.value)->SmiPrint(os);
Steve Blocka7e24c12009-10-30 11:49:00 +00001718 } else {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001719 // TODO(svenpanne) Const-correct HeapObjectShortPrint!
1720 HeapObject* obj = const_cast<HeapObject*>(HeapObject::cast(v.value));
1721 obj->HeapObjectShortPrint(os);
Steve Blocka7e24c12009-10-30 11:49:00 +00001722 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001723 return os;
Steve Blocka7e24c12009-10-30 11:49:00 +00001724}
1725
1726
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001727void Smi::SmiPrint(std::ostream& os) const { // NOLINT
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001728 os << value();
Steve Blocka7e24c12009-10-30 11:49:00 +00001729}
1730
1731
Steve Blocka7e24c12009-10-30 11:49:00 +00001732// Should a word be prefixed by 'a' or 'an' in order to read naturally in
1733// English? Returns false for non-ASCII or words that don't start with
1734// a capital letter. The a/an rule follows pronunciation in English.
1735// We don't use the BBC's overcorrect "an historic occasion" though if
1736// you speak a dialect you may well say "an 'istoric occasion".
1737static bool AnWord(String* str) {
1738 if (str->length() == 0) return false; // A nothing.
1739 int c0 = str->Get(0);
1740 int c1 = str->length() > 1 ? str->Get(1) : 0;
1741 if (c0 == 'U') {
1742 if (c1 > 'Z') {
1743 return true; // An Umpire, but a UTF8String, a U.
1744 }
1745 } else if (c0 == 'A' || c0 == 'E' || c0 == 'I' || c0 == 'O') {
1746 return true; // An Ape, an ABCBook.
1747 } else if ((c1 == 0 || (c1 >= 'A' && c1 <= 'Z')) &&
1748 (c0 == 'F' || c0 == 'H' || c0 == 'M' || c0 == 'N' || c0 == 'R' ||
1749 c0 == 'S' || c0 == 'X')) {
1750 return true; // An MP3File, an M.
1751 }
1752 return false;
1753}
1754
1755
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001756Handle<String> String::SlowFlatten(Handle<ConsString> cons,
1757 PretenureFlag pretenure) {
1758 DCHECK(AllowHeapAllocation::IsAllowed());
1759 DCHECK(cons->second()->length() != 0);
1760 Isolate* isolate = cons->GetIsolate();
1761 int length = cons->length();
1762 PretenureFlag tenure = isolate->heap()->InNewSpace(*cons) ? pretenure
1763 : TENURED;
1764 Handle<SeqString> result;
1765 if (cons->IsOneByteRepresentation()) {
1766 Handle<SeqOneByteString> flat = isolate->factory()->NewRawOneByteString(
1767 length, tenure).ToHandleChecked();
1768 DisallowHeapAllocation no_gc;
1769 WriteToFlat(*cons, flat->GetChars(), 0, length);
1770 result = flat;
1771 } else {
1772 Handle<SeqTwoByteString> flat = isolate->factory()->NewRawTwoByteString(
1773 length, tenure).ToHandleChecked();
1774 DisallowHeapAllocation no_gc;
1775 WriteToFlat(*cons, flat->GetChars(), 0, length);
1776 result = flat;
Steve Blocka7e24c12009-10-30 11:49:00 +00001777 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001778 cons->set_first(*result);
1779 cons->set_second(isolate->heap()->empty_string());
1780 DCHECK(result->IsFlat());
1781 return result;
Steve Blocka7e24c12009-10-30 11:49:00 +00001782}
1783
1784
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001785
Steve Blocka7e24c12009-10-30 11:49:00 +00001786bool String::MakeExternal(v8::String::ExternalStringResource* resource) {
Steve Block8defd9f2010-07-08 12:39:36 +01001787 // Externalizing twice leaks the external resource, so it's
Kristian Monsen9dcf7e22010-06-28 14:14:28 +01001788 // prohibited by the API.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001789 DCHECK(!this->IsExternalString());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001790 DCHECK(!resource->IsCompressible());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001791#ifdef ENABLE_SLOW_DCHECKS
Steve Block3ce2e202009-11-05 08:53:23 +00001792 if (FLAG_enable_slow_asserts) {
Steve Blocka7e24c12009-10-30 11:49:00 +00001793 // Assert that the resource and the string are equivalent.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001794 DCHECK(static_cast<size_t>(this->length()) == resource->length());
Kristian Monsen25f61362010-05-21 11:50:48 +01001795 ScopedVector<uc16> smart_chars(this->length());
1796 String::WriteToFlat(this, smart_chars.start(), 0, this->length());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001797 DCHECK(memcmp(smart_chars.start(),
Steve Blocka7e24c12009-10-30 11:49:00 +00001798 resource->data(),
Kristian Monsen25f61362010-05-21 11:50:48 +01001799 resource->length() * sizeof(smart_chars[0])) == 0);
Steve Blocka7e24c12009-10-30 11:49:00 +00001800 }
1801#endif // DEBUG
Steve Blocka7e24c12009-10-30 11:49:00 +00001802 int size = this->Size(); // Byte size of the original string.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001803 // Abort if size does not allow in-place conversion.
1804 if (size < ExternalString::kShortSize) return false;
1805 Heap* heap = GetHeap();
1806 bool is_one_byte = this->IsOneByteRepresentation();
1807 bool is_internalized = this->IsInternalizedString();
Steve Blocka7e24c12009-10-30 11:49:00 +00001808
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001809 // Morph the string to an external string by replacing the map and
1810 // reinitializing the fields. This won't work if the space the existing
1811 // string occupies is too small for a regular external string.
1812 // Instead, we resort to a short external string instead, omitting
1813 // the field caching the address of the backing store. When we encounter
1814 // short external strings in generated code, we need to bailout to runtime.
1815 Map* new_map;
1816 if (size < ExternalString::kSize) {
1817 new_map = is_internalized
1818 ? (is_one_byte
1819 ? heap->short_external_internalized_string_with_one_byte_data_map()
1820 : heap->short_external_internalized_string_map())
1821 : (is_one_byte ? heap->short_external_string_with_one_byte_data_map()
1822 : heap->short_external_string_map());
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001823 } else {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001824 new_map = is_internalized
1825 ? (is_one_byte
1826 ? heap->external_internalized_string_with_one_byte_data_map()
1827 : heap->external_internalized_string_map())
1828 : (is_one_byte ? heap->external_string_with_one_byte_data_map()
1829 : heap->external_string_map());
Ben Murdoch85b71792012-04-11 18:30:58 +01001830 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001831
1832 // Byte size of the external String object.
1833 int new_size = this->SizeFromMap(new_map);
Ben Murdochda12d292016-06-02 14:46:10 +01001834 heap->CreateFillerObjectAt(this->address() + new_size, size - new_size,
1835 ClearRecordedSlots::kNo);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001836
1837 // We are storing the new map using release store after creating a filler for
1838 // the left-over space to avoid races with the sweeper thread.
1839 this->synchronized_set_map(new_map);
1840
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001841 ExternalTwoByteString* self = ExternalTwoByteString::cast(this);
1842 self->set_resource(resource);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001843 if (is_internalized) self->Hash(); // Force regeneration of the hash value.
Steve Blocka7e24c12009-10-30 11:49:00 +00001844
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001845 heap->AdjustLiveBytes(this, new_size - size, Heap::CONCURRENT_TO_SWEEPER);
Steve Blocka7e24c12009-10-30 11:49:00 +00001846 return true;
1847}
1848
1849
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001850bool String::MakeExternal(v8::String::ExternalOneByteStringResource* resource) {
1851 // Externalizing twice leaks the external resource, so it's
1852 // prohibited by the API.
1853 DCHECK(!this->IsExternalString());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001854 DCHECK(!resource->IsCompressible());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001855#ifdef ENABLE_SLOW_DCHECKS
Steve Block3ce2e202009-11-05 08:53:23 +00001856 if (FLAG_enable_slow_asserts) {
Steve Blocka7e24c12009-10-30 11:49:00 +00001857 // Assert that the resource and the string are equivalent.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001858 DCHECK(static_cast<size_t>(this->length()) == resource->length());
1859 if (this->IsTwoByteRepresentation()) {
1860 ScopedVector<uint16_t> smart_chars(this->length());
1861 String::WriteToFlat(this, smart_chars.start(), 0, this->length());
1862 DCHECK(String::IsOneByte(smart_chars.start(), this->length()));
1863 }
Kristian Monsen25f61362010-05-21 11:50:48 +01001864 ScopedVector<char> smart_chars(this->length());
1865 String::WriteToFlat(this, smart_chars.start(), 0, this->length());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001866 DCHECK(memcmp(smart_chars.start(),
Steve Blocka7e24c12009-10-30 11:49:00 +00001867 resource->data(),
Kristian Monsen25f61362010-05-21 11:50:48 +01001868 resource->length() * sizeof(smart_chars[0])) == 0);
Steve Blocka7e24c12009-10-30 11:49:00 +00001869 }
1870#endif // DEBUG
Steve Blocka7e24c12009-10-30 11:49:00 +00001871 int size = this->Size(); // Byte size of the original string.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001872 // Abort if size does not allow in-place conversion.
1873 if (size < ExternalString::kShortSize) return false;
1874 Heap* heap = GetHeap();
1875 bool is_internalized = this->IsInternalizedString();
Steve Blocka7e24c12009-10-30 11:49:00 +00001876
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001877 // Morph the string to an external string by replacing the map and
1878 // reinitializing the fields. This won't work if the space the existing
1879 // string occupies is too small for a regular external string.
1880 // Instead, we resort to a short external string instead, omitting
1881 // the field caching the address of the backing store. When we encounter
1882 // short external strings in generated code, we need to bailout to runtime.
1883 Map* new_map;
1884 if (size < ExternalString::kSize) {
1885 new_map = is_internalized
1886 ? heap->short_external_one_byte_internalized_string_map()
1887 : heap->short_external_one_byte_string_map();
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001888 } else {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001889 new_map = is_internalized
1890 ? heap->external_one_byte_internalized_string_map()
1891 : heap->external_one_byte_string_map();
Ben Murdoch85b71792012-04-11 18:30:58 +01001892 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001893
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001894 // Byte size of the external String object.
1895 int new_size = this->SizeFromMap(new_map);
Ben Murdochda12d292016-06-02 14:46:10 +01001896 heap->CreateFillerObjectAt(this->address() + new_size, size - new_size,
1897 ClearRecordedSlots::kNo);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001898
1899 // We are storing the new map using release store after creating a filler for
1900 // the left-over space to avoid races with the sweeper thread.
1901 this->synchronized_set_map(new_map);
1902
1903 ExternalOneByteString* self = ExternalOneByteString::cast(this);
1904 self->set_resource(resource);
1905 if (is_internalized) self->Hash(); // Force regeneration of the hash value.
1906
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001907 heap->AdjustLiveBytes(this, new_size - size, Heap::CONCURRENT_TO_SWEEPER);
Steve Blocka7e24c12009-10-30 11:49:00 +00001908 return true;
1909}
1910
1911
1912void String::StringShortPrint(StringStream* accumulator) {
1913 int len = length();
Steve Blockd0582a62009-12-15 09:54:21 +00001914 if (len > kMaxShortPrintLength) {
Steve Blocka7e24c12009-10-30 11:49:00 +00001915 accumulator->Add("<Very long string[%u]>", len);
1916 return;
1917 }
1918
1919 if (!LooksValid()) {
1920 accumulator->Add("<Invalid String>");
1921 return;
1922 }
1923
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001924 StringCharacterStream stream(this);
Steve Blocka7e24c12009-10-30 11:49:00 +00001925
1926 bool truncated = false;
1927 if (len > kMaxShortPrintLength) {
1928 len = kMaxShortPrintLength;
1929 truncated = true;
1930 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001931 bool one_byte = true;
Steve Blocka7e24c12009-10-30 11:49:00 +00001932 for (int i = 0; i < len; i++) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001933 uint16_t c = stream.GetNext();
Steve Blocka7e24c12009-10-30 11:49:00 +00001934
1935 if (c < 32 || c >= 127) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001936 one_byte = false;
Steve Blocka7e24c12009-10-30 11:49:00 +00001937 }
1938 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001939 stream.Reset(this);
1940 if (one_byte) {
Steve Blocka7e24c12009-10-30 11:49:00 +00001941 accumulator->Add("<String[%u]: ", length());
1942 for (int i = 0; i < len; i++) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001943 accumulator->Put(static_cast<char>(stream.GetNext()));
Steve Blocka7e24c12009-10-30 11:49:00 +00001944 }
1945 accumulator->Put('>');
1946 } else {
1947 // Backslash indicates that the string contains control
1948 // characters and that backslashes are therefore escaped.
1949 accumulator->Add("<String[%u]\\: ", length());
1950 for (int i = 0; i < len; i++) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001951 uint16_t c = stream.GetNext();
Steve Blocka7e24c12009-10-30 11:49:00 +00001952 if (c == '\n') {
1953 accumulator->Add("\\n");
1954 } else if (c == '\r') {
1955 accumulator->Add("\\r");
1956 } else if (c == '\\') {
1957 accumulator->Add("\\\\");
1958 } else if (c < 32 || c > 126) {
1959 accumulator->Add("\\x%02x", c);
1960 } else {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001961 accumulator->Put(static_cast<char>(c));
Steve Blocka7e24c12009-10-30 11:49:00 +00001962 }
1963 }
1964 if (truncated) {
1965 accumulator->Put('.');
1966 accumulator->Put('.');
1967 accumulator->Put('.');
1968 }
1969 accumulator->Put('>');
1970 }
1971 return;
1972}
1973
1974
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001975void String::PrintUC16(std::ostream& os, int start, int end) { // NOLINT
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001976 if (end < 0) end = length();
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001977 StringCharacterStream stream(this, start);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001978 for (int i = start; i < end && stream.HasMore(); i++) {
1979 os << AsUC16(stream.GetNext());
1980 }
1981}
1982
1983
Steve Blocka7e24c12009-10-30 11:49:00 +00001984void JSObject::JSObjectShortPrint(StringStream* accumulator) {
1985 switch (map()->instance_type()) {
1986 case JS_ARRAY_TYPE: {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001987 double length = JSArray::cast(this)->length()->IsUndefined()
1988 ? 0
1989 : JSArray::cast(this)->length()->Number();
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001990 accumulator->Add("<JS Array[%u]>", static_cast<uint32_t>(length));
Steve Blocka7e24c12009-10-30 11:49:00 +00001991 break;
1992 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001993 case JS_BOUND_FUNCTION_TYPE: {
1994 JSBoundFunction* bound_function = JSBoundFunction::cast(this);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001995 accumulator->Add("<JS BoundFunction");
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001996 accumulator->Add(
1997 " (BoundTargetFunction %p)>",
1998 reinterpret_cast<void*>(bound_function->bound_target_function()));
1999 break;
2000 }
Ben Murdoch69a99ed2011-11-30 16:03:39 +00002001 case JS_WEAK_MAP_TYPE: {
Ben Murdoch3ef787d2012-04-12 10:51:47 +01002002 accumulator->Add("<JS WeakMap>");
Ben Murdoch69a99ed2011-11-30 16:03:39 +00002003 break;
2004 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002005 case JS_WEAK_SET_TYPE: {
2006 accumulator->Add("<JS WeakSet>");
2007 break;
2008 }
Steve Blocka7e24c12009-10-30 11:49:00 +00002009 case JS_REGEXP_TYPE: {
2010 accumulator->Add("<JS RegExp>");
2011 break;
2012 }
2013 case JS_FUNCTION_TYPE: {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002014 JSFunction* function = JSFunction::cast(this);
2015 Object* fun_name = function->shared()->DebugName();
Steve Blocka7e24c12009-10-30 11:49:00 +00002016 bool printed = false;
2017 if (fun_name->IsString()) {
2018 String* str = String::cast(fun_name);
2019 if (str->length() > 0) {
2020 accumulator->Add("<JS Function ");
2021 accumulator->Put(str);
Steve Blocka7e24c12009-10-30 11:49:00 +00002022 printed = true;
2023 }
2024 }
2025 if (!printed) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002026 accumulator->Add("<JS Function");
Steve Blocka7e24c12009-10-30 11:49:00 +00002027 }
Ben Murdochc5610432016-08-08 18:44:38 +01002028 if (FLAG_trace_file_names) {
2029 Object* source_name =
2030 Script::cast(function->shared()->script())->name();
2031 if (source_name->IsString()) {
2032 String* str = String::cast(source_name);
2033 if (str->length() > 0) {
2034 accumulator->Add(" <");
2035 accumulator->Put(str);
2036 accumulator->Add(">");
2037 }
2038 }
2039 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002040 accumulator->Add(" (SharedFunctionInfo %p)",
2041 reinterpret_cast<void*>(function->shared()));
2042 accumulator->Put('>');
2043 break;
2044 }
2045 case JS_GENERATOR_OBJECT_TYPE: {
2046 accumulator->Add("<JS Generator>");
2047 break;
2048 }
2049 case JS_MODULE_TYPE: {
2050 accumulator->Add("<JS Module>");
Steve Blocka7e24c12009-10-30 11:49:00 +00002051 break;
2052 }
2053 // All other JSObjects are rather similar to each other (JSObject,
Ben Murdochda12d292016-06-02 14:46:10 +01002054 // JSGlobalProxy, JSGlobalObject, JSUndetectable, JSValue).
Steve Blocka7e24c12009-10-30 11:49:00 +00002055 default: {
Ben Murdoch8b112d22011-06-08 16:22:53 +01002056 Map* map_of_this = map();
Ben Murdoch3ef787d2012-04-12 10:51:47 +01002057 Heap* heap = GetHeap();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002058 Object* constructor = map_of_this->GetConstructor();
Steve Blocka7e24c12009-10-30 11:49:00 +00002059 bool printed = false;
2060 if (constructor->IsHeapObject() &&
Steve Block44f0eee2011-05-26 01:26:41 +01002061 !heap->Contains(HeapObject::cast(constructor))) {
Steve Blocka7e24c12009-10-30 11:49:00 +00002062 accumulator->Add("!!!INVALID CONSTRUCTOR!!!");
2063 } else {
2064 bool global_object = IsJSGlobalProxy();
2065 if (constructor->IsJSFunction()) {
Steve Block44f0eee2011-05-26 01:26:41 +01002066 if (!heap->Contains(JSFunction::cast(constructor)->shared())) {
Steve Blocka7e24c12009-10-30 11:49:00 +00002067 accumulator->Add("!!!INVALID SHARED ON CONSTRUCTOR!!!");
2068 } else {
2069 Object* constructor_name =
2070 JSFunction::cast(constructor)->shared()->name();
2071 if (constructor_name->IsString()) {
2072 String* str = String::cast(constructor_name);
2073 if (str->length() > 0) {
2074 bool vowel = AnWord(str);
2075 accumulator->Add("<%sa%s ",
2076 global_object ? "Global Object: " : "",
2077 vowel ? "n" : "");
2078 accumulator->Put(str);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002079 accumulator->Add(" with %smap %p",
2080 map_of_this->is_deprecated() ? "deprecated " : "",
2081 map_of_this);
Steve Blocka7e24c12009-10-30 11:49:00 +00002082 printed = true;
2083 }
2084 }
2085 }
2086 }
2087 if (!printed) {
2088 accumulator->Add("<JS %sObject", global_object ? "Global " : "");
2089 }
2090 }
2091 if (IsJSValue()) {
2092 accumulator->Add(" value = ");
2093 JSValue::cast(this)->value()->ShortPrint(accumulator);
2094 }
2095 accumulator->Put('>');
2096 break;
2097 }
2098 }
2099}
2100
2101
Ben Murdoch3ef787d2012-04-12 10:51:47 +01002102void JSObject::PrintElementsTransition(
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002103 FILE* file, Handle<JSObject> object,
2104 ElementsKind from_kind, Handle<FixedArrayBase> from_elements,
2105 ElementsKind to_kind, Handle<FixedArrayBase> to_elements) {
Ben Murdoch3ef787d2012-04-12 10:51:47 +01002106 if (from_kind != to_kind) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002107 OFStream os(file);
2108 os << "elements transition [" << ElementsKindToString(from_kind) << " -> "
2109 << ElementsKindToString(to_kind) << "] in ";
2110 JavaScriptFrame::PrintTop(object->GetIsolate(), file, false, true);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01002111 PrintF(file, " for ");
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002112 object->ShortPrint(file);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01002113 PrintF(file, " from ");
2114 from_elements->ShortPrint(file);
2115 PrintF(file, " to ");
2116 to_elements->ShortPrint(file);
2117 PrintF(file, "\n");
2118 }
2119}
2120
2121
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002122// static
2123MaybeHandle<JSFunction> Map::GetConstructorFunction(
2124 Handle<Map> map, Handle<Context> native_context) {
2125 if (map->IsPrimitiveMap()) {
2126 int const constructor_function_index = map->GetConstructorFunctionIndex();
2127 if (constructor_function_index != kNoConstructorFunctionIndex) {
2128 return handle(
2129 JSFunction::cast(native_context->get(constructor_function_index)));
2130 }
2131 }
2132 return MaybeHandle<JSFunction>();
2133}
2134
2135
2136void Map::PrintReconfiguration(FILE* file, int modify_index, PropertyKind kind,
2137 PropertyAttributes attributes) {
2138 OFStream os(file);
2139 os << "[reconfiguring]";
2140 Name* name = instance_descriptors()->GetKey(modify_index);
2141 if (name->IsString()) {
2142 String::cast(name)->PrintOn(file);
2143 } else {
2144 os << "{symbol " << static_cast<void*>(name) << "}";
2145 }
2146 os << ": " << (kind == kData ? "kData" : "ACCESSORS") << ", attrs: ";
2147 os << attributes << " [";
2148 JavaScriptFrame::PrintTop(GetIsolate(), file, false, true);
2149 os << "]\n";
2150}
2151
Ben Murdoch097c5b22016-05-18 11:27:45 +01002152void Map::PrintGeneralization(
2153 FILE* file, const char* reason, int modify_index, int split,
2154 int descriptors, bool constant_to_field, Representation old_representation,
2155 Representation new_representation, MaybeHandle<FieldType> old_field_type,
2156 MaybeHandle<Object> old_value, MaybeHandle<FieldType> new_field_type,
2157 MaybeHandle<Object> new_value) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002158 OFStream os(file);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002159 os << "[generalizing]";
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002160 Name* name = instance_descriptors()->GetKey(modify_index);
2161 if (name->IsString()) {
2162 String::cast(name)->PrintOn(file);
2163 } else {
2164 os << "{symbol " << static_cast<void*>(name) << "}";
2165 }
2166 os << ":";
2167 if (constant_to_field) {
2168 os << "c";
2169 } else {
2170 os << old_representation.Mnemonic() << "{";
Ben Murdoch097c5b22016-05-18 11:27:45 +01002171 if (old_field_type.is_null()) {
2172 os << Brief(*(old_value.ToHandleChecked()));
2173 } else {
2174 old_field_type.ToHandleChecked()->PrintTo(os);
2175 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002176 os << "}";
2177 }
2178 os << "->" << new_representation.Mnemonic() << "{";
Ben Murdoch097c5b22016-05-18 11:27:45 +01002179 if (new_field_type.is_null()) {
2180 os << Brief(*(new_value.ToHandleChecked()));
2181 } else {
2182 new_field_type.ToHandleChecked()->PrintTo(os);
2183 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002184 os << "} (";
2185 if (strlen(reason) > 0) {
2186 os << reason;
2187 } else {
2188 os << "+" << (descriptors - split) << " maps";
2189 }
2190 os << ") [";
2191 JavaScriptFrame::PrintTop(GetIsolate(), file, false, true);
2192 os << "]\n";
2193}
2194
2195
2196void JSObject::PrintInstanceMigration(FILE* file,
2197 Map* original_map,
2198 Map* new_map) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002199 PrintF(file, "[migrating]");
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002200 DescriptorArray* o = original_map->instance_descriptors();
2201 DescriptorArray* n = new_map->instance_descriptors();
2202 for (int i = 0; i < original_map->NumberOfOwnDescriptors(); i++) {
2203 Representation o_r = o->GetDetails(i).representation();
2204 Representation n_r = n->GetDetails(i).representation();
2205 if (!o_r.Equals(n_r)) {
2206 String::cast(o->GetKey(i))->PrintOn(file);
2207 PrintF(file, ":%s->%s ", o_r.Mnemonic(), n_r.Mnemonic());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002208 } else if (o->GetDetails(i).type() == DATA_CONSTANT &&
2209 n->GetDetails(i).type() == DATA) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002210 Name* name = o->GetKey(i);
2211 if (name->IsString()) {
2212 String::cast(name)->PrintOn(file);
2213 } else {
2214 PrintF(file, "{symbol %p}", static_cast<void*>(name));
2215 }
2216 PrintF(file, " ");
2217 }
2218 }
2219 PrintF(file, "\n");
2220}
2221
2222
Emily Bernierd0a1eb72015-03-24 16:35:39 -04002223void HeapObject::HeapObjectShortPrint(std::ostream& os) { // NOLINT
Steve Block44f0eee2011-05-26 01:26:41 +01002224 Heap* heap = GetHeap();
2225 if (!heap->Contains(this)) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002226 os << "!!!INVALID POINTER!!!";
Steve Blocka7e24c12009-10-30 11:49:00 +00002227 return;
2228 }
Steve Block44f0eee2011-05-26 01:26:41 +01002229 if (!heap->Contains(map())) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002230 os << "!!!INVALID MAP!!!";
Steve Blocka7e24c12009-10-30 11:49:00 +00002231 return;
2232 }
2233
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002234 os << this << " ";
Steve Blocka7e24c12009-10-30 11:49:00 +00002235
2236 if (IsString()) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002237 HeapStringAllocator allocator;
2238 StringStream accumulator(&allocator);
2239 String::cast(this)->StringShortPrint(&accumulator);
2240 os << accumulator.ToCString().get();
Steve Blocka7e24c12009-10-30 11:49:00 +00002241 return;
2242 }
2243 if (IsJSObject()) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002244 HeapStringAllocator allocator;
2245 StringStream accumulator(&allocator);
2246 JSObject::cast(this)->JSObjectShortPrint(&accumulator);
2247 os << accumulator.ToCString().get();
Steve Blocka7e24c12009-10-30 11:49:00 +00002248 return;
2249 }
2250 switch (map()->instance_type()) {
2251 case MAP_TYPE:
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002252 os << "<Map(" << ElementsKindToString(Map::cast(this)->elements_kind())
2253 << ")>";
Steve Blocka7e24c12009-10-30 11:49:00 +00002254 break;
2255 case FIXED_ARRAY_TYPE:
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002256 os << "<FixedArray[" << FixedArray::cast(this)->length() << "]>";
Steve Blocka7e24c12009-10-30 11:49:00 +00002257 break;
Ben Murdoch3ef787d2012-04-12 10:51:47 +01002258 case FIXED_DOUBLE_ARRAY_TYPE:
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002259 os << "<FixedDoubleArray[" << FixedDoubleArray::cast(this)->length()
2260 << "]>";
Ben Murdoch3ef787d2012-04-12 10:51:47 +01002261 break;
Steve Blocka7e24c12009-10-30 11:49:00 +00002262 case BYTE_ARRAY_TYPE:
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002263 os << "<ByteArray[" << ByteArray::cast(this)->length() << "]>";
Steve Blocka7e24c12009-10-30 11:49:00 +00002264 break;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002265 case BYTECODE_ARRAY_TYPE:
2266 os << "<BytecodeArray[" << BytecodeArray::cast(this)->length() << "]>";
2267 break;
2268 case TRANSITION_ARRAY_TYPE:
2269 os << "<TransitionArray[" << TransitionArray::cast(this)->length()
2270 << "]>";
2271 break;
Ben Murdoch3ef787d2012-04-12 10:51:47 +01002272 case FREE_SPACE_TYPE:
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002273 os << "<FreeSpace[" << FreeSpace::cast(this)->size() << "]>";
Ben Murdoch3ef787d2012-04-12 10:51:47 +01002274 break;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002275#define TYPED_ARRAY_SHORT_PRINT(Type, type, TYPE, ctype, size) \
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002276 case FIXED_##TYPE##_ARRAY_TYPE: \
2277 os << "<Fixed" #Type "Array[" << Fixed##Type##Array::cast(this)->length() \
2278 << "]>"; \
2279 break;
2280
2281 TYPED_ARRAYS(TYPED_ARRAY_SHORT_PRINT)
2282#undef TYPED_ARRAY_SHORT_PRINT
2283
2284 case SHARED_FUNCTION_INFO_TYPE: {
2285 SharedFunctionInfo* shared = SharedFunctionInfo::cast(this);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002286 base::SmartArrayPointer<char> debug_name =
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002287 shared->DebugName()->ToCString();
2288 if (debug_name[0] != 0) {
2289 os << "<SharedFunctionInfo " << debug_name.get() << ">";
2290 } else {
2291 os << "<SharedFunctionInfo>";
2292 }
Steve Blocka7e24c12009-10-30 11:49:00 +00002293 break;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002294 }
Steve Block1e0659c2011-05-24 12:43:12 +01002295 case JS_MESSAGE_OBJECT_TYPE:
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002296 os << "<JSMessageObject>";
Steve Block1e0659c2011-05-24 12:43:12 +01002297 break;
Steve Blocka7e24c12009-10-30 11:49:00 +00002298#define MAKE_STRUCT_CASE(NAME, Name, name) \
2299 case NAME##_TYPE: \
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002300 os << "<" #Name ">"; \
Steve Blocka7e24c12009-10-30 11:49:00 +00002301 break;
2302 STRUCT_LIST(MAKE_STRUCT_CASE)
2303#undef MAKE_STRUCT_CASE
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002304 case CODE_TYPE: {
2305 Code* code = Code::cast(this);
2306 os << "<Code: " << Code::Kind2String(code->kind()) << ">";
Steve Blocka7e24c12009-10-30 11:49:00 +00002307 break;
2308 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002309 case ODDBALL_TYPE: {
2310 if (IsUndefined()) {
2311 os << "<undefined>";
2312 } else if (IsTheHole()) {
2313 os << "<the hole>";
2314 } else if (IsNull()) {
2315 os << "<null>";
2316 } else if (IsTrue()) {
2317 os << "<true>";
2318 } else if (IsFalse()) {
2319 os << "<false>";
2320 } else {
Ben Murdochc5610432016-08-08 18:44:38 +01002321 os << "<Odd Oddball: ";
2322 os << Oddball::cast(this)->to_string()->ToCString().get();
2323 os << ">";
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002324 }
Steve Blocka7e24c12009-10-30 11:49:00 +00002325 break;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002326 }
2327 case SYMBOL_TYPE: {
2328 Symbol* symbol = Symbol::cast(this);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04002329 symbol->SymbolShortPrint(os);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002330 break;
2331 }
2332 case HEAP_NUMBER_TYPE: {
2333 os << "<Number: ";
2334 HeapNumber::cast(this)->HeapNumberPrint(os);
2335 os << ">";
2336 break;
2337 }
2338 case MUTABLE_HEAP_NUMBER_TYPE: {
2339 os << "<MutableNumber: ";
2340 HeapNumber::cast(this)->HeapNumberPrint(os);
2341 os << '>';
2342 break;
2343 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002344 case SIMD128_VALUE_TYPE: {
2345#define SIMD128_TYPE(TYPE, Type, type, lane_count, lane_type) \
2346 if (Is##Type()) { \
2347 os << "<" #Type ">"; \
2348 break; \
2349 }
2350 SIMD128_TYPES(SIMD128_TYPE)
2351#undef SIMD128_TYPE
2352 UNREACHABLE();
2353 break;
2354 }
Ben Murdoch589d6972011-11-30 16:04:58 +00002355 case JS_PROXY_TYPE:
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002356 os << "<JSProxy>";
Ben Murdoch589d6972011-11-30 16:04:58 +00002357 break;
Ben Murdoch257744e2011-11-30 15:57:28 +00002358 case FOREIGN_TYPE:
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002359 os << "<Foreign>";
Steve Blocka7e24c12009-10-30 11:49:00 +00002360 break;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002361 case CELL_TYPE: {
2362 os << "Cell for ";
2363 HeapStringAllocator allocator;
2364 StringStream accumulator(&allocator);
2365 Cell::cast(this)->value()->ShortPrint(&accumulator);
2366 os << accumulator.ToCString().get();
Steve Blocka7e24c12009-10-30 11:49:00 +00002367 break;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002368 }
2369 case PROPERTY_CELL_TYPE: {
2370 os << "PropertyCell for ";
2371 HeapStringAllocator allocator;
2372 StringStream accumulator(&allocator);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002373 PropertyCell* cell = PropertyCell::cast(this);
2374 cell->value()->ShortPrint(&accumulator);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002375 os << accumulator.ToCString().get();
2376 break;
2377 }
Emily Bernierd0a1eb72015-03-24 16:35:39 -04002378 case WEAK_CELL_TYPE: {
2379 os << "WeakCell for ";
2380 HeapStringAllocator allocator;
2381 StringStream accumulator(&allocator);
2382 WeakCell::cast(this)->value()->ShortPrint(&accumulator);
2383 os << accumulator.ToCString().get();
2384 break;
2385 }
Steve Blocka7e24c12009-10-30 11:49:00 +00002386 default:
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002387 os << "<Other heap object (" << map()->instance_type() << ")>";
Steve Blocka7e24c12009-10-30 11:49:00 +00002388 break;
2389 }
2390}
2391
2392
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002393void HeapObject::Iterate(ObjectVisitor* v) { IterateFast<ObjectVisitor>(v); }
2394
2395
2396void HeapObject::IterateBody(ObjectVisitor* v) {
Steve Blocka7e24c12009-10-30 11:49:00 +00002397 Map* m = map();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002398 IterateBodyFast<ObjectVisitor>(m->instance_type(), SizeFromMap(m), v);
Steve Blocka7e24c12009-10-30 11:49:00 +00002399}
2400
2401
2402void HeapObject::IterateBody(InstanceType type, int object_size,
2403 ObjectVisitor* v) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002404 IterateBodyFast<ObjectVisitor>(type, object_size, v);
2405}
2406
2407
2408struct CallIsValidSlot {
2409 template <typename BodyDescriptor>
2410 static bool apply(HeapObject* obj, int offset, int) {
2411 return BodyDescriptor::IsValidSlot(obj, offset);
Steve Blocka7e24c12009-10-30 11:49:00 +00002412 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002413};
Steve Blocka7e24c12009-10-30 11:49:00 +00002414
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002415
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002416bool HeapObject::IsValidSlot(int offset) {
2417 DCHECK_NE(0, offset);
2418 return BodyDescriptorApply<CallIsValidSlot, bool>(map()->instance_type(),
2419 this, offset, 0);
Steve Blocka7e24c12009-10-30 11:49:00 +00002420}
2421
2422
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002423bool HeapNumber::HeapNumberBooleanValue() {
2424 return DoubleToBoolean(value());
Steve Blocka7e24c12009-10-30 11:49:00 +00002425}
2426
2427
Emily Bernierd0a1eb72015-03-24 16:35:39 -04002428void HeapNumber::HeapNumberPrint(std::ostream& os) { // NOLINT
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002429 os << value();
Steve Blocka7e24c12009-10-30 11:49:00 +00002430}
2431
2432
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002433#define FIELD_ADDR_CONST(p, offset) \
2434 (reinterpret_cast<const byte*>(p) + offset - kHeapObjectTag)
2435
2436#define READ_INT32_FIELD(p, offset) \
2437 (*reinterpret_cast<const int32_t*>(FIELD_ADDR_CONST(p, offset)))
2438
2439#define READ_INT64_FIELD(p, offset) \
2440 (*reinterpret_cast<const int64_t*>(FIELD_ADDR_CONST(p, offset)))
2441
2442#define READ_BYTE_FIELD(p, offset) \
2443 (*reinterpret_cast<const byte*>(FIELD_ADDR_CONST(p, offset)))
2444
2445
2446// static
2447Handle<String> Simd128Value::ToString(Handle<Simd128Value> input) {
2448#define SIMD128_TYPE(TYPE, Type, type, lane_count, lane_type) \
2449 if (input->Is##Type()) return Type::ToString(Handle<Type>::cast(input));
2450 SIMD128_TYPES(SIMD128_TYPE)
2451#undef SIMD128_TYPE
2452 UNREACHABLE();
2453 return Handle<String>::null();
2454}
2455
2456
2457// static
2458Handle<String> Float32x4::ToString(Handle<Float32x4> input) {
2459 Isolate* const isolate = input->GetIsolate();
2460 char arr[100];
2461 Vector<char> buffer(arr, arraysize(arr));
2462 std::ostringstream os;
2463 os << "SIMD.Float32x4("
2464 << std::string(DoubleToCString(input->get_lane(0), buffer)) << ", "
2465 << std::string(DoubleToCString(input->get_lane(1), buffer)) << ", "
2466 << std::string(DoubleToCString(input->get_lane(2), buffer)) << ", "
2467 << std::string(DoubleToCString(input->get_lane(3), buffer)) << ")";
2468 return isolate->factory()->NewStringFromAsciiChecked(os.str().c_str());
2469}
2470
2471
2472#define SIMD128_BOOL_TO_STRING(Type, lane_count) \
2473 Handle<String> Type::ToString(Handle<Type> input) { \
2474 Isolate* const isolate = input->GetIsolate(); \
2475 std::ostringstream os; \
2476 os << "SIMD." #Type "("; \
2477 os << (input->get_lane(0) ? "true" : "false"); \
2478 for (int i = 1; i < lane_count; i++) { \
2479 os << ", " << (input->get_lane(i) ? "true" : "false"); \
2480 } \
2481 os << ")"; \
2482 return isolate->factory()->NewStringFromAsciiChecked(os.str().c_str()); \
2483 }
2484SIMD128_BOOL_TO_STRING(Bool32x4, 4)
2485SIMD128_BOOL_TO_STRING(Bool16x8, 8)
2486SIMD128_BOOL_TO_STRING(Bool8x16, 16)
2487#undef SIMD128_BOOL_TO_STRING
2488
2489
2490#define SIMD128_INT_TO_STRING(Type, lane_count) \
2491 Handle<String> Type::ToString(Handle<Type> input) { \
2492 Isolate* const isolate = input->GetIsolate(); \
2493 char arr[100]; \
2494 Vector<char> buffer(arr, arraysize(arr)); \
2495 std::ostringstream os; \
2496 os << "SIMD." #Type "("; \
2497 os << IntToCString(input->get_lane(0), buffer); \
2498 for (int i = 1; i < lane_count; i++) { \
2499 os << ", " << IntToCString(input->get_lane(i), buffer); \
2500 } \
2501 os << ")"; \
2502 return isolate->factory()->NewStringFromAsciiChecked(os.str().c_str()); \
2503 }
2504SIMD128_INT_TO_STRING(Int32x4, 4)
2505SIMD128_INT_TO_STRING(Uint32x4, 4)
2506SIMD128_INT_TO_STRING(Int16x8, 8)
2507SIMD128_INT_TO_STRING(Uint16x8, 8)
2508SIMD128_INT_TO_STRING(Int8x16, 16)
2509SIMD128_INT_TO_STRING(Uint8x16, 16)
2510#undef SIMD128_INT_TO_STRING
2511
2512
2513bool Simd128Value::BitwiseEquals(const Simd128Value* other) const {
2514 return READ_INT64_FIELD(this, kValueOffset) ==
2515 READ_INT64_FIELD(other, kValueOffset) &&
2516 READ_INT64_FIELD(this, kValueOffset + kInt64Size) ==
2517 READ_INT64_FIELD(other, kValueOffset + kInt64Size);
2518}
2519
2520
2521uint32_t Simd128Value::Hash() const {
2522 uint32_t seed = v8::internal::kZeroHashSeed;
2523 uint32_t hash;
2524 hash = ComputeIntegerHash(READ_INT32_FIELD(this, kValueOffset), seed);
2525 hash = ComputeIntegerHash(
2526 READ_INT32_FIELD(this, kValueOffset + 1 * kInt32Size), hash * 31);
2527 hash = ComputeIntegerHash(
2528 READ_INT32_FIELD(this, kValueOffset + 2 * kInt32Size), hash * 31);
2529 hash = ComputeIntegerHash(
2530 READ_INT32_FIELD(this, kValueOffset + 3 * kInt32Size), hash * 31);
2531 return hash;
2532}
2533
2534
2535void Simd128Value::CopyBits(void* destination) const {
2536 memcpy(destination, &READ_BYTE_FIELD(this, kValueOffset), kSimd128Size);
2537}
2538
2539
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00002540String* JSReceiver::class_name() {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002541 if (IsFunction()) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002542 return GetHeap()->Function_string();
Steve Blocka7e24c12009-10-30 11:49:00 +00002543 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002544 Object* maybe_constructor = map()->GetConstructor();
2545 if (maybe_constructor->IsJSFunction()) {
2546 JSFunction* constructor = JSFunction::cast(maybe_constructor);
Steve Blocka7e24c12009-10-30 11:49:00 +00002547 return String::cast(constructor->shared()->instance_class_name());
2548 }
2549 // If the constructor is not present, return "Object".
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002550 return GetHeap()->Object_string();
Steve Blocka7e24c12009-10-30 11:49:00 +00002551}
2552
2553
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002554MaybeHandle<String> JSReceiver::BuiltinStringTag(Handle<JSReceiver> object) {
2555 Maybe<bool> is_array = Object::IsArray(object);
2556 MAYBE_RETURN(is_array, MaybeHandle<String>());
2557 Isolate* const isolate = object->GetIsolate();
2558 if (is_array.FromJust()) {
2559 return isolate->factory()->Array_string();
Steve Blocka7e24c12009-10-30 11:49:00 +00002560 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002561 // TODO(adamk): According to ES2015, we should return "Function" when
2562 // object has a [[Call]] internal method (corresponds to IsCallable).
2563 // But this is well cemented in layout tests and might cause webbreakage.
2564 // if (object->IsCallable()) {
2565 // return isolate->factory()->Function_string();
2566 // }
2567 // TODO(adamk): class_name() is expensive, replace with instance type
2568 // checks where possible.
2569 return handle(object->class_name(), isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00002570}
2571
2572
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002573// static
2574Handle<String> JSReceiver::GetConstructorName(Handle<JSReceiver> receiver) {
2575 Isolate* isolate = receiver->GetIsolate();
2576
2577 // If the object was instantiated simply with base == new.target, the
2578 // constructor on the map provides the most accurate name.
2579 // Don't provide the info for prototypes, since their constructors are
2580 // reclaimed and replaced by Object in OptimizeAsPrototype.
2581 if (!receiver->IsJSProxy() && receiver->map()->new_target_is_base() &&
2582 !receiver->map()->is_prototype_map()) {
2583 Object* maybe_constructor = receiver->map()->GetConstructor();
2584 if (maybe_constructor->IsJSFunction()) {
2585 JSFunction* constructor = JSFunction::cast(maybe_constructor);
2586 String* name = String::cast(constructor->shared()->name());
2587 if (name->length() == 0) name = constructor->shared()->inferred_name();
2588 if (name->length() != 0 &&
2589 !name->Equals(isolate->heap()->Object_string())) {
2590 return handle(name, isolate);
2591 }
2592 }
2593 }
2594
Ben Murdochda12d292016-06-02 14:46:10 +01002595 Handle<Object> maybe_tag = JSReceiver::GetDataProperty(
2596 receiver, isolate->factory()->to_string_tag_symbol());
2597 if (maybe_tag->IsString()) return Handle<String>::cast(maybe_tag);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002598
2599 PrototypeIterator iter(isolate, receiver);
2600 if (iter.IsAtEnd()) return handle(receiver->class_name());
2601 Handle<JSReceiver> start = PrototypeIterator::GetCurrent<JSReceiver>(iter);
2602 LookupIterator it(receiver, isolate->factory()->constructor_string(), start,
2603 LookupIterator::PROTOTYPE_CHAIN_SKIP_INTERCEPTOR);
2604 Handle<Object> maybe_constructor = JSReceiver::GetDataProperty(&it);
2605 Handle<String> result = isolate->factory()->Object_string();
2606 if (maybe_constructor->IsJSFunction()) {
2607 JSFunction* constructor = JSFunction::cast(*maybe_constructor);
2608 String* name = String::cast(constructor->shared()->name());
2609 if (name->length() == 0) name = constructor->shared()->inferred_name();
2610 if (name->length() > 0) result = handle(name, isolate);
2611 }
2612
2613 return result.is_identical_to(isolate->factory()->Object_string())
2614 ? handle(receiver->class_name())
2615 : result;
2616}
2617
2618
2619Context* JSReceiver::GetCreationContext() {
Ben Murdoch097c5b22016-05-18 11:27:45 +01002620 JSReceiver* receiver = this;
2621 while (receiver->IsJSBoundFunction()) {
2622 receiver = JSBoundFunction::cast(receiver)->bound_target_function();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002623 }
Ben Murdoch097c5b22016-05-18 11:27:45 +01002624 Object* constructor = receiver->map()->GetConstructor();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002625 JSFunction* function;
2626 if (constructor->IsJSFunction()) {
2627 function = JSFunction::cast(constructor);
2628 } else {
2629 // Functions have null as a constructor,
2630 // but any JSFunction knows its context immediately.
Ben Murdoch097c5b22016-05-18 11:27:45 +01002631 CHECK(receiver->IsJSFunction());
2632 function = JSFunction::cast(receiver);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002633 }
2634
2635 return function->context()->native_context();
2636}
2637
Ben Murdoch097c5b22016-05-18 11:27:45 +01002638static Handle<Object> WrapType(Handle<FieldType> type) {
2639 if (type->IsClass()) return Map::WeakCellForMap(type->AsClass());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002640 return type;
Steve Blocka7e24c12009-10-30 11:49:00 +00002641}
2642
Ben Murdoch097c5b22016-05-18 11:27:45 +01002643MaybeHandle<Map> Map::CopyWithField(Handle<Map> map, Handle<Name> name,
2644 Handle<FieldType> type,
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002645 PropertyAttributes attributes,
2646 Representation representation,
2647 TransitionFlag flag) {
2648 DCHECK(DescriptorArray::kNotFound ==
2649 map->instance_descriptors()->Search(
2650 *name, map->NumberOfOwnDescriptors()));
Ben Murdoch8b112d22011-06-08 16:22:53 +01002651
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002652 // Ensure the descriptor array does not get too big.
2653 if (map->NumberOfOwnDescriptors() >= kMaxNumberOfDescriptors) {
2654 return MaybeHandle<Map>();
Steve Blocka7e24c12009-10-30 11:49:00 +00002655 }
2656
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002657 Isolate* isolate = map->GetIsolate();
2658
Steve Blocka7e24c12009-10-30 11:49:00 +00002659 // Compute the new index for new field.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002660 int index = map->NextFreePropertyIndex();
Steve Blocka7e24c12009-10-30 11:49:00 +00002661
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002662 if (map->instance_type() == JS_CONTEXT_EXTENSION_OBJECT_TYPE) {
2663 representation = Representation::Tagged();
Ben Murdoch097c5b22016-05-18 11:27:45 +01002664 type = FieldType::Any(isolate);
John Reck59135872010-11-02 12:39:01 -07002665 }
Steve Blocka7e24c12009-10-30 11:49:00 +00002666
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002667 Handle<Object> wrapped_type(WrapType(type));
2668
2669 DataDescriptor new_field_desc(name, index, wrapped_type, attributes,
2670 representation);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002671 Handle<Map> new_map = Map::CopyAddDescriptor(map, &new_field_desc, flag);
2672 int unused_property_fields = new_map->unused_property_fields() - 1;
2673 if (unused_property_fields < 0) {
2674 unused_property_fields += JSObject::kFieldsAdded;
John Reck59135872010-11-02 12:39:01 -07002675 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002676 new_map->set_unused_property_fields(unused_property_fields);
2677 return new_map;
Steve Blocka7e24c12009-10-30 11:49:00 +00002678}
2679
2680
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002681MaybeHandle<Map> Map::CopyWithConstant(Handle<Map> map,
2682 Handle<Name> name,
2683 Handle<Object> constant,
2684 PropertyAttributes attributes,
2685 TransitionFlag flag) {
2686 // Ensure the descriptor array does not get too big.
2687 if (map->NumberOfOwnDescriptors() >= kMaxNumberOfDescriptors) {
2688 return MaybeHandle<Map>();
John Reck59135872010-11-02 12:39:01 -07002689 }
Steve Blocka7e24c12009-10-30 11:49:00 +00002690
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002691 // Allocate new instance descriptors with (name, constant) added.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002692 DataConstantDescriptor new_constant_desc(name, constant, attributes);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002693 return Map::CopyAddDescriptor(map, &new_constant_desc, flag);
Steve Blocka7e24c12009-10-30 11:49:00 +00002694}
2695
2696
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002697void JSObject::AddSlowProperty(Handle<JSObject> object,
2698 Handle<Name> name,
2699 Handle<Object> value,
2700 PropertyAttributes attributes) {
2701 DCHECK(!object->HasFastProperties());
2702 Isolate* isolate = object->GetIsolate();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002703 if (object->IsJSGlobalObject()) {
2704 Handle<GlobalDictionary> dict(object->global_dictionary());
2705 PropertyDetails details(attributes, DATA, 0, PropertyCellType::kNoCell);
Steve Blocka7e24c12009-10-30 11:49:00 +00002706 int entry = dict->FindEntry(name);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002707 // If there's a cell there, just invalidate and set the property.
2708 if (entry != GlobalDictionary::kNotFound) {
2709 PropertyCell::UpdateCell(dict, entry, value, details);
2710 // TODO(ishell): move this to UpdateCell.
2711 // Need to adjust the details.
Steve Blocka7e24c12009-10-30 11:49:00 +00002712 int index = dict->NextEnumerationIndex();
Steve Blocka7e24c12009-10-30 11:49:00 +00002713 dict->SetNextEnumerationIndex(index + 1);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002714 PropertyCell* cell = PropertyCell::cast(dict->ValueAt(entry));
2715 details = cell->property_details().set_index(index);
2716 cell->set_property_details(details);
2717
2718 } else {
2719 auto cell = isolate->factory()->NewPropertyCell();
2720 cell->set_value(*value);
2721 auto cell_type = value->IsUndefined() ? PropertyCellType::kUndefined
2722 : PropertyCellType::kConstant;
2723 details = details.set_cell_type(cell_type);
2724 value = cell;
2725
2726 Handle<GlobalDictionary> result =
2727 GlobalDictionary::Add(dict, name, value, details);
2728 if (*dict != *result) object->set_properties(*result);
Steve Blocka7e24c12009-10-30 11:49:00 +00002729 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002730 } else {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002731 Handle<NameDictionary> dict(object->property_dictionary());
2732 PropertyDetails details(attributes, DATA, 0, PropertyCellType::kNoCell);
2733 Handle<NameDictionary> result =
2734 NameDictionary::Add(dict, name, value, details);
2735 if (*dict != *result) object->set_properties(*result);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002736 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002737}
2738
2739
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002740const char* Representation::Mnemonic() const {
2741 switch (kind_) {
2742 case kNone: return "v";
2743 case kTagged: return "t";
2744 case kSmi: return "s";
2745 case kDouble: return "d";
2746 case kInteger32: return "i";
2747 case kHeapObject: return "h";
2748 case kExternal: return "x";
2749 default:
2750 UNREACHABLE();
2751 return NULL;
2752 }
2753}
2754
Ben Murdochc5610432016-08-08 18:44:38 +01002755bool Map::InstancesNeedRewriting(Map* target) {
2756 int target_number_of_fields = target->NumberOfFields();
2757 int target_inobject = target->GetInObjectProperties();
2758 int target_unused = target->unused_property_fields();
2759 int old_number_of_fields;
2760
2761 return InstancesNeedRewriting(target, target_number_of_fields,
2762 target_inobject, target_unused,
2763 &old_number_of_fields);
2764}
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002765
2766bool Map::InstancesNeedRewriting(Map* target, int target_number_of_fields,
2767 int target_inobject, int target_unused,
2768 int* old_number_of_fields) {
2769 // If fields were added (or removed), rewrite the instance.
2770 *old_number_of_fields = NumberOfFields();
2771 DCHECK(target_number_of_fields >= *old_number_of_fields);
2772 if (target_number_of_fields != *old_number_of_fields) return true;
2773
2774 // If smi descriptors were replaced by double descriptors, rewrite.
2775 DescriptorArray* old_desc = instance_descriptors();
2776 DescriptorArray* new_desc = target->instance_descriptors();
2777 int limit = NumberOfOwnDescriptors();
2778 for (int i = 0; i < limit; i++) {
2779 if (new_desc->GetDetails(i).representation().IsDouble() !=
2780 old_desc->GetDetails(i).representation().IsDouble()) {
2781 return true;
Steve Block44f0eee2011-05-26 01:26:41 +01002782 }
Steve Block8defd9f2010-07-08 12:39:36 +01002783 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002784
2785 // If no fields were added, and no inobject properties were removed, setting
2786 // the map is sufficient.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002787 if (target_inobject == GetInObjectProperties()) return false;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002788 // In-object slack tracking may have reduced the object size of the new map.
2789 // In that case, succeed if all existing fields were inobject, and they still
2790 // fit within the new inobject size.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002791 DCHECK(target_inobject < GetInObjectProperties());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002792 if (target_number_of_fields <= target_inobject) {
2793 DCHECK(target_number_of_fields + target_unused == target_inobject);
2794 return false;
2795 }
2796 // Otherwise, properties will need to be moved to the backing store.
2797 return true;
2798}
2799
2800
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002801// static
2802void JSObject::UpdatePrototypeUserRegistration(Handle<Map> old_map,
2803 Handle<Map> new_map,
2804 Isolate* isolate) {
2805 if (!FLAG_track_prototype_users) return;
2806 if (!old_map->is_prototype_map()) return;
2807 DCHECK(new_map->is_prototype_map());
2808 bool was_registered = JSObject::UnregisterPrototypeUser(old_map, isolate);
2809 new_map->set_prototype_info(old_map->prototype_info());
2810 old_map->set_prototype_info(Smi::FromInt(0));
2811 if (FLAG_trace_prototype_users) {
2812 PrintF("Moving prototype_info %p from map %p to map %p.\n",
2813 reinterpret_cast<void*>(new_map->prototype_info()),
2814 reinterpret_cast<void*>(*old_map),
2815 reinterpret_cast<void*>(*new_map));
2816 }
2817 if (was_registered) {
2818 if (new_map->prototype_info()->IsPrototypeInfo()) {
2819 // The new map isn't registered with its prototype yet; reflect this fact
2820 // in the PrototypeInfo it just inherited from the old map.
2821 PrototypeInfo::cast(new_map->prototype_info())
2822 ->set_registry_slot(PrototypeInfo::UNREGISTERED);
2823 }
2824 JSObject::LazyRegisterPrototypeUser(new_map, isolate);
2825 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002826}
2827
Ben Murdoch097c5b22016-05-18 11:27:45 +01002828namespace {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002829// To migrate a fast instance to a fast map:
2830// - First check whether the instance needs to be rewritten. If not, simply
2831// change the map.
2832// - Otherwise, allocate a fixed array large enough to hold all fields, in
2833// addition to unused space.
2834// - Copy all existing properties in, in the following order: backing store
2835// properties, unused fields, inobject properties.
2836// - If all allocation succeeded, commit the state atomically:
2837// * Copy inobject properties from the backing store back into the object.
2838// * Trim the difference in instance size of the object. This also cleanly
2839// frees inobject properties that moved to the backing store.
2840// * If there are properties left in the backing store, trim of the space used
2841// to temporarily store the inobject properties.
2842// * If there are properties left in the backing store, install the backing
2843// store.
Ben Murdoch097c5b22016-05-18 11:27:45 +01002844void MigrateFastToFast(Handle<JSObject> object, Handle<Map> new_map) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002845 Isolate* isolate = object->GetIsolate();
2846 Handle<Map> old_map(object->map());
Ben Murdoch097c5b22016-05-18 11:27:45 +01002847 // In case of a regular transition.
2848 if (new_map->GetBackPointer() == *old_map) {
2849 // If the map does not add named properties, simply set the map.
2850 if (old_map->NumberOfOwnDescriptors() ==
2851 new_map->NumberOfOwnDescriptors()) {
2852 object->synchronized_set_map(*new_map);
2853 return;
2854 }
2855
2856 PropertyDetails details = new_map->GetLastDescriptorDetails();
2857 // Either new_map adds an kDescriptor property, or a kField property for
2858 // which there is still space, and which does not require a mutable double
2859 // box (an out-of-object double).
2860 if (details.location() == kDescriptor ||
2861 (old_map->unused_property_fields() > 0 &&
2862 ((FLAG_unbox_double_fields && object->properties()->length() == 0) ||
2863 !details.representation().IsDouble()))) {
2864 object->synchronized_set_map(*new_map);
2865 return;
2866 }
2867
2868 // If there is still space in the object, we need to allocate a mutable
2869 // double box.
2870 if (old_map->unused_property_fields() > 0) {
2871 FieldIndex index =
2872 FieldIndex::ForDescriptor(*new_map, new_map->LastAdded());
2873 DCHECK(details.representation().IsDouble());
2874 DCHECK(!new_map->IsUnboxedDoubleField(index));
2875 Handle<Object> value = isolate->factory()->NewHeapNumber(0, MUTABLE);
2876 object->RawFastPropertyAtPut(index, *value);
2877 object->synchronized_set_map(*new_map);
2878 return;
2879 }
2880
2881 // This migration is a transition from a map that has run out of property
2882 // space. Extend the backing store.
2883 int grow_by = new_map->unused_property_fields() + 1;
2884 Handle<FixedArray> old_storage = handle(object->properties(), isolate);
2885 Handle<FixedArray> new_storage =
2886 isolate->factory()->CopyFixedArrayAndGrow(old_storage, grow_by);
2887
2888 // Properly initialize newly added property.
2889 Handle<Object> value;
2890 if (details.representation().IsDouble()) {
2891 value = isolate->factory()->NewHeapNumber(0, MUTABLE);
2892 } else {
2893 value = isolate->factory()->uninitialized_value();
2894 }
2895 DCHECK_EQ(DATA, details.type());
2896 int target_index = details.field_index() - new_map->GetInObjectProperties();
2897 DCHECK(target_index >= 0); // Must be a backing store index.
2898 new_storage->set(target_index, *value);
2899
2900 // From here on we cannot fail and we shouldn't GC anymore.
2901 DisallowHeapAllocation no_allocation;
2902
2903 // Set the new property value and do the map transition.
2904 object->set_properties(*new_storage);
2905 object->synchronized_set_map(*new_map);
2906 return;
2907 }
2908
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002909 int old_number_of_fields;
2910 int number_of_fields = new_map->NumberOfFields();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002911 int inobject = new_map->GetInObjectProperties();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002912 int unused = new_map->unused_property_fields();
2913
2914 // Nothing to do if no functions were converted to fields and no smis were
2915 // converted to doubles.
2916 if (!old_map->InstancesNeedRewriting(*new_map, number_of_fields, inobject,
2917 unused, &old_number_of_fields)) {
2918 object->synchronized_set_map(*new_map);
2919 return;
2920 }
2921
2922 int total_size = number_of_fields + unused;
2923 int external = total_size - inobject;
2924
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002925 Handle<FixedArray> array = isolate->factory()->NewFixedArray(total_size);
2926
2927 Handle<DescriptorArray> old_descriptors(old_map->instance_descriptors());
2928 Handle<DescriptorArray> new_descriptors(new_map->instance_descriptors());
2929 int old_nof = old_map->NumberOfOwnDescriptors();
2930 int new_nof = new_map->NumberOfOwnDescriptors();
2931
2932 // This method only supports generalizing instances to at least the same
2933 // number of properties.
2934 DCHECK(old_nof <= new_nof);
2935
2936 for (int i = 0; i < old_nof; i++) {
2937 PropertyDetails details = new_descriptors->GetDetails(i);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002938 if (details.type() != DATA) continue;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002939 PropertyDetails old_details = old_descriptors->GetDetails(i);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04002940 Representation old_representation = old_details.representation();
2941 Representation representation = details.representation();
Emily Bernierd0a1eb72015-03-24 16:35:39 -04002942 Handle<Object> value;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002943 if (old_details.type() == ACCESSOR_CONSTANT) {
2944 // In case of kAccessor -> kData property reconfiguration, the property
2945 // must already be prepared for data or certain type.
2946 DCHECK(!details.representation().IsNone());
2947 if (details.representation().IsDouble()) {
2948 value = isolate->factory()->NewHeapNumber(0, MUTABLE);
2949 } else {
2950 value = isolate->factory()->uninitialized_value();
2951 }
2952 } else if (old_details.type() == DATA_CONSTANT) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -04002953 value = handle(old_descriptors->GetValue(i), isolate);
2954 DCHECK(!old_representation.IsDouble() && !representation.IsDouble());
2955 } else {
2956 FieldIndex index = FieldIndex::ForDescriptor(*old_map, i);
2957 if (object->IsUnboxedDoubleField(index)) {
2958 double old = object->RawFastDoublePropertyAt(index);
2959 value = isolate->factory()->NewHeapNumber(
2960 old, representation.IsDouble() ? MUTABLE : IMMUTABLE);
2961
2962 } else {
2963 value = handle(object->RawFastPropertyAt(index), isolate);
2964 if (!old_representation.IsDouble() && representation.IsDouble()) {
2965 if (old_representation.IsNone()) {
2966 value = handle(Smi::FromInt(0), isolate);
2967 }
2968 value = Object::NewStorageFor(isolate, value, representation);
2969 } else if (old_representation.IsDouble() &&
2970 !representation.IsDouble()) {
2971 value = Object::WrapForRead(isolate, value, old_representation);
2972 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002973 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002974 }
Emily Bernierd0a1eb72015-03-24 16:35:39 -04002975 DCHECK(!(representation.IsDouble() && value->IsSmi()));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002976 int target_index = new_descriptors->GetFieldIndex(i) - inobject;
2977 if (target_index < 0) target_index += total_size;
2978 array->set(target_index, *value);
2979 }
2980
2981 for (int i = old_nof; i < new_nof; i++) {
2982 PropertyDetails details = new_descriptors->GetDetails(i);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002983 if (details.type() != DATA) continue;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002984 Handle<Object> value;
2985 if (details.representation().IsDouble()) {
2986 value = isolate->factory()->NewHeapNumber(0, MUTABLE);
2987 } else {
2988 value = isolate->factory()->uninitialized_value();
2989 }
2990 int target_index = new_descriptors->GetFieldIndex(i) - inobject;
2991 if (target_index < 0) target_index += total_size;
2992 array->set(target_index, *value);
2993 }
2994
2995 // From here on we cannot fail and we shouldn't GC anymore.
2996 DisallowHeapAllocation no_allocation;
2997
Ben Murdoch097c5b22016-05-18 11:27:45 +01002998 Heap* heap = isolate->heap();
2999
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003000 // Copy (real) inobject properties. If necessary, stop at number_of_fields to
3001 // avoid overwriting |one_pointer_filler_map|.
3002 int limit = Min(inobject, number_of_fields);
3003 for (int i = 0; i < limit; i++) {
3004 FieldIndex index = FieldIndex::ForPropertyIndex(*new_map, i);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04003005 Object* value = array->get(external + i);
3006 // Can't use JSObject::FastPropertyAtPut() because proper map was not set
3007 // yet.
3008 if (new_map->IsUnboxedDoubleField(index)) {
3009 DCHECK(value->IsMutableHeapNumber());
3010 object->RawFastDoublePropertyAtPut(index,
3011 HeapNumber::cast(value)->value());
Ben Murdoch097c5b22016-05-18 11:27:45 +01003012 if (i < old_number_of_fields && !old_map->IsUnboxedDoubleField(index)) {
3013 // Transition from tagged to untagged slot.
3014 heap->ClearRecordedSlot(*object,
3015 HeapObject::RawField(*object, index.offset()));
3016 }
Emily Bernierd0a1eb72015-03-24 16:35:39 -04003017 } else {
3018 object->RawFastPropertyAtPut(index, value);
3019 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003020 }
3021
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003022
3023 // If there are properties in the new backing store, trim it to the correct
3024 // size and install the backing store into the object.
3025 if (external > 0) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003026 heap->RightTrimFixedArray<Heap::CONCURRENT_TO_SWEEPER>(*array, inobject);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003027 object->set_properties(*array);
3028 }
3029
3030 // Create filler object past the new instance size.
3031 int new_instance_size = new_map->instance_size();
3032 int instance_size_delta = old_map->instance_size() - new_instance_size;
3033 DCHECK(instance_size_delta >= 0);
3034
3035 if (instance_size_delta > 0) {
3036 Address address = object->address();
Ben Murdochda12d292016-06-02 14:46:10 +01003037 heap->CreateFillerObjectAt(address + new_instance_size, instance_size_delta,
3038 ClearRecordedSlots::kYes);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003039 heap->AdjustLiveBytes(*object, -instance_size_delta,
3040 Heap::CONCURRENT_TO_SWEEPER);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003041 }
3042
3043 // We are storing the new map using release store after creating a filler for
3044 // the left-over space to avoid races with the sweeper thread.
3045 object->synchronized_set_map(*new_map);
3046}
3047
Ben Murdoch097c5b22016-05-18 11:27:45 +01003048void MigrateFastToSlow(Handle<JSObject> object, Handle<Map> new_map,
3049 int expected_additional_properties) {
3050 // The global object is always normalized.
3051 DCHECK(!object->IsJSGlobalObject());
3052 // JSGlobalProxy must never be normalized
3053 DCHECK(!object->IsJSGlobalProxy());
3054
3055 Isolate* isolate = object->GetIsolate();
3056 HandleScope scope(isolate);
3057 Handle<Map> map(object->map());
3058
3059 // Allocate new content.
3060 int real_size = map->NumberOfOwnDescriptors();
3061 int property_count = real_size;
3062 if (expected_additional_properties > 0) {
3063 property_count += expected_additional_properties;
3064 } else {
3065 property_count += 2; // Make space for two more properties.
3066 }
3067 Handle<NameDictionary> dictionary =
3068 NameDictionary::New(isolate, property_count);
3069
3070 Handle<DescriptorArray> descs(map->instance_descriptors());
3071 for (int i = 0; i < real_size; i++) {
3072 PropertyDetails details = descs->GetDetails(i);
3073 Handle<Name> key(descs->GetKey(i));
3074 switch (details.type()) {
3075 case DATA_CONSTANT: {
3076 Handle<Object> value(descs->GetConstant(i), isolate);
3077 PropertyDetails d(details.attributes(), DATA, i + 1,
3078 PropertyCellType::kNoCell);
3079 dictionary = NameDictionary::Add(dictionary, key, value, d);
3080 break;
3081 }
3082 case DATA: {
3083 FieldIndex index = FieldIndex::ForDescriptor(*map, i);
3084 Handle<Object> value;
3085 if (object->IsUnboxedDoubleField(index)) {
3086 double old_value = object->RawFastDoublePropertyAt(index);
3087 value = isolate->factory()->NewHeapNumber(old_value);
3088 } else {
3089 value = handle(object->RawFastPropertyAt(index), isolate);
3090 if (details.representation().IsDouble()) {
3091 DCHECK(value->IsMutableHeapNumber());
3092 Handle<HeapNumber> old = Handle<HeapNumber>::cast(value);
3093 value = isolate->factory()->NewHeapNumber(old->value());
3094 }
3095 }
3096 PropertyDetails d(details.attributes(), DATA, i + 1,
3097 PropertyCellType::kNoCell);
3098 dictionary = NameDictionary::Add(dictionary, key, value, d);
3099 break;
3100 }
3101 case ACCESSOR: {
3102 FieldIndex index = FieldIndex::ForDescriptor(*map, i);
3103 Handle<Object> value(object->RawFastPropertyAt(index), isolate);
3104 PropertyDetails d(details.attributes(), ACCESSOR_CONSTANT, i + 1,
3105 PropertyCellType::kNoCell);
3106 dictionary = NameDictionary::Add(dictionary, key, value, d);
3107 break;
3108 }
3109 case ACCESSOR_CONSTANT: {
3110 Handle<Object> value(descs->GetCallbacksObject(i), isolate);
3111 PropertyDetails d(details.attributes(), ACCESSOR_CONSTANT, i + 1,
3112 PropertyCellType::kNoCell);
3113 dictionary = NameDictionary::Add(dictionary, key, value, d);
3114 break;
3115 }
3116 }
3117 }
3118
3119 // Copy the next enumeration index from instance descriptor.
3120 dictionary->SetNextEnumerationIndex(real_size + 1);
3121
3122 // From here on we cannot fail and we shouldn't GC anymore.
3123 DisallowHeapAllocation no_allocation;
3124
3125 // Resize the object in the heap if necessary.
3126 int new_instance_size = new_map->instance_size();
3127 int instance_size_delta = map->instance_size() - new_instance_size;
3128 DCHECK(instance_size_delta >= 0);
3129
3130 if (instance_size_delta > 0) {
3131 Heap* heap = isolate->heap();
3132 heap->CreateFillerObjectAt(object->address() + new_instance_size,
Ben Murdochda12d292016-06-02 14:46:10 +01003133 instance_size_delta, ClearRecordedSlots::kYes);
Ben Murdoch097c5b22016-05-18 11:27:45 +01003134 heap->AdjustLiveBytes(*object, -instance_size_delta,
3135 Heap::CONCURRENT_TO_SWEEPER);
3136 }
3137
3138 // We are storing the new map using release store after creating a filler for
3139 // the left-over space to avoid races with the sweeper thread.
3140 object->synchronized_set_map(*new_map);
3141
3142 object->set_properties(*dictionary);
3143
3144 // Ensure that in-object space of slow-mode object does not contain random
3145 // garbage.
3146 int inobject_properties = new_map->GetInObjectProperties();
3147 for (int i = 0; i < inobject_properties; i++) {
3148 FieldIndex index = FieldIndex::ForPropertyIndex(*new_map, i);
3149 object->RawFastPropertyAtPut(index, Smi::FromInt(0));
3150 }
3151
3152 isolate->counters()->props_to_dictionary()->Increment();
3153
3154#ifdef DEBUG
3155 if (FLAG_trace_normalization) {
3156 OFStream os(stdout);
3157 os << "Object properties have been normalized:\n";
3158 object->Print(os);
3159 }
3160#endif
3161}
3162
3163} // namespace
3164
3165void JSObject::MigrateToMap(Handle<JSObject> object, Handle<Map> new_map,
3166 int expected_additional_properties) {
3167 if (object->map() == *new_map) return;
3168 Handle<Map> old_map(object->map());
3169 if (old_map->is_prototype_map()) {
3170 // If this object is a prototype (the callee will check), invalidate any
3171 // prototype chains involving it.
3172 InvalidatePrototypeChains(object->map());
3173
3174 // If the map was registered with its prototype before, ensure that it
3175 // registers with its new prototype now. This preserves the invariant that
3176 // when a map on a prototype chain is registered with its prototype, then
3177 // all prototypes further up the chain are also registered with their
3178 // respective prototypes.
3179 UpdatePrototypeUserRegistration(old_map, new_map, new_map->GetIsolate());
3180 }
3181
3182 if (old_map->is_dictionary_map()) {
3183 // For slow-to-fast migrations JSObject::MigrateSlowToFast()
3184 // must be used instead.
3185 CHECK(new_map->is_dictionary_map());
3186
3187 // Slow-to-slow migration is trivial.
3188 object->set_map(*new_map);
3189 } else if (!new_map->is_dictionary_map()) {
3190 MigrateFastToFast(object, new_map);
3191 if (old_map->is_prototype_map()) {
3192 DCHECK(!old_map->is_stable());
3193 DCHECK(new_map->is_stable());
3194 // Clear out the old descriptor array to avoid problems to sharing
3195 // the descriptor array without using an explicit.
3196 old_map->InitializeDescriptors(
3197 old_map->GetHeap()->empty_descriptor_array(),
3198 LayoutDescriptor::FastPointerLayout());
3199 // Ensure that no transition was inserted for prototype migrations.
3200 DCHECK_EQ(
3201 0, TransitionArray::NumberOfTransitions(old_map->raw_transitions()));
3202 DCHECK(new_map->GetBackPointer()->IsUndefined());
3203 }
3204 } else {
3205 MigrateFastToSlow(object, new_map, expected_additional_properties);
3206 }
3207
3208 // Careful: Don't allocate here!
3209 // For some callers of this method, |object| might be in an inconsistent
3210 // state now: the new map might have a new elements_kind, but the object's
3211 // elements pointer hasn't been updated yet. Callers will fix this, but in
3212 // the meantime, (indirectly) calling JSObjectVerify() must be avoided.
3213 // When adding code here, add a DisallowHeapAllocation too.
3214}
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003215
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003216int Map::NumberOfFields() {
3217 DescriptorArray* descriptors = instance_descriptors();
3218 int result = 0;
3219 for (int i = 0; i < NumberOfOwnDescriptors(); i++) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003220 if (descriptors->GetDetails(i).location() == kField) result++;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003221 }
Steve Blocka7e24c12009-10-30 11:49:00 +00003222 return result;
3223}
3224
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003225Handle<Map> Map::CopyGeneralizeAllRepresentations(
Ben Murdochc5610432016-08-08 18:44:38 +01003226 Handle<Map> map, ElementsKind elements_kind, int modify_index,
3227 StoreMode store_mode, PropertyKind kind, PropertyAttributes attributes,
3228 const char* reason) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003229 Isolate* isolate = map->GetIsolate();
Emily Bernierd0a1eb72015-03-24 16:35:39 -04003230 Handle<DescriptorArray> old_descriptors(map->instance_descriptors(), isolate);
3231 int number_of_own_descriptors = map->NumberOfOwnDescriptors();
3232 Handle<DescriptorArray> descriptors =
3233 DescriptorArray::CopyUpTo(old_descriptors, number_of_own_descriptors);
Steve Blocka7e24c12009-10-30 11:49:00 +00003234
Emily Bernierd0a1eb72015-03-24 16:35:39 -04003235 for (int i = 0; i < number_of_own_descriptors; i++) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003236 descriptors->SetRepresentation(i, Representation::Tagged());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003237 if (descriptors->GetDetails(i).type() == DATA) {
Ben Murdoch097c5b22016-05-18 11:27:45 +01003238 descriptors->SetValue(i, FieldType::Any());
John Reck59135872010-11-02 12:39:01 -07003239 }
3240 }
Steve Blocka7e24c12009-10-30 11:49:00 +00003241
Emily Bernierd0a1eb72015-03-24 16:35:39 -04003242 Handle<LayoutDescriptor> new_layout_descriptor(
3243 LayoutDescriptor::FastPointerLayout(), isolate);
3244 Handle<Map> new_map = CopyReplaceDescriptors(
3245 map, descriptors, new_layout_descriptor, OMIT_TRANSITION,
3246 MaybeHandle<Name>(), reason, SPECIAL_TRANSITION);
3247
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003248 // Unless the instance is being migrated, ensure that modify_index is a field.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003249 if (modify_index >= 0) {
3250 PropertyDetails details = descriptors->GetDetails(modify_index);
3251 if (store_mode == FORCE_FIELD &&
3252 (details.type() != DATA || details.attributes() != attributes)) {
3253 int field_index = details.type() == DATA ? details.field_index()
3254 : new_map->NumberOfFields();
3255 DataDescriptor d(handle(descriptors->GetKey(modify_index), isolate),
3256 field_index, attributes, Representation::Tagged());
3257 descriptors->Replace(modify_index, &d);
3258 if (details.type() != DATA) {
3259 int unused_property_fields = new_map->unused_property_fields() - 1;
3260 if (unused_property_fields < 0) {
3261 unused_property_fields += JSObject::kFieldsAdded;
3262 }
3263 new_map->set_unused_property_fields(unused_property_fields);
John Reck59135872010-11-02 12:39:01 -07003264 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003265 } else {
3266 DCHECK(details.attributes() == attributes);
John Reck59135872010-11-02 12:39:01 -07003267 }
Steve Blocka7e24c12009-10-30 11:49:00 +00003268
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003269 if (FLAG_trace_generalization) {
Ben Murdoch097c5b22016-05-18 11:27:45 +01003270 MaybeHandle<FieldType> field_type = FieldType::None(isolate);
3271 if (details.type() == DATA) {
3272 field_type = handle(
3273 map->instance_descriptors()->GetFieldType(modify_index), isolate);
3274 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003275 map->PrintGeneralization(
3276 stdout, reason, modify_index, new_map->NumberOfOwnDescriptors(),
3277 new_map->NumberOfOwnDescriptors(),
3278 details.type() == DATA_CONSTANT && store_mode == FORCE_FIELD,
3279 details.representation(), Representation::Tagged(), field_type,
Ben Murdoch097c5b22016-05-18 11:27:45 +01003280 MaybeHandle<Object>(), FieldType::Any(isolate),
3281 MaybeHandle<Object>());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003282 }
Steve Blocka7e24c12009-10-30 11:49:00 +00003283 }
Ben Murdochc5610432016-08-08 18:44:38 +01003284 new_map->set_elements_kind(elements_kind);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003285 return new_map;
Steve Blocka7e24c12009-10-30 11:49:00 +00003286}
3287
3288
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003289void Map::DeprecateTransitionTree() {
3290 if (is_deprecated()) return;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003291 Object* transitions = raw_transitions();
3292 int num_transitions = TransitionArray::NumberOfTransitions(transitions);
3293 for (int i = 0; i < num_transitions; ++i) {
3294 TransitionArray::GetTarget(transitions, i)->DeprecateTransitionTree();
Steve Blocka7e24c12009-10-30 11:49:00 +00003295 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003296 deprecate();
3297 dependent_code()->DeoptimizeDependentCodeGroup(
3298 GetIsolate(), DependentCode::kTransitionGroup);
3299 NotifyLeafMapLayoutChange();
Steve Blocka7e24c12009-10-30 11:49:00 +00003300}
3301
3302
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003303static inline bool EqualImmutableValues(Object* obj1, Object* obj2) {
3304 if (obj1 == obj2) return true; // Valid for both kData and kAccessor kinds.
3305 // TODO(ishell): compare AccessorPairs.
3306 return false;
3307}
Steve Blocka7e24c12009-10-30 11:49:00 +00003308
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003309
3310// Installs |new_descriptors| over the current instance_descriptors to ensure
3311// proper sharing of descriptor arrays.
3312void Map::ReplaceDescriptors(DescriptorArray* new_descriptors,
3313 LayoutDescriptor* new_layout_descriptor) {
3314 // Don't overwrite the empty descriptor array or initial map's descriptors.
3315 if (NumberOfOwnDescriptors() == 0 || GetBackPointer()->IsUndefined()) {
3316 return;
3317 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003318
3319 DescriptorArray* to_replace = instance_descriptors();
Ben Murdochda12d292016-06-02 14:46:10 +01003320 GetHeap()->incremental_marking()->IterateBlackObject(to_replace);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003321 Map* current = this;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003322 while (current->instance_descriptors() == to_replace) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003323 Object* next = current->GetBackPointer();
3324 if (next->IsUndefined()) break; // Stop overwriting at initial map.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003325 current->SetEnumLength(kInvalidEnumCacheSentinel);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04003326 current->UpdateDescriptors(new_descriptors, new_layout_descriptor);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003327 current = Map::cast(next);
3328 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003329 set_owns_descriptors(false);
3330}
3331
3332
3333Map* Map::FindRootMap() {
3334 Map* result = this;
3335 while (true) {
3336 Object* back = result->GetBackPointer();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003337 if (back->IsUndefined()) {
3338 // Initial map always owns descriptors and doesn't have unused entries
3339 // in the descriptor array.
3340 DCHECK(result->owns_descriptors());
3341 DCHECK_EQ(result->NumberOfOwnDescriptors(),
3342 result->instance_descriptors()->number_of_descriptors());
3343 return result;
3344 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003345 result = Map::cast(back);
3346 }
3347}
3348
3349
3350Map* Map::FindLastMatchMap(int verbatim,
3351 int length,
3352 DescriptorArray* descriptors) {
3353 DisallowHeapAllocation no_allocation;
3354
3355 // This can only be called on roots of transition trees.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003356 DCHECK_EQ(verbatim, NumberOfOwnDescriptors());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003357
3358 Map* current = this;
3359
3360 for (int i = verbatim; i < length; i++) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003361 Name* name = descriptors->GetKey(i);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04003362 PropertyDetails details = descriptors->GetDetails(i);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003363 Map* next = TransitionArray::SearchTransition(current, details.kind(), name,
3364 details.attributes());
3365 if (next == NULL) break;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003366 DescriptorArray* next_descriptors = next->instance_descriptors();
3367
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003368 PropertyDetails next_details = next_descriptors->GetDetails(i);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003369 DCHECK_EQ(details.kind(), next_details.kind());
3370 DCHECK_EQ(details.attributes(), next_details.attributes());
3371 if (details.location() != next_details.location()) break;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003372 if (!details.representation().Equals(next_details.representation())) break;
Steve Blocka7e24c12009-10-30 11:49:00 +00003373
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003374 if (next_details.location() == kField) {
Ben Murdoch097c5b22016-05-18 11:27:45 +01003375 FieldType* next_field_type = next_descriptors->GetFieldType(i);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003376 if (!descriptors->GetFieldType(i)->NowIs(next_field_type)) {
3377 break;
3378 }
3379 } else {
3380 if (!EqualImmutableValues(descriptors->GetValue(i),
3381 next_descriptors->GetValue(i))) {
3382 break;
3383 }
3384 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003385 current = next;
3386 }
3387 return current;
Steve Blocka7e24c12009-10-30 11:49:00 +00003388}
3389
3390
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003391Map* Map::FindFieldOwner(int descriptor) {
3392 DisallowHeapAllocation no_allocation;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003393 DCHECK_EQ(DATA, instance_descriptors()->GetDetails(descriptor).type());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003394 Map* result = this;
3395 while (true) {
3396 Object* back = result->GetBackPointer();
3397 if (back->IsUndefined()) break;
3398 Map* parent = Map::cast(back);
3399 if (parent->NumberOfOwnDescriptors() <= descriptor) break;
3400 result = parent;
Steve Blocka7e24c12009-10-30 11:49:00 +00003401 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003402 return result;
Steve Blocka7e24c12009-10-30 11:49:00 +00003403}
3404
3405
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003406void Map::UpdateFieldType(int descriptor, Handle<Name> name,
Emily Bernierd0a1eb72015-03-24 16:35:39 -04003407 Representation new_representation,
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003408 Handle<Object> new_wrapped_type) {
3409 DCHECK(new_wrapped_type->IsSmi() || new_wrapped_type->IsWeakCell());
Ben Murdochda12d292016-06-02 14:46:10 +01003410 // We store raw pointers in the queue, so no allocations are allowed.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003411 DisallowHeapAllocation no_allocation;
3412 PropertyDetails details = instance_descriptors()->GetDetails(descriptor);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003413 if (details.type() != DATA) return;
Emily Bernierd0a1eb72015-03-24 16:35:39 -04003414
Ben Murdochda12d292016-06-02 14:46:10 +01003415 Zone zone(GetIsolate()->allocator());
3416 ZoneQueue<Map*> backlog(&zone);
3417 backlog.push(this);
3418
3419 while (!backlog.empty()) {
3420 Map* current = backlog.front();
3421 backlog.pop();
3422
3423 Object* transitions = current->raw_transitions();
3424 int num_transitions = TransitionArray::NumberOfTransitions(transitions);
3425 for (int i = 0; i < num_transitions; ++i) {
3426 Map* target = TransitionArray::GetTarget(transitions, i);
3427 backlog.push(target);
3428 }
3429 DescriptorArray* descriptors = current->instance_descriptors();
3430 PropertyDetails details = descriptors->GetDetails(descriptor);
3431
3432 // It is allowed to change representation here only from None to something.
3433 DCHECK(details.representation().Equals(new_representation) ||
3434 details.representation().IsNone());
3435
3436 // Skip if already updated the shared descriptor.
3437 if (descriptors->GetValue(descriptor) != *new_wrapped_type) {
3438 DataDescriptor d(name, descriptors->GetFieldIndex(descriptor),
3439 new_wrapped_type, details.attributes(),
3440 new_representation);
3441 descriptors->Replace(descriptor, &d);
3442 }
3443 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003444}
3445
Ben Murdoch097c5b22016-05-18 11:27:45 +01003446bool FieldTypeIsCleared(Representation rep, FieldType* type) {
3447 return type->IsNone() && rep.IsHeapObject();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003448}
3449
3450
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003451// static
Ben Murdoch097c5b22016-05-18 11:27:45 +01003452Handle<FieldType> Map::GeneralizeFieldType(Representation rep1,
3453 Handle<FieldType> type1,
3454 Representation rep2,
3455 Handle<FieldType> type2,
3456 Isolate* isolate) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003457 // Cleared field types need special treatment. They represent lost knowledge,
3458 // so we must be conservative, so their generalization with any other type
3459 // is "Any".
3460 if (FieldTypeIsCleared(rep1, *type1) || FieldTypeIsCleared(rep2, *type2)) {
Ben Murdoch097c5b22016-05-18 11:27:45 +01003461 return FieldType::Any(isolate);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003462 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003463 if (type1->NowIs(type2)) return type2;
3464 if (type2->NowIs(type1)) return type1;
Ben Murdoch097c5b22016-05-18 11:27:45 +01003465 return FieldType::Any(isolate);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003466}
3467
3468
3469// static
Emily Bernierd0a1eb72015-03-24 16:35:39 -04003470void Map::GeneralizeFieldType(Handle<Map> map, int modify_index,
3471 Representation new_representation,
Ben Murdoch097c5b22016-05-18 11:27:45 +01003472 Handle<FieldType> new_field_type) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003473 Isolate* isolate = map->GetIsolate();
3474
3475 // Check if we actually need to generalize the field type at all.
Emily Bernierd0a1eb72015-03-24 16:35:39 -04003476 Handle<DescriptorArray> old_descriptors(map->instance_descriptors(), isolate);
3477 Representation old_representation =
3478 old_descriptors->GetDetails(modify_index).representation();
Ben Murdoch097c5b22016-05-18 11:27:45 +01003479 Handle<FieldType> old_field_type(old_descriptors->GetFieldType(modify_index),
3480 isolate);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04003481
3482 if (old_representation.Equals(new_representation) &&
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003483 !FieldTypeIsCleared(new_representation, *new_field_type) &&
3484 // Checking old_field_type for being cleared is not necessary because
3485 // the NowIs check below would fail anyway in that case.
Emily Bernierd0a1eb72015-03-24 16:35:39 -04003486 new_field_type->NowIs(old_field_type)) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003487 DCHECK(Map::GeneralizeFieldType(old_representation, old_field_type,
3488 new_representation, new_field_type, isolate)
3489 ->NowIs(old_field_type));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003490 return;
3491 }
3492
3493 // Determine the field owner.
3494 Handle<Map> field_owner(map->FindFieldOwner(modify_index), isolate);
3495 Handle<DescriptorArray> descriptors(
3496 field_owner->instance_descriptors(), isolate);
3497 DCHECK_EQ(*old_field_type, descriptors->GetFieldType(modify_index));
3498
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003499 new_field_type =
3500 Map::GeneralizeFieldType(old_representation, old_field_type,
3501 new_representation, new_field_type, isolate);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003502
3503 PropertyDetails details = descriptors->GetDetails(modify_index);
3504 Handle<Name> name(descriptors->GetKey(modify_index));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003505
3506 Handle<Object> wrapped_type(WrapType(new_field_type));
Emily Bernierd0a1eb72015-03-24 16:35:39 -04003507 field_owner->UpdateFieldType(modify_index, name, new_representation,
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003508 wrapped_type);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003509 field_owner->dependent_code()->DeoptimizeDependentCodeGroup(
3510 isolate, DependentCode::kFieldTypeGroup);
3511
3512 if (FLAG_trace_generalization) {
3513 map->PrintGeneralization(
Ben Murdoch097c5b22016-05-18 11:27:45 +01003514 stdout, "field type generalization", modify_index,
3515 map->NumberOfOwnDescriptors(), map->NumberOfOwnDescriptors(), false,
3516 details.representation(), details.representation(), old_field_type,
3517 MaybeHandle<Object>(), new_field_type, MaybeHandle<Object>());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003518 }
3519}
3520
Ben Murdoch097c5b22016-05-18 11:27:45 +01003521static inline Handle<FieldType> GetFieldType(
3522 Isolate* isolate, Handle<DescriptorArray> descriptors, int descriptor,
3523 PropertyLocation location, Representation representation) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003524#ifdef DEBUG
3525 PropertyDetails details = descriptors->GetDetails(descriptor);
3526 DCHECK_EQ(kData, details.kind());
3527 DCHECK_EQ(details.location(), location);
3528#endif
3529 if (location == kField) {
3530 return handle(descriptors->GetFieldType(descriptor), isolate);
3531 } else {
3532 return descriptors->GetValue(descriptor)
3533 ->OptimalType(isolate, representation);
3534 }
3535}
3536
Ben Murdochc5610432016-08-08 18:44:38 +01003537// Reconfigures elements kind to |new_elements_kind| and/or property at
3538// |modify_index| with |new_kind|, |new_attributes|, |store_mode| and/or
3539// |new_representation|/|new_field_type|.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003540// If |modify_index| is negative then no properties are reconfigured but the
3541// map is migrated to the up-to-date non-deprecated state.
3542//
3543// This method rewrites or completes the transition tree to reflect the new
3544// change. To avoid high degrees over polymorphism, and to stabilize quickly,
3545// on every rewrite the new type is deduced by merging the current type with
3546// any potential new (partial) version of the type in the transition tree.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003547// To do this, on each rewrite:
3548// - Search the root of the transition tree using FindRootMap.
Ben Murdochc5610432016-08-08 18:44:38 +01003549// - Find/create a |root_map| with requested |new_elements_kind|.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003550// - Find |target_map|, the newest matching version of this map using the
3551// virtually "enhanced" |old_map|'s descriptor array (i.e. whose entry at
3552// |modify_index| is considered to be of |new_kind| and having
3553// |new_attributes|) to walk the transition tree.
3554// - Merge/generalize the "enhanced" descriptor array of the |old_map| and
3555// descriptor array of the |target_map|.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003556// - Generalize the |modify_index| descriptor using |new_representation| and
3557// |new_field_type|.
3558// - Walk the tree again starting from the root towards |target_map|. Stop at
3559// |split_map|, the first map who's descriptor array does not match the merged
3560// descriptor array.
3561// - If |target_map| == |split_map|, |target_map| is in the expected state.
3562// Return it.
3563// - Otherwise, invalidate the outdated transition target from |target_map|, and
3564// replace its transition tree with a new branch for the updated descriptors.
Ben Murdochc5610432016-08-08 18:44:38 +01003565Handle<Map> Map::Reconfigure(Handle<Map> old_map,
3566 ElementsKind new_elements_kind, int modify_index,
3567 PropertyKind new_kind,
3568 PropertyAttributes new_attributes,
3569 Representation new_representation,
3570 Handle<FieldType> new_field_type,
3571 StoreMode store_mode) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003572 DCHECK_NE(kAccessor, new_kind); // TODO(ishell): not supported yet.
3573 DCHECK(store_mode != FORCE_FIELD || modify_index >= 0);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003574 Isolate* isolate = old_map->GetIsolate();
3575
3576 Handle<DescriptorArray> old_descriptors(
3577 old_map->instance_descriptors(), isolate);
3578 int old_nof = old_map->NumberOfOwnDescriptors();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003579
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003580 // If it's just a representation generalization case (i.e. property kind and
3581 // attributes stays unchanged) it's fine to transition from None to anything
3582 // but double without any modification to the object, because the default
3583 // uninitialized value for representation None can be overwritten by both
3584 // smi and tagged values. Doubles, however, would require a box allocation.
3585 if (modify_index >= 0 && !new_representation.IsNone() &&
Ben Murdochc5610432016-08-08 18:44:38 +01003586 !new_representation.IsDouble() &&
3587 old_map->elements_kind() == new_elements_kind) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003588 PropertyDetails old_details = old_descriptors->GetDetails(modify_index);
3589 Representation old_representation = old_details.representation();
Emily Bernierd0a1eb72015-03-24 16:35:39 -04003590
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003591 if (old_representation.IsNone()) {
3592 DCHECK_EQ(new_kind, old_details.kind());
3593 DCHECK_EQ(new_attributes, old_details.attributes());
3594 DCHECK_EQ(DATA, old_details.type());
3595 if (FLAG_trace_generalization) {
3596 old_map->PrintGeneralization(
3597 stdout, "uninitialized field", modify_index,
3598 old_map->NumberOfOwnDescriptors(),
3599 old_map->NumberOfOwnDescriptors(), false, old_representation,
Ben Murdoch097c5b22016-05-18 11:27:45 +01003600 new_representation,
3601 handle(old_descriptors->GetFieldType(modify_index), isolate),
3602 MaybeHandle<Object>(), new_field_type, MaybeHandle<Object>());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003603 }
3604 Handle<Map> field_owner(old_map->FindFieldOwner(modify_index), isolate);
3605
3606 GeneralizeFieldType(field_owner, modify_index, new_representation,
3607 new_field_type);
3608 DCHECK(old_descriptors->GetDetails(modify_index)
3609 .representation()
3610 .Equals(new_representation));
3611 DCHECK(
3612 old_descriptors->GetFieldType(modify_index)->NowIs(new_field_type));
3613 return old_map;
3614 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003615 }
3616
3617 // Check the state of the root map.
3618 Handle<Map> root_map(old_map->FindRootMap(), isolate);
3619 if (!old_map->EquivalentToForTransition(*root_map)) {
Ben Murdochc5610432016-08-08 18:44:38 +01003620 return CopyGeneralizeAllRepresentations(
3621 old_map, new_elements_kind, modify_index, store_mode, new_kind,
3622 new_attributes, "GenAll_NotEquivalent");
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003623 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003624
3625 ElementsKind from_kind = root_map->elements_kind();
Ben Murdochc5610432016-08-08 18:44:38 +01003626 ElementsKind to_kind = new_elements_kind;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003627 // TODO(ishell): Add a test for SLOW_SLOPPY_ARGUMENTS_ELEMENTS.
3628 if (from_kind != to_kind && to_kind != DICTIONARY_ELEMENTS &&
Ben Murdochc5610432016-08-08 18:44:38 +01003629 to_kind != SLOW_STRING_WRAPPER_ELEMENTS &&
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003630 to_kind != SLOW_SLOPPY_ARGUMENTS_ELEMENTS &&
3631 !(IsTransitionableFastElementsKind(from_kind) &&
3632 IsMoreGeneralElementsKindTransition(from_kind, to_kind))) {
Ben Murdochc5610432016-08-08 18:44:38 +01003633 return CopyGeneralizeAllRepresentations(
3634 old_map, to_kind, modify_index, store_mode, new_kind, new_attributes,
3635 "GenAll_InvalidElementsTransition");
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003636 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003637 int root_nof = root_map->NumberOfOwnDescriptors();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003638 if (modify_index >= 0 && modify_index < root_nof) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003639 PropertyDetails old_details = old_descriptors->GetDetails(modify_index);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003640 if (old_details.kind() != new_kind ||
3641 old_details.attributes() != new_attributes) {
Ben Murdochc5610432016-08-08 18:44:38 +01003642 return CopyGeneralizeAllRepresentations(
3643 old_map, to_kind, modify_index, store_mode, new_kind, new_attributes,
3644 "GenAll_RootModification1");
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003645 }
3646 if ((old_details.type() != DATA && store_mode == FORCE_FIELD) ||
3647 (old_details.type() == DATA &&
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003648 (!new_field_type->NowIs(old_descriptors->GetFieldType(modify_index)) ||
3649 !new_representation.fits_into(old_details.representation())))) {
Ben Murdochc5610432016-08-08 18:44:38 +01003650 return CopyGeneralizeAllRepresentations(
3651 old_map, to_kind, modify_index, store_mode, new_kind, new_attributes,
3652 "GenAll_RootModification2");
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003653 }
3654 }
3655
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003656 // From here on, use the map with correct elements kind as root map.
3657 if (from_kind != to_kind) {
3658 root_map = Map::AsElementsKind(root_map, to_kind);
3659 }
3660
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003661 Handle<Map> target_map = root_map;
3662 for (int i = root_nof; i < old_nof; ++i) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -04003663 PropertyDetails old_details = old_descriptors->GetDetails(i);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003664 PropertyKind next_kind;
3665 PropertyLocation next_location;
3666 PropertyAttributes next_attributes;
3667 Representation next_representation;
3668 bool property_kind_reconfiguration = false;
3669
3670 if (modify_index == i) {
3671 DCHECK_EQ(FORCE_FIELD, store_mode);
3672 property_kind_reconfiguration = old_details.kind() != new_kind;
3673
3674 next_kind = new_kind;
3675 next_location = kField;
3676 next_attributes = new_attributes;
3677 // If property kind is not reconfigured merge the result with
3678 // representation/field type from the old descriptor.
3679 next_representation = new_representation;
3680 if (!property_kind_reconfiguration) {
3681 next_representation =
3682 next_representation.generalize(old_details.representation());
3683 }
3684
3685 } else {
3686 next_kind = old_details.kind();
3687 next_location = old_details.location();
3688 next_attributes = old_details.attributes();
3689 next_representation = old_details.representation();
3690 }
3691 Map* transition = TransitionArray::SearchTransition(
3692 *target_map, next_kind, old_descriptors->GetKey(i), next_attributes);
3693 if (transition == NULL) break;
3694 Handle<Map> tmp_map(transition, isolate);
3695
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003696 Handle<DescriptorArray> tmp_descriptors = handle(
3697 tmp_map->instance_descriptors(), isolate);
3698
3699 // Check if target map is incompatible.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003700 PropertyDetails tmp_details = tmp_descriptors->GetDetails(i);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003701 DCHECK_EQ(next_kind, tmp_details.kind());
3702 DCHECK_EQ(next_attributes, tmp_details.attributes());
3703 if (next_kind == kAccessor &&
3704 !EqualImmutableValues(old_descriptors->GetValue(i),
3705 tmp_descriptors->GetValue(i))) {
Ben Murdochc5610432016-08-08 18:44:38 +01003706 return CopyGeneralizeAllRepresentations(
3707 old_map, to_kind, modify_index, store_mode, new_kind, new_attributes,
3708 "GenAll_Incompatible");
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003709 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003710 if (next_location == kField && tmp_details.location() == kDescriptor) break;
3711
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003712 Representation tmp_representation = tmp_details.representation();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003713 if (!next_representation.fits_into(tmp_representation)) break;
3714
3715 PropertyLocation old_location = old_details.location();
3716 PropertyLocation tmp_location = tmp_details.location();
3717 if (tmp_location == kField) {
3718 if (next_kind == kData) {
Ben Murdoch097c5b22016-05-18 11:27:45 +01003719 Handle<FieldType> next_field_type;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003720 if (modify_index == i) {
3721 next_field_type = new_field_type;
3722 if (!property_kind_reconfiguration) {
Ben Murdoch097c5b22016-05-18 11:27:45 +01003723 Handle<FieldType> old_field_type =
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003724 GetFieldType(isolate, old_descriptors, i,
3725 old_details.location(), tmp_representation);
3726 Representation old_representation = old_details.representation();
3727 next_field_type = GeneralizeFieldType(
3728 old_representation, old_field_type, new_representation,
3729 next_field_type, isolate);
3730 }
3731 } else {
Ben Murdoch097c5b22016-05-18 11:27:45 +01003732 Handle<FieldType> old_field_type =
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003733 GetFieldType(isolate, old_descriptors, i, old_details.location(),
3734 tmp_representation);
3735 next_field_type = old_field_type;
3736 }
3737 GeneralizeFieldType(tmp_map, i, tmp_representation, next_field_type);
3738 }
3739 } else if (old_location == kField ||
3740 !EqualImmutableValues(old_descriptors->GetValue(i),
3741 tmp_descriptors->GetValue(i))) {
Ben Murdoch7d3e7fc2011-07-12 16:37:06 +01003742 break;
Steve Blocka7e24c12009-10-30 11:49:00 +00003743 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003744 DCHECK(!tmp_map->is_deprecated());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003745 target_map = tmp_map;
Steve Blocka7e24c12009-10-30 11:49:00 +00003746 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003747
3748 // Directly change the map if the target map is more general.
3749 Handle<DescriptorArray> target_descriptors(
3750 target_map->instance_descriptors(), isolate);
3751 int target_nof = target_map->NumberOfOwnDescriptors();
3752 if (target_nof == old_nof &&
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003753 (store_mode != FORCE_FIELD ||
3754 (modify_index >= 0 &&
3755 target_descriptors->GetDetails(modify_index).location() == kField))) {
3756#ifdef DEBUG
3757 if (modify_index >= 0) {
3758 PropertyDetails details = target_descriptors->GetDetails(modify_index);
3759 DCHECK_EQ(new_kind, details.kind());
3760 DCHECK_EQ(new_attributes, details.attributes());
3761 DCHECK(new_representation.fits_into(details.representation()));
3762 DCHECK(details.location() != kField ||
3763 new_field_type->NowIs(
3764 target_descriptors->GetFieldType(modify_index)));
3765 }
3766#endif
3767 if (*target_map != *old_map) {
3768 old_map->NotifyLeafMapLayoutChange();
3769 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003770 return target_map;
3771 }
3772
3773 // Find the last compatible target map in the transition tree.
3774 for (int i = target_nof; i < old_nof; ++i) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -04003775 PropertyDetails old_details = old_descriptors->GetDetails(i);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003776 PropertyKind next_kind;
3777 PropertyAttributes next_attributes;
3778 if (modify_index == i) {
3779 next_kind = new_kind;
3780 next_attributes = new_attributes;
3781 } else {
3782 next_kind = old_details.kind();
3783 next_attributes = old_details.attributes();
3784 }
3785 Map* transition = TransitionArray::SearchTransition(
3786 *target_map, next_kind, old_descriptors->GetKey(i), next_attributes);
3787 if (transition == NULL) break;
3788 Handle<Map> tmp_map(transition, isolate);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003789 Handle<DescriptorArray> tmp_descriptors(
3790 tmp_map->instance_descriptors(), isolate);
3791
3792 // Check if target map is compatible.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003793#ifdef DEBUG
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003794 PropertyDetails tmp_details = tmp_descriptors->GetDetails(i);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003795 DCHECK_EQ(next_kind, tmp_details.kind());
3796 DCHECK_EQ(next_attributes, tmp_details.attributes());
3797#endif
3798 if (next_kind == kAccessor &&
3799 !EqualImmutableValues(old_descriptors->GetValue(i),
3800 tmp_descriptors->GetValue(i))) {
Ben Murdochc5610432016-08-08 18:44:38 +01003801 return CopyGeneralizeAllRepresentations(
3802 old_map, to_kind, modify_index, store_mode, new_kind, new_attributes,
3803 "GenAll_Incompatible");
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003804 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003805 DCHECK(!tmp_map->is_deprecated());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003806 target_map = tmp_map;
3807 }
3808 target_nof = target_map->NumberOfOwnDescriptors();
3809 target_descriptors = handle(target_map->instance_descriptors(), isolate);
3810
3811 // Allocate a new descriptor array large enough to hold the required
3812 // descriptors, with minimally the exact same size as the old descriptor
3813 // array.
3814 int new_slack = Max(
3815 old_nof, old_descriptors->number_of_descriptors()) - old_nof;
3816 Handle<DescriptorArray> new_descriptors = DescriptorArray::Allocate(
3817 isolate, old_nof, new_slack);
3818 DCHECK(new_descriptors->length() > target_descriptors->length() ||
3819 new_descriptors->NumberOfSlackDescriptors() > 0 ||
3820 new_descriptors->number_of_descriptors() ==
3821 old_descriptors->number_of_descriptors());
3822 DCHECK(new_descriptors->number_of_descriptors() == old_nof);
3823
3824 // 0 -> |root_nof|
3825 int current_offset = 0;
3826 for (int i = 0; i < root_nof; ++i) {
3827 PropertyDetails old_details = old_descriptors->GetDetails(i);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003828 if (old_details.location() == kField) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -04003829 current_offset += old_details.field_width_in_words();
3830 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003831 Descriptor d(handle(old_descriptors->GetKey(i), isolate),
3832 handle(old_descriptors->GetValue(i), isolate),
3833 old_details);
3834 new_descriptors->Set(i, &d);
3835 }
3836
3837 // |root_nof| -> |target_nof|
3838 for (int i = root_nof; i < target_nof; ++i) {
3839 Handle<Name> target_key(target_descriptors->GetKey(i), isolate);
3840 PropertyDetails old_details = old_descriptors->GetDetails(i);
3841 PropertyDetails target_details = target_descriptors->GetDetails(i);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003842
3843 PropertyKind next_kind;
3844 PropertyAttributes next_attributes;
3845 PropertyLocation next_location;
3846 Representation next_representation;
3847 bool property_kind_reconfiguration = false;
3848
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003849 if (modify_index == i) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003850 DCHECK_EQ(FORCE_FIELD, store_mode);
3851 property_kind_reconfiguration = old_details.kind() != new_kind;
3852
3853 next_kind = new_kind;
3854 next_attributes = new_attributes;
3855 next_location = kField;
3856
3857 // Merge new representation/field type with ones from the target
3858 // descriptor. If property kind is not reconfigured merge the result with
3859 // representation/field type from the old descriptor.
3860 next_representation =
3861 new_representation.generalize(target_details.representation());
3862 if (!property_kind_reconfiguration) {
3863 next_representation =
3864 next_representation.generalize(old_details.representation());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003865 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003866 } else {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003867 // Merge old_descriptor and target_descriptor entries.
3868 DCHECK_EQ(target_details.kind(), old_details.kind());
3869 next_kind = target_details.kind();
3870 next_attributes = target_details.attributes();
3871 next_location =
3872 old_details.location() == kField ||
3873 target_details.location() == kField ||
3874 !EqualImmutableValues(target_descriptors->GetValue(i),
3875 old_descriptors->GetValue(i))
3876 ? kField
3877 : kDescriptor;
3878
3879 next_representation = old_details.representation().generalize(
3880 target_details.representation());
3881 }
3882 DCHECK_EQ(next_kind, target_details.kind());
3883 DCHECK_EQ(next_attributes, target_details.attributes());
3884
3885 if (next_location == kField) {
3886 if (next_kind == kData) {
Ben Murdoch097c5b22016-05-18 11:27:45 +01003887 Handle<FieldType> target_field_type =
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003888 GetFieldType(isolate, target_descriptors, i,
3889 target_details.location(), next_representation);
3890
Ben Murdoch097c5b22016-05-18 11:27:45 +01003891 Handle<FieldType> next_field_type;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003892 if (modify_index == i) {
3893 next_field_type = GeneralizeFieldType(
3894 target_details.representation(), target_field_type,
3895 new_representation, new_field_type, isolate);
3896 if (!property_kind_reconfiguration) {
Ben Murdoch097c5b22016-05-18 11:27:45 +01003897 Handle<FieldType> old_field_type =
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003898 GetFieldType(isolate, old_descriptors, i,
3899 old_details.location(), next_representation);
3900 next_field_type = GeneralizeFieldType(
3901 old_details.representation(), old_field_type,
3902 next_representation, next_field_type, isolate);
3903 }
3904 } else {
Ben Murdoch097c5b22016-05-18 11:27:45 +01003905 Handle<FieldType> old_field_type =
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003906 GetFieldType(isolate, old_descriptors, i, old_details.location(),
3907 next_representation);
3908 next_field_type = GeneralizeFieldType(
3909 old_details.representation(), old_field_type, next_representation,
3910 target_field_type, isolate);
3911 }
3912 Handle<Object> wrapped_type(WrapType(next_field_type));
3913 DataDescriptor d(target_key, current_offset, wrapped_type,
3914 next_attributes, next_representation);
3915 current_offset += d.GetDetails().field_width_in_words();
3916 new_descriptors->Set(i, &d);
3917 } else {
3918 UNIMPLEMENTED(); // TODO(ishell): implement.
3919 }
3920 } else {
3921 PropertyDetails details(next_attributes, next_kind, next_location,
3922 next_representation);
3923 Descriptor d(target_key, handle(target_descriptors->GetValue(i), isolate),
3924 details);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003925 new_descriptors->Set(i, &d);
3926 }
3927 }
3928
3929 // |target_nof| -> |old_nof|
3930 for (int i = target_nof; i < old_nof; ++i) {
3931 PropertyDetails old_details = old_descriptors->GetDetails(i);
3932 Handle<Name> old_key(old_descriptors->GetKey(i), isolate);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003933
3934 // Merge old_descriptor entry and modified details together.
3935 PropertyKind next_kind;
3936 PropertyAttributes next_attributes;
3937 PropertyLocation next_location;
3938 Representation next_representation;
3939 bool property_kind_reconfiguration = false;
3940
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003941 if (modify_index == i) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003942 DCHECK_EQ(FORCE_FIELD, store_mode);
3943 // In case of property kind reconfiguration it is not necessary to
3944 // take into account representation/field type of the old descriptor.
3945 property_kind_reconfiguration = old_details.kind() != new_kind;
3946
3947 next_kind = new_kind;
3948 next_attributes = new_attributes;
3949 next_location = kField;
3950 next_representation = new_representation;
3951 if (!property_kind_reconfiguration) {
3952 next_representation =
3953 next_representation.generalize(old_details.representation());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003954 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003955 } else {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003956 next_kind = old_details.kind();
3957 next_attributes = old_details.attributes();
3958 next_location = old_details.location();
3959 next_representation = old_details.representation();
3960 }
3961
3962 if (next_location == kField) {
3963 if (next_kind == kData) {
Ben Murdoch097c5b22016-05-18 11:27:45 +01003964 Handle<FieldType> next_field_type;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003965 if (modify_index == i) {
3966 next_field_type = new_field_type;
3967 if (!property_kind_reconfiguration) {
Ben Murdoch097c5b22016-05-18 11:27:45 +01003968 Handle<FieldType> old_field_type =
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003969 GetFieldType(isolate, old_descriptors, i,
3970 old_details.location(), next_representation);
3971 next_field_type = GeneralizeFieldType(
3972 old_details.representation(), old_field_type,
3973 next_representation, next_field_type, isolate);
3974 }
3975 } else {
Ben Murdoch097c5b22016-05-18 11:27:45 +01003976 Handle<FieldType> old_field_type =
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003977 GetFieldType(isolate, old_descriptors, i, old_details.location(),
3978 next_representation);
3979 next_field_type = old_field_type;
3980 }
3981
3982 Handle<Object> wrapped_type(WrapType(next_field_type));
3983
3984 DataDescriptor d(old_key, current_offset, wrapped_type, next_attributes,
3985 next_representation);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04003986 current_offset += d.GetDetails().field_width_in_words();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003987 new_descriptors->Set(i, &d);
3988 } else {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003989 UNIMPLEMENTED(); // TODO(ishell): implement.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003990 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003991 } else {
3992 PropertyDetails details(next_attributes, next_kind, next_location,
3993 next_representation);
3994 Descriptor d(old_key, handle(old_descriptors->GetValue(i), isolate),
3995 details);
3996 new_descriptors->Set(i, &d);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003997 }
3998 }
3999
4000 new_descriptors->Sort();
4001
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004002 DCHECK(store_mode != FORCE_FIELD ||
4003 new_descriptors->GetDetails(modify_index).location() == kField);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004004
4005 Handle<Map> split_map(root_map->FindLastMatchMap(
4006 root_nof, old_nof, *new_descriptors), isolate);
4007 int split_nof = split_map->NumberOfOwnDescriptors();
4008 DCHECK_NE(old_nof, split_nof);
4009
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004010 PropertyKind split_kind;
4011 PropertyAttributes split_attributes;
4012 if (modify_index == split_nof) {
4013 split_kind = new_kind;
4014 split_attributes = new_attributes;
4015 } else {
4016 PropertyDetails split_prop_details = old_descriptors->GetDetails(split_nof);
4017 split_kind = split_prop_details.kind();
4018 split_attributes = split_prop_details.attributes();
4019 }
Emily Bernierd0a1eb72015-03-24 16:35:39 -04004020
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004021 // Invalidate a transition target at |key|.
4022 Map* maybe_transition = TransitionArray::SearchTransition(
4023 *split_map, split_kind, old_descriptors->GetKey(split_nof),
4024 split_attributes);
4025 if (maybe_transition != NULL) {
4026 maybe_transition->DeprecateTransitionTree();
4027 }
4028
4029 // If |maybe_transition| is not NULL then the transition array already
4030 // contains entry for given descriptor. This means that the transition
Emily Bernierd0a1eb72015-03-24 16:35:39 -04004031 // could be inserted regardless of whether transitions array is full or not.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004032 if (maybe_transition == NULL &&
4033 !TransitionArray::CanHaveMoreTransitions(split_map)) {
Ben Murdochc5610432016-08-08 18:44:38 +01004034 return CopyGeneralizeAllRepresentations(
4035 old_map, to_kind, modify_index, store_mode, new_kind, new_attributes,
4036 "GenAll_CantHaveMoreTransitions");
Emily Bernierd0a1eb72015-03-24 16:35:39 -04004037 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004038
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004039 old_map->NotifyLeafMapLayoutChange();
4040
4041 if (FLAG_trace_generalization && modify_index >= 0) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004042 PropertyDetails old_details = old_descriptors->GetDetails(modify_index);
4043 PropertyDetails new_details = new_descriptors->GetDetails(modify_index);
Ben Murdoch097c5b22016-05-18 11:27:45 +01004044 MaybeHandle<FieldType> old_field_type;
4045 MaybeHandle<FieldType> new_field_type;
4046 MaybeHandle<Object> old_value;
4047 MaybeHandle<Object> new_value;
4048 if (old_details.type() == DATA) {
4049 old_field_type =
4050 handle(old_descriptors->GetFieldType(modify_index), isolate);
4051 } else {
4052 old_value = handle(old_descriptors->GetValue(modify_index), isolate);
4053 }
4054 if (new_details.type() == DATA) {
4055 new_field_type =
4056 handle(new_descriptors->GetFieldType(modify_index), isolate);
4057 } else {
4058 new_value = handle(new_descriptors->GetValue(modify_index), isolate);
4059 }
4060
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004061 old_map->PrintGeneralization(
4062 stdout, "", modify_index, split_nof, old_nof,
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004063 old_details.location() == kDescriptor && store_mode == FORCE_FIELD,
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004064 old_details.representation(), new_details.representation(),
Ben Murdoch097c5b22016-05-18 11:27:45 +01004065 old_field_type, old_value, new_field_type, new_value);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004066 }
4067
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004068 Handle<LayoutDescriptor> new_layout_descriptor =
4069 LayoutDescriptor::New(split_map, new_descriptors, old_nof);
4070
4071 Handle<Map> new_map =
4072 AddMissingTransitions(split_map, new_descriptors, new_layout_descriptor);
4073
4074 // Deprecated part of the transition tree is no longer reachable, so replace
4075 // current instance descriptors in the "survived" part of the tree with
4076 // the new descriptors to maintain descriptors sharing invariant.
4077 split_map->ReplaceDescriptors(*new_descriptors, *new_layout_descriptor);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004078 return new_map;
Steve Blocka7e24c12009-10-30 11:49:00 +00004079}
4080
4081
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004082// Generalize the representation of all DATA descriptors.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004083Handle<Map> Map::GeneralizeAllFieldRepresentations(
4084 Handle<Map> map) {
4085 Handle<DescriptorArray> descriptors(map->instance_descriptors());
4086 for (int i = 0; i < map->NumberOfOwnDescriptors(); ++i) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004087 PropertyDetails details = descriptors->GetDetails(i);
4088 if (details.type() == DATA) {
4089 map = ReconfigureProperty(map, i, kData, details.attributes(),
4090 Representation::Tagged(),
Ben Murdoch097c5b22016-05-18 11:27:45 +01004091 FieldType::Any(map->GetIsolate()), FORCE_FIELD);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01004092 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004093 }
4094 return map;
4095}
4096
4097
4098// static
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004099MaybeHandle<Map> Map::TryUpdate(Handle<Map> old_map) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004100 DisallowHeapAllocation no_allocation;
4101 DisallowDeoptimization no_deoptimization(old_map->GetIsolate());
4102
4103 if (!old_map->is_deprecated()) return old_map;
4104
4105 // Check the state of the root map.
4106 Map* root_map = old_map->FindRootMap();
4107 if (!old_map->EquivalentToForTransition(root_map)) return MaybeHandle<Map>();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004108
4109 ElementsKind from_kind = root_map->elements_kind();
4110 ElementsKind to_kind = old_map->elements_kind();
4111 if (from_kind != to_kind) {
4112 // Try to follow existing elements kind transitions.
4113 root_map = root_map->LookupElementsTransitionMap(to_kind);
4114 if (root_map == NULL) return MaybeHandle<Map>();
4115 // From here on, use the map with correct elements kind as root map.
4116 }
Ben Murdochc5610432016-08-08 18:44:38 +01004117 Map* new_map = root_map->TryReplayPropertyTransitions(*old_map);
4118 if (new_map == nullptr) return MaybeHandle<Map>();
4119 return handle(new_map);
4120}
4121
4122Map* Map::TryReplayPropertyTransitions(Map* old_map) {
4123 DisallowHeapAllocation no_allocation;
4124 DisallowDeoptimization no_deoptimization(GetIsolate());
4125
4126 int root_nof = NumberOfOwnDescriptors();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004127
4128 int old_nof = old_map->NumberOfOwnDescriptors();
4129 DescriptorArray* old_descriptors = old_map->instance_descriptors();
4130
Ben Murdochc5610432016-08-08 18:44:38 +01004131 Map* new_map = this;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004132 for (int i = root_nof; i < old_nof; ++i) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -04004133 PropertyDetails old_details = old_descriptors->GetDetails(i);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004134 Map* transition = TransitionArray::SearchTransition(
4135 new_map, old_details.kind(), old_descriptors->GetKey(i),
4136 old_details.attributes());
Ben Murdochc5610432016-08-08 18:44:38 +01004137 if (transition == NULL) return nullptr;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004138 new_map = transition;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004139 DescriptorArray* new_descriptors = new_map->instance_descriptors();
4140
4141 PropertyDetails new_details = new_descriptors->GetDetails(i);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04004142 DCHECK_EQ(old_details.kind(), new_details.kind());
4143 DCHECK_EQ(old_details.attributes(), new_details.attributes());
4144 if (!old_details.representation().fits_into(new_details.representation())) {
Ben Murdochc5610432016-08-08 18:44:38 +01004145 return nullptr;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004146 }
Emily Bernierd0a1eb72015-03-24 16:35:39 -04004147 switch (new_details.type()) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004148 case DATA: {
Ben Murdoch097c5b22016-05-18 11:27:45 +01004149 FieldType* new_type = new_descriptors->GetFieldType(i);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004150 // Cleared field types need special treatment. They represent lost
4151 // knowledge, so we must first generalize the new_type to "Any".
4152 if (FieldTypeIsCleared(new_details.representation(), new_type)) {
Ben Murdochc5610432016-08-08 18:44:38 +01004153 return nullptr;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004154 }
4155 PropertyType old_property_type = old_details.type();
4156 if (old_property_type == DATA) {
Ben Murdoch097c5b22016-05-18 11:27:45 +01004157 FieldType* old_type = old_descriptors->GetFieldType(i);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004158 if (FieldTypeIsCleared(old_details.representation(), old_type) ||
4159 !old_type->NowIs(new_type)) {
Ben Murdochc5610432016-08-08 18:44:38 +01004160 return nullptr;
Emily Bernierd0a1eb72015-03-24 16:35:39 -04004161 }
4162 } else {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004163 DCHECK(old_property_type == DATA_CONSTANT);
4164 Object* old_value = old_descriptors->GetValue(i);
4165 if (!new_type->NowContains(old_value)) {
Ben Murdochc5610432016-08-08 18:44:38 +01004166 return nullptr;
Emily Bernierd0a1eb72015-03-24 16:35:39 -04004167 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004168 }
4169 break;
Emily Bernierd0a1eb72015-03-24 16:35:39 -04004170 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004171 case ACCESSOR: {
4172#ifdef DEBUG
Ben Murdoch097c5b22016-05-18 11:27:45 +01004173 FieldType* new_type = new_descriptors->GetFieldType(i);
4174 DCHECK(new_type->IsAny());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004175#endif
Emily Bernierd0a1eb72015-03-24 16:35:39 -04004176 break;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004177 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004178
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004179 case DATA_CONSTANT:
4180 case ACCESSOR_CONSTANT: {
4181 Object* old_value = old_descriptors->GetValue(i);
4182 Object* new_value = new_descriptors->GetValue(i);
4183 if (old_details.location() == kField || old_value != new_value) {
Ben Murdochc5610432016-08-08 18:44:38 +01004184 return nullptr;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004185 }
4186 break;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004187 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004188 }
4189 }
Ben Murdochc5610432016-08-08 18:44:38 +01004190 if (new_map->NumberOfOwnDescriptors() != old_nof) return nullptr;
4191 return new_map;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004192}
4193
4194
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004195// static
4196Handle<Map> Map::Update(Handle<Map> map) {
4197 if (!map->is_deprecated()) return map;
4198 return ReconfigureProperty(map, -1, kData, NONE, Representation::None(),
Ben Murdoch097c5b22016-05-18 11:27:45 +01004199 FieldType::None(map->GetIsolate()),
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004200 ALLOW_IN_DESCRIPTOR);
4201}
4202
4203
4204Maybe<bool> JSObject::SetPropertyWithInterceptor(LookupIterator* it,
Ben Murdoch097c5b22016-05-18 11:27:45 +01004205 ShouldThrow should_throw,
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004206 Handle<Object> value) {
4207 Isolate* isolate = it->isolate();
4208 // Make sure that the top context does not change when doing callbacks or
4209 // interceptor calls.
4210 AssertNoContextChange ncc(isolate);
4211
4212 DCHECK_EQ(LookupIterator::INTERCEPTOR, it->state());
4213 Handle<InterceptorInfo> interceptor(it->GetInterceptor());
4214 if (interceptor->setter()->IsUndefined()) return Just(false);
4215
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004216 Handle<JSObject> holder = it->GetHolder<JSObject>();
Ben Murdochda12d292016-06-02 14:46:10 +01004217 bool result;
4218 Handle<Object> receiver = it->GetReceiver();
4219 if (!receiver->IsJSReceiver()) {
4220 ASSIGN_RETURN_ON_EXCEPTION_VALUE(isolate, receiver,
4221 Object::ConvertReceiver(isolate, receiver),
4222 Nothing<bool>());
4223 }
4224 PropertyCallbackArguments args(isolate, interceptor->data(), *receiver,
4225 *holder, should_throw);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004226
4227 if (it->IsElement()) {
4228 uint32_t index = it->index();
4229 v8::IndexedPropertySetterCallback setter =
4230 v8::ToCData<v8::IndexedPropertySetterCallback>(interceptor->setter());
Ben Murdochda12d292016-06-02 14:46:10 +01004231 // TODO(neis): In the future, we may want to actually return the
4232 // interceptor's result, which then should be a boolean.
4233 result = !args.Call(setter, index, value).is_null();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004234 } else {
4235 Handle<Name> name = it->name();
4236 DCHECK(!name->IsPrivate());
4237
4238 if (name->IsSymbol() && !interceptor->can_intercept_symbols()) {
4239 return Just(false);
4240 }
4241
4242 v8::GenericNamedPropertySetterCallback setter =
4243 v8::ToCData<v8::GenericNamedPropertySetterCallback>(
4244 interceptor->setter());
Ben Murdochda12d292016-06-02 14:46:10 +01004245 result = !args.Call(setter, name, value).is_null();
Emily Bernierd0a1eb72015-03-24 16:35:39 -04004246 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004247
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004248 RETURN_VALUE_IF_SCHEDULED_EXCEPTION(it->isolate(), Nothing<bool>());
Ben Murdochda12d292016-06-02 14:46:10 +01004249 return Just(result);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004250}
4251
4252
4253MaybeHandle<Object> Object::SetProperty(Handle<Object> object,
4254 Handle<Name> name, Handle<Object> value,
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004255 LanguageMode language_mode,
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004256 StoreFromKeyed store_mode) {
4257 LookupIterator it(object, name);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004258 MAYBE_RETURN_NULL(SetProperty(&it, value, language_mode, store_mode));
4259 return value;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004260}
4261
4262
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004263Maybe<bool> Object::SetPropertyInternal(LookupIterator* it,
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004264 Handle<Object> value,
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004265 LanguageMode language_mode,
Emily Bernierd0a1eb72015-03-24 16:35:39 -04004266 StoreFromKeyed store_mode,
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004267 bool* found) {
Ben Murdochc5610432016-08-08 18:44:38 +01004268 it->UpdateProtector();
Ben Murdochda12d292016-06-02 14:46:10 +01004269 DCHECK(it->IsFound());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004270 ShouldThrow should_throw =
4271 is_sloppy(language_mode) ? DONT_THROW : THROW_ON_ERROR;
4272
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004273 // Make sure that the top context does not change when doing callbacks or
4274 // interceptor calls.
4275 AssertNoContextChange ncc(it->isolate());
4276
Ben Murdochda12d292016-06-02 14:46:10 +01004277 do {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004278 switch (it->state()) {
4279 case LookupIterator::NOT_FOUND:
4280 UNREACHABLE();
4281
4282 case LookupIterator::ACCESS_CHECK:
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004283 if (it->HasAccess()) break;
4284 // Check whether it makes sense to reuse the lookup iterator. Here it
4285 // might still call into setters up the prototype chain.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004286 return JSObject::SetPropertyWithFailedAccessCheck(it, value,
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004287 should_throw);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004288
4289 case LookupIterator::JSPROXY:
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004290 return JSProxy::SetProperty(it->GetHolder<JSProxy>(), it->GetName(),
4291 value, it->GetReceiver(), language_mode);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004292
Ben Murdochc5610432016-08-08 18:44:38 +01004293 case LookupIterator::INTERCEPTOR: {
4294 Handle<Map> store_target_map =
4295 handle(it->GetStoreTarget()->map(), it->isolate());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004296 if (it->HolderIsReceiverOrHiddenPrototype()) {
Ben Murdoch097c5b22016-05-18 11:27:45 +01004297 Maybe<bool> result =
4298 JSObject::SetPropertyWithInterceptor(it, should_throw, value);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004299 if (result.IsNothing() || result.FromJust()) return result;
Ben Murdochc5610432016-08-08 18:44:38 +01004300 // Interceptor modified the store target but failed to set the
4301 // property.
4302 Utils::ApiCheck(*store_target_map == it->GetStoreTarget()->map(),
4303 it->IsElement() ? "v8::IndexedPropertySetterCallback"
4304 : "v8::NamedPropertySetterCallback",
4305 "Interceptor silently changed store target.");
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004306 } else {
4307 Maybe<PropertyAttributes> maybe_attributes =
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004308 JSObject::GetPropertyAttributesWithInterceptor(it);
4309 if (!maybe_attributes.IsJust()) return Nothing<bool>();
Ben Murdochda12d292016-06-02 14:46:10 +01004310 if ((maybe_attributes.FromJust() & READ_ONLY) != 0) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004311 return WriteToReadOnlyProperty(it, value, should_throw);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004312 }
Ben Murdochc5610432016-08-08 18:44:38 +01004313 // Interceptor modified the store target but failed to set the
4314 // property.
4315 Utils::ApiCheck(*store_target_map == it->GetStoreTarget()->map(),
4316 it->IsElement() ? "v8::IndexedPropertySetterCallback"
4317 : "v8::NamedPropertySetterCallback",
4318 "Interceptor silently changed store target.");
4319 if (maybe_attributes.FromJust() == ABSENT) break;
Ben Murdochda12d292016-06-02 14:46:10 +01004320 *found = false;
4321 return Nothing<bool>();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004322 }
4323 break;
Ben Murdochc5610432016-08-08 18:44:38 +01004324 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004325
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004326 case LookupIterator::ACCESSOR: {
4327 if (it->IsReadOnly()) {
4328 return WriteToReadOnlyProperty(it, value, should_throw);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004329 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004330 Handle<Object> accessors = it->GetAccessors();
4331 if (accessors->IsAccessorInfo() &&
4332 !it->HolderIsReceiverOrHiddenPrototype() &&
4333 AccessorInfo::cast(*accessors)->is_special_data_property()) {
Ben Murdochda12d292016-06-02 14:46:10 +01004334 *found = false;
4335 return Nothing<bool>();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004336 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004337 return SetPropertyWithAccessor(it, value, should_throw);
4338 }
4339 case LookupIterator::INTEGER_INDEXED_EXOTIC:
Ben Murdochda12d292016-06-02 14:46:10 +01004340 // TODO(verwaest): We should throw an exception if holder is receiver.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004341 return Just(true);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004342
4343 case LookupIterator::DATA:
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004344 if (it->IsReadOnly()) {
4345 return WriteToReadOnlyProperty(it, value, should_throw);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004346 }
4347 if (it->HolderIsReceiverOrHiddenPrototype()) {
4348 return SetDataProperty(it, value);
4349 }
Ben Murdochda12d292016-06-02 14:46:10 +01004350 // Fall through.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004351 case LookupIterator::TRANSITION:
Ben Murdochda12d292016-06-02 14:46:10 +01004352 *found = false;
4353 return Nothing<bool>();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004354 }
Ben Murdochda12d292016-06-02 14:46:10 +01004355 it->Next();
4356 } while (it->IsFound());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004357
4358 *found = false;
4359 return Nothing<bool>();
4360}
4361
4362
4363Maybe<bool> Object::SetProperty(LookupIterator* it, Handle<Object> value,
4364 LanguageMode language_mode,
4365 StoreFromKeyed store_mode) {
Ben Murdochda12d292016-06-02 14:46:10 +01004366 if (it->IsFound()) {
4367 bool found = true;
4368 Maybe<bool> result =
4369 SetPropertyInternal(it, value, language_mode, store_mode, &found);
4370 if (found) return result;
4371 }
4372
4373 // If the receiver is the JSGlobalObject, the store was contextual. In case
4374 // the property did not exist yet on the global object itself, we have to
4375 // throw a reference error in strict mode. In sloppy mode, we continue.
4376 if (is_strict(language_mode) && it->GetReceiver()->IsJSGlobalObject()) {
4377 it->isolate()->Throw(*it->isolate()->factory()->NewReferenceError(
4378 MessageTemplate::kNotDefined, it->name()));
4379 return Nothing<bool>();
4380 }
4381
Ben Murdoch097c5b22016-05-18 11:27:45 +01004382 ShouldThrow should_throw =
4383 is_sloppy(language_mode) ? DONT_THROW : THROW_ON_ERROR;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004384 return AddDataProperty(it, value, NONE, should_throw, store_mode);
4385}
4386
4387
4388Maybe<bool> Object::SetSuperProperty(LookupIterator* it, Handle<Object> value,
4389 LanguageMode language_mode,
4390 StoreFromKeyed store_mode) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004391 Isolate* isolate = it->isolate();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004392
Ben Murdochda12d292016-06-02 14:46:10 +01004393 if (it->IsFound()) {
4394 bool found = true;
4395 Maybe<bool> result =
4396 SetPropertyInternal(it, value, language_mode, store_mode, &found);
4397 if (found) return result;
4398 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004399
Ben Murdochc5610432016-08-08 18:44:38 +01004400 it->UpdateProtector();
4401
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004402 // The property either doesn't exist on the holder or exists there as a data
4403 // property.
4404
Ben Murdoch097c5b22016-05-18 11:27:45 +01004405 ShouldThrow should_throw =
4406 is_sloppy(language_mode) ? DONT_THROW : THROW_ON_ERROR;
4407
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004408 if (!it->GetReceiver()->IsJSReceiver()) {
4409 return WriteToReadOnlyProperty(it, value, should_throw);
4410 }
4411 Handle<JSReceiver> receiver = Handle<JSReceiver>::cast(it->GetReceiver());
4412
Ben Murdochc5610432016-08-08 18:44:38 +01004413 LookupIterator::Configuration c = LookupIterator::OWN;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004414 LookupIterator own_lookup =
4415 it->IsElement() ? LookupIterator(isolate, receiver, it->index(), c)
4416 : LookupIterator(receiver, it->name(), c);
4417
4418 for (; own_lookup.IsFound(); own_lookup.Next()) {
4419 switch (own_lookup.state()) {
4420 case LookupIterator::ACCESS_CHECK:
4421 if (!own_lookup.HasAccess()) {
4422 return JSObject::SetPropertyWithFailedAccessCheck(&own_lookup, value,
4423 should_throw);
4424 }
4425 break;
4426
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004427 case LookupIterator::ACCESSOR:
Ben Murdoch097c5b22016-05-18 11:27:45 +01004428 if (own_lookup.GetAccessors()->IsAccessorInfo()) {
4429 if (own_lookup.IsReadOnly()) {
4430 return WriteToReadOnlyProperty(&own_lookup, value, should_throw);
4431 }
4432 return JSObject::SetPropertyWithAccessor(&own_lookup, value,
4433 should_throw);
4434 }
4435 // Fall through.
4436 case LookupIterator::INTEGER_INDEXED_EXOTIC:
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004437 return RedefineIncompatibleProperty(isolate, it->GetName(), value,
4438 should_throw);
4439
4440 case LookupIterator::DATA: {
Ben Murdoch097c5b22016-05-18 11:27:45 +01004441 if (own_lookup.IsReadOnly()) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004442 return WriteToReadOnlyProperty(&own_lookup, value, should_throw);
4443 }
4444 return SetDataProperty(&own_lookup, value);
4445 }
4446
4447 case LookupIterator::INTERCEPTOR:
4448 case LookupIterator::JSPROXY: {
4449 PropertyDescriptor desc;
4450 Maybe<bool> owned =
4451 JSReceiver::GetOwnPropertyDescriptor(&own_lookup, &desc);
4452 MAYBE_RETURN(owned, Nothing<bool>());
4453 if (!owned.FromJust()) {
4454 return JSReceiver::CreateDataProperty(&own_lookup, value,
4455 should_throw);
4456 }
4457 if (PropertyDescriptor::IsAccessorDescriptor(&desc) ||
4458 !desc.writable()) {
4459 return RedefineIncompatibleProperty(isolate, it->GetName(), value,
4460 should_throw);
4461 }
4462
4463 PropertyDescriptor value_desc;
4464 value_desc.set_value(value);
4465 return JSReceiver::DefineOwnProperty(isolate, receiver, it->GetName(),
4466 &value_desc, should_throw);
4467 }
4468
4469 case LookupIterator::NOT_FOUND:
4470 case LookupIterator::TRANSITION:
4471 UNREACHABLE();
4472 }
4473 }
4474
Ben Murdochda12d292016-06-02 14:46:10 +01004475 return AddDataProperty(&own_lookup, value, NONE, should_throw, store_mode);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004476}
4477
Ben Murdoch097c5b22016-05-18 11:27:45 +01004478MaybeHandle<Object> Object::ReadAbsentProperty(LookupIterator* it) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004479 return it->isolate()->factory()->undefined_value();
4480}
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004481
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004482MaybeHandle<Object> Object::ReadAbsentProperty(Isolate* isolate,
4483 Handle<Object> receiver,
Ben Murdoch097c5b22016-05-18 11:27:45 +01004484 Handle<Object> name) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004485 return isolate->factory()->undefined_value();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004486}
4487
4488
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004489Maybe<bool> Object::CannotCreateProperty(Isolate* isolate,
4490 Handle<Object> receiver,
4491 Handle<Object> name,
4492 Handle<Object> value,
4493 ShouldThrow should_throw) {
4494 RETURN_FAILURE(
4495 isolate, should_throw,
4496 NewTypeError(MessageTemplate::kStrictCannotCreateProperty, name,
4497 Object::TypeOf(isolate, receiver), receiver));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004498}
4499
4500
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004501Maybe<bool> Object::WriteToReadOnlyProperty(LookupIterator* it,
4502 Handle<Object> value,
4503 ShouldThrow should_throw) {
4504 return WriteToReadOnlyProperty(it->isolate(), it->GetReceiver(),
4505 it->GetName(), value, should_throw);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04004506}
4507
4508
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004509Maybe<bool> Object::WriteToReadOnlyProperty(Isolate* isolate,
4510 Handle<Object> receiver,
4511 Handle<Object> name,
4512 Handle<Object> value,
4513 ShouldThrow should_throw) {
4514 RETURN_FAILURE(isolate, should_throw,
4515 NewTypeError(MessageTemplate::kStrictReadOnlyProperty, name,
4516 Object::TypeOf(isolate, receiver), receiver));
4517}
4518
4519
4520Maybe<bool> Object::RedefineIncompatibleProperty(Isolate* isolate,
4521 Handle<Object> name,
4522 Handle<Object> value,
4523 ShouldThrow should_throw) {
4524 RETURN_FAILURE(isolate, should_throw,
4525 NewTypeError(MessageTemplate::kRedefineDisallowed, name));
4526}
4527
4528
4529Maybe<bool> Object::SetDataProperty(LookupIterator* it, Handle<Object> value) {
4530 // Proxies are handled elsewhere. Other non-JSObjects cannot have own
4531 // properties.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004532 Handle<JSObject> receiver = Handle<JSObject>::cast(it->GetReceiver());
4533
4534 // Store on the holder which may be hidden behind the receiver.
4535 DCHECK(it->HolderIsReceiverOrHiddenPrototype());
4536
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004537 Handle<Object> to_assign = value;
4538 // Convert the incoming value to a number for storing into typed arrays.
4539 if (it->IsElement() && receiver->HasFixedTypedArrayElements()) {
4540 if (!value->IsNumber() && !value->IsUndefined()) {
4541 ASSIGN_RETURN_ON_EXCEPTION_VALUE(
4542 it->isolate(), to_assign, Object::ToNumber(value), Nothing<bool>());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004543 // We have to recheck the length. However, it can only change if the
4544 // underlying buffer was neutered, so just check that.
4545 if (Handle<JSArrayBufferView>::cast(receiver)->WasNeutered()) {
4546 return Just(true);
4547 // TODO(neis): According to the spec, this should throw a TypeError.
4548 }
4549 }
4550 }
4551
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004552 // Possibly migrate to the most up-to-date map that will be able to store
4553 // |value| under it->name().
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004554 it->PrepareForDataProperty(to_assign);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004555
4556 // Write the property value.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004557 it->WriteDataValue(to_assign);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004558
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004559#if VERIFY_HEAP
4560 if (FLAG_verify_heap) {
4561 receiver->JSObjectVerify();
4562 }
4563#endif
4564 return Just(true);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004565}
4566
4567
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004568Maybe<bool> Object::AddDataProperty(LookupIterator* it, Handle<Object> value,
4569 PropertyAttributes attributes,
4570 ShouldThrow should_throw,
4571 StoreFromKeyed store_mode) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004572 if (!it->GetReceiver()->IsJSObject()) {
Ben Murdoch097c5b22016-05-18 11:27:45 +01004573 if (it->GetReceiver()->IsJSProxy() && it->GetName()->IsPrivate()) {
4574 RETURN_FAILURE(it->isolate(), should_throw,
4575 NewTypeError(MessageTemplate::kProxyPrivate));
4576 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004577 return CannotCreateProperty(it->isolate(), it->GetReceiver(), it->GetName(),
4578 value, should_throw);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004579 }
4580
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004581 DCHECK_NE(LookupIterator::INTEGER_INDEXED_EXOTIC, it->state());
4582
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004583 Handle<JSObject> receiver = it->GetStoreTarget();
4584
4585 // If the receiver is a JSGlobalProxy, store on the prototype (JSGlobalObject)
4586 // instead. If the prototype is Null, the proxy is detached.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004587 if (receiver->IsJSGlobalProxy()) return Just(true);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004588
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004589 Isolate* isolate = it->isolate();
Emily Bernierd0a1eb72015-03-24 16:35:39 -04004590
Ben Murdoch097c5b22016-05-18 11:27:45 +01004591 if (it->ExtendingNonExtensible(receiver)) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004592 RETURN_FAILURE(
4593 isolate, should_throw,
4594 NewTypeError(MessageTemplate::kObjectNotExtensible, it->GetName()));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004595 }
4596
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004597 if (it->IsElement()) {
4598 if (receiver->IsJSArray()) {
4599 Handle<JSArray> array = Handle<JSArray>::cast(receiver);
4600 if (JSArray::WouldChangeReadOnlyLength(array, it->index())) {
4601 RETURN_FAILURE(array->GetIsolate(), should_throw,
4602 NewTypeError(MessageTemplate::kStrictReadOnlyProperty,
4603 isolate->factory()->length_string(),
4604 Object::TypeOf(isolate, array), array));
4605 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004606
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004607 if (FLAG_trace_external_array_abuse &&
4608 array->HasFixedTypedArrayElements()) {
4609 CheckArrayAbuse(array, "typed elements write", it->index(), true);
4610 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004611
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004612 if (FLAG_trace_js_array_abuse && !array->HasFixedTypedArrayElements()) {
4613 CheckArrayAbuse(array, "elements write", it->index(), false);
Steve Blocka7e24c12009-10-30 11:49:00 +00004614 }
4615 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004616
4617 Maybe<bool> result = JSObject::AddDataElement(receiver, it->index(), value,
4618 attributes, should_throw);
4619 JSObject::ValidateElements(receiver);
4620 return result;
4621 } else {
Ben Murdochc5610432016-08-08 18:44:38 +01004622 it->UpdateProtector();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004623 // Migrate to the most up-to-date map that will be able to store |value|
4624 // under it->name() with |attributes|.
Ben Murdoch097c5b22016-05-18 11:27:45 +01004625 it->PrepareTransitionToDataProperty(receiver, value, attributes,
4626 store_mode);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004627 DCHECK_EQ(LookupIterator::TRANSITION, it->state());
Ben Murdoch097c5b22016-05-18 11:27:45 +01004628 it->ApplyTransitionToDataProperty(receiver);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004629
4630 // TODO(verwaest): Encapsulate dictionary handling better.
4631 if (receiver->map()->is_dictionary_map()) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004632 // TODO(dcarney): just populate TransitionPropertyCell here?
4633 JSObject::AddSlowProperty(receiver, it->name(), value, attributes);
4634 } else {
4635 // Write the property value.
4636 it->WriteDataValue(value);
4637 }
4638
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004639#if VERIFY_HEAP
4640 if (FLAG_verify_heap) {
4641 receiver->JSObjectVerify();
4642 }
4643#endif
Steve Blocka7e24c12009-10-30 11:49:00 +00004644 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004645
4646 return Just(true);
Steve Blocka7e24c12009-10-30 11:49:00 +00004647}
4648
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004649
4650void Map::EnsureDescriptorSlack(Handle<Map> map, int slack) {
4651 // Only supports adding slack to owned descriptors.
4652 DCHECK(map->owns_descriptors());
4653
4654 Handle<DescriptorArray> descriptors(map->instance_descriptors());
4655 int old_size = map->NumberOfOwnDescriptors();
4656 if (slack <= descriptors->NumberOfSlackDescriptors()) return;
4657
4658 Handle<DescriptorArray> new_descriptors = DescriptorArray::CopyUpTo(
4659 descriptors, old_size, slack);
4660
Emily Bernierd0a1eb72015-03-24 16:35:39 -04004661 DisallowHeapAllocation no_allocation;
4662 // The descriptors are still the same, so keep the layout descriptor.
4663 LayoutDescriptor* layout_descriptor = map->GetLayoutDescriptor();
4664
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004665 if (old_size == 0) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -04004666 map->UpdateDescriptors(*new_descriptors, layout_descriptor);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004667 return;
4668 }
4669
4670 // If the source descriptors had an enum cache we copy it. This ensures
4671 // that the maps to which we push the new descriptor array back can rely
4672 // on a cache always being available once it is set. If the map has more
4673 // enumerated descriptors than available in the original cache, the cache
4674 // will be lazily replaced by the extended cache when needed.
4675 if (descriptors->HasEnumCache()) {
4676 new_descriptors->CopyEnumCacheFrom(*descriptors);
4677 }
4678
4679 // Replace descriptors by new_descriptors in all maps that share it.
Ben Murdochda12d292016-06-02 14:46:10 +01004680 map->GetHeap()->incremental_marking()->IterateBlackObject(*descriptors);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004681
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004682 Map* current = *map;
4683 while (current->instance_descriptors() == *descriptors) {
4684 Object* next = current->GetBackPointer();
4685 if (next->IsUndefined()) break; // Stop overwriting at initial map.
4686 current->UpdateDescriptors(*new_descriptors, layout_descriptor);
4687 current = Map::cast(next);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004688 }
Emily Bernierd0a1eb72015-03-24 16:35:39 -04004689 map->UpdateDescriptors(*new_descriptors, layout_descriptor);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004690}
4691
4692
4693template<class T>
4694static int AppendUniqueCallbacks(NeanderArray* callbacks,
4695 Handle<typename T::Array> array,
4696 int valid_descriptors) {
4697 int nof_callbacks = callbacks->length();
4698
4699 Isolate* isolate = array->GetIsolate();
4700 // Ensure the keys are unique names before writing them into the
4701 // instance descriptor. Since it may cause a GC, it has to be done before we
4702 // temporarily put the heap in an invalid state while appending descriptors.
4703 for (int i = 0; i < nof_callbacks; ++i) {
4704 Handle<AccessorInfo> entry(AccessorInfo::cast(callbacks->get(i)));
4705 if (entry->name()->IsUniqueName()) continue;
4706 Handle<String> key =
4707 isolate->factory()->InternalizeString(
4708 Handle<String>(String::cast(entry->name())));
4709 entry->set_name(*key);
4710 }
4711
4712 // Fill in new callback descriptors. Process the callbacks from
4713 // back to front so that the last callback with a given name takes
4714 // precedence over previously added callbacks with that name.
4715 for (int i = nof_callbacks - 1; i >= 0; i--) {
4716 Handle<AccessorInfo> entry(AccessorInfo::cast(callbacks->get(i)));
4717 Handle<Name> key(Name::cast(entry->name()));
4718 // Check if a descriptor with this name already exists before writing.
4719 if (!T::Contains(key, entry, valid_descriptors, array)) {
4720 T::Insert(key, entry, valid_descriptors, array);
4721 valid_descriptors++;
Ben Murdoch3ef787d2012-04-12 10:51:47 +01004722 }
4723 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004724
4725 return valid_descriptors;
4726}
4727
4728struct DescriptorArrayAppender {
4729 typedef DescriptorArray Array;
4730 static bool Contains(Handle<Name> key,
4731 Handle<AccessorInfo> entry,
4732 int valid_descriptors,
4733 Handle<DescriptorArray> array) {
4734 DisallowHeapAllocation no_gc;
4735 return array->Search(*key, valid_descriptors) != DescriptorArray::kNotFound;
4736 }
4737 static void Insert(Handle<Name> key,
4738 Handle<AccessorInfo> entry,
4739 int valid_descriptors,
4740 Handle<DescriptorArray> array) {
4741 DisallowHeapAllocation no_gc;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004742 AccessorConstantDescriptor desc(key, entry, entry->property_attributes());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004743 array->Append(&desc);
4744 }
4745};
4746
4747
4748struct FixedArrayAppender {
4749 typedef FixedArray Array;
4750 static bool Contains(Handle<Name> key,
4751 Handle<AccessorInfo> entry,
4752 int valid_descriptors,
4753 Handle<FixedArray> array) {
4754 for (int i = 0; i < valid_descriptors; i++) {
4755 if (*key == AccessorInfo::cast(array->get(i))->name()) return true;
4756 }
4757 return false;
4758 }
4759 static void Insert(Handle<Name> key,
4760 Handle<AccessorInfo> entry,
4761 int valid_descriptors,
4762 Handle<FixedArray> array) {
4763 DisallowHeapAllocation no_gc;
4764 array->set(valid_descriptors, *entry);
4765 }
4766};
4767
4768
4769void Map::AppendCallbackDescriptors(Handle<Map> map,
4770 Handle<Object> descriptors) {
4771 int nof = map->NumberOfOwnDescriptors();
4772 Handle<DescriptorArray> array(map->instance_descriptors());
4773 NeanderArray callbacks(descriptors);
4774 DCHECK(array->NumberOfSlackDescriptors() >= callbacks.length());
4775 nof = AppendUniqueCallbacks<DescriptorArrayAppender>(&callbacks, array, nof);
4776 map->SetNumberOfOwnDescriptors(nof);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01004777}
4778
Steve Blocka7e24c12009-10-30 11:49:00 +00004779
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004780int AccessorInfo::AppendUnique(Handle<Object> descriptors,
4781 Handle<FixedArray> array,
4782 int valid_descriptors) {
4783 NeanderArray callbacks(descriptors);
4784 DCHECK(array->length() >= callbacks.length() + valid_descriptors);
4785 return AppendUniqueCallbacks<FixedArrayAppender>(&callbacks,
4786 array,
4787 valid_descriptors);
Ben Murdochb0fe1622011-05-05 13:52:32 +01004788}
4789
4790
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004791static bool ContainsMap(MapHandleList* maps, Map* map) {
4792 DCHECK_NOT_NULL(map);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01004793 for (int i = 0; i < maps->length(); ++i) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004794 if (!maps->at(i).is_null() && *maps->at(i) == map) return true;
Ben Murdoch3ef787d2012-04-12 10:51:47 +01004795 }
4796 return false;
4797}
Ben Murdoch592a9fc2012-03-05 11:04:45 +00004798
Ben Murdochc5610432016-08-08 18:44:38 +01004799Map* Map::FindElementsKindTransitionedMap(MapHandleList* candidates) {
4800 DisallowHeapAllocation no_allocation;
4801 DisallowDeoptimization no_deoptimization(GetIsolate());
Ben Murdoch85b71792012-04-11 18:30:58 +01004802
Ben Murdochc5610432016-08-08 18:44:38 +01004803 ElementsKind kind = elements_kind();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004804 bool packed = IsFastPackedElementsKind(kind);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004805
4806 Map* transition = nullptr;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004807 if (IsTransitionableFastElementsKind(kind)) {
Ben Murdochc5610432016-08-08 18:44:38 +01004808 // Check the state of the root map.
4809 Map* root_map = FindRootMap();
4810 if (!EquivalentToForTransition(root_map)) return nullptr;
4811 root_map = root_map->LookupElementsTransitionMap(kind);
4812 DCHECK_NOT_NULL(root_map);
4813 // Starting from the next existing elements kind transition try to
4814 // replay the property transitions that does not involve instance rewriting
4815 // (ElementsTransitionAndStoreStub does not support that).
4816 for (root_map = root_map->ElementsTransitionMap();
4817 root_map != nullptr && root_map->has_fast_elements();
4818 root_map = root_map->ElementsTransitionMap()) {
4819 Map* current = root_map->TryReplayPropertyTransitions(this);
4820 if (current == nullptr) continue;
4821 if (InstancesNeedRewriting(current)) continue;
4822
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004823 if (ContainsMap(candidates, current) &&
4824 (packed || !IsFastPackedElementsKind(current->elements_kind()))) {
4825 transition = current;
4826 packed = packed && IsFastPackedElementsKind(current->elements_kind());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004827 }
Ben Murdoch85b71792012-04-11 18:30:58 +01004828 }
Ben Murdoch3ef787d2012-04-12 10:51:47 +01004829 }
Ben Murdochc5610432016-08-08 18:44:38 +01004830 return transition;
Ben Murdoch3ef787d2012-04-12 10:51:47 +01004831}
Ben Murdoch85b71792012-04-11 18:30:58 +01004832
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004833
4834static Map* FindClosestElementsTransition(Map* map, ElementsKind to_kind) {
Ben Murdochc5610432016-08-08 18:44:38 +01004835 // Ensure we are requested to search elements kind transition "near the root".
4836 DCHECK_EQ(map->FindRootMap()->NumberOfOwnDescriptors(),
4837 map->NumberOfOwnDescriptors());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004838 Map* current_map = map;
Ben Murdoch3ef787d2012-04-12 10:51:47 +01004839
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004840 ElementsKind kind = map->elements_kind();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004841 while (kind != to_kind) {
4842 Map* next_map = current_map->ElementsTransitionMap();
4843 if (next_map == nullptr) return current_map;
4844 kind = next_map->elements_kind();
4845 current_map = next_map;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004846 }
4847
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004848 DCHECK_EQ(to_kind, current_map->elements_kind());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004849 return current_map;
4850}
4851
4852
4853Map* Map::LookupElementsTransitionMap(ElementsKind to_kind) {
4854 Map* to_map = FindClosestElementsTransition(this, to_kind);
4855 if (to_map->elements_kind() == to_kind) return to_map;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004856 return nullptr;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004857}
4858
4859
4860bool Map::IsMapInArrayPrototypeChain() {
4861 Isolate* isolate = GetIsolate();
4862 if (isolate->initial_array_prototype()->map() == this) {
4863 return true;
4864 }
4865
4866 if (isolate->initial_object_prototype()->map() == this) {
4867 return true;
4868 }
4869
4870 return false;
4871}
4872
4873
Emily Bernierd0a1eb72015-03-24 16:35:39 -04004874Handle<WeakCell> Map::WeakCellForMap(Handle<Map> map) {
4875 Isolate* isolate = map->GetIsolate();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004876 if (map->weak_cell_cache()->IsWeakCell()) {
4877 return Handle<WeakCell>(WeakCell::cast(map->weak_cell_cache()));
Emily Bernierd0a1eb72015-03-24 16:35:39 -04004878 }
4879 Handle<WeakCell> weak_cell = isolate->factory()->NewWeakCell(map);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004880 map->set_weak_cell_cache(*weak_cell);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04004881 return weak_cell;
4882}
4883
4884
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004885static Handle<Map> AddMissingElementsTransitions(Handle<Map> map,
4886 ElementsKind to_kind) {
4887 DCHECK(IsTransitionElementsKind(map->elements_kind()));
4888
4889 Handle<Map> current_map = map;
4890
4891 ElementsKind kind = map->elements_kind();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004892 TransitionFlag flag;
4893 if (map->is_prototype_map()) {
4894 flag = OMIT_TRANSITION;
4895 } else {
4896 flag = INSERT_TRANSITION;
4897 if (IsFastElementsKind(kind)) {
4898 while (kind != to_kind && !IsTerminalElementsKind(kind)) {
4899 kind = GetNextTransitionElementsKind(kind);
4900 current_map = Map::CopyAsElementsKind(current_map, kind, flag);
4901 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004902 }
4903 }
4904
4905 // In case we are exiting the fast elements kind system, just add the map in
4906 // the end.
4907 if (kind != to_kind) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004908 current_map = Map::CopyAsElementsKind(current_map, to_kind, flag);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004909 }
4910
4911 DCHECK(current_map->elements_kind() == to_kind);
4912 return current_map;
4913}
4914
4915
4916Handle<Map> Map::TransitionElementsTo(Handle<Map> map,
4917 ElementsKind to_kind) {
4918 ElementsKind from_kind = map->elements_kind();
4919 if (from_kind == to_kind) return map;
4920
4921 Isolate* isolate = map->GetIsolate();
4922 Context* native_context = isolate->context()->native_context();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004923 if (from_kind == FAST_SLOPPY_ARGUMENTS_ELEMENTS) {
4924 if (*map == native_context->fast_aliased_arguments_map()) {
4925 DCHECK_EQ(SLOW_SLOPPY_ARGUMENTS_ELEMENTS, to_kind);
4926 return handle(native_context->slow_aliased_arguments_map());
4927 }
4928 } else if (from_kind == SLOW_SLOPPY_ARGUMENTS_ELEMENTS) {
4929 if (*map == native_context->slow_aliased_arguments_map()) {
4930 DCHECK_EQ(FAST_SLOPPY_ARGUMENTS_ELEMENTS, to_kind);
4931 return handle(native_context->fast_aliased_arguments_map());
4932 }
4933 } else if (IsFastElementsKind(from_kind) && IsFastElementsKind(to_kind)) {
4934 // Reuse map transitions for JSArrays.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004935 DisallowHeapAllocation no_gc;
Ben Murdochda12d292016-06-02 14:46:10 +01004936 if (native_context->get(Context::ArrayMapIndex(from_kind)) == *map) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004937 Object* maybe_transitioned_map =
Ben Murdochda12d292016-06-02 14:46:10 +01004938 native_context->get(Context::ArrayMapIndex(to_kind));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004939 if (maybe_transitioned_map->IsMap()) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004940 return handle(Map::cast(maybe_transitioned_map), isolate);
Ben Murdoch85b71792012-04-11 18:30:58 +01004941 }
Ben Murdoch592a9fc2012-03-05 11:04:45 +00004942 }
4943 }
4944
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004945 DCHECK(!map->IsUndefined());
4946 // Check if we can go back in the elements kind transition chain.
4947 if (IsHoleyElementsKind(from_kind) &&
4948 to_kind == GetPackedElementsKind(from_kind) &&
4949 map->GetBackPointer()->IsMap() &&
4950 Map::cast(map->GetBackPointer())->elements_kind() == to_kind) {
4951 return handle(Map::cast(map->GetBackPointer()));
Ben Murdoch3ef787d2012-04-12 10:51:47 +01004952 }
4953
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004954 bool allow_store_transition = IsTransitionElementsKind(from_kind);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004955 // Only store fast element maps in ascending generality.
4956 if (IsFastElementsKind(to_kind)) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004957 allow_store_transition =
4958 allow_store_transition && IsTransitionableFastElementsKind(from_kind) &&
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004959 IsMoreGeneralElementsKindTransition(from_kind, to_kind);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01004960 }
4961
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004962 if (!allow_store_transition) {
4963 return Map::CopyAsElementsKind(map, to_kind, OMIT_TRANSITION);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01004964 }
4965
Ben Murdochc5610432016-08-08 18:44:38 +01004966 return Map::ReconfigureElementsKind(map, to_kind);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01004967}
4968
4969
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004970// static
4971Handle<Map> Map::AsElementsKind(Handle<Map> map, ElementsKind kind) {
4972 Handle<Map> closest_map(FindClosestElementsTransition(*map, kind));
Ben Murdoch3ef787d2012-04-12 10:51:47 +01004973
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004974 if (closest_map->elements_kind() == kind) {
4975 return closest_map;
Ben Murdoch3ef787d2012-04-12 10:51:47 +01004976 }
4977
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004978 return AddMissingElementsTransitions(closest_map, kind);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01004979}
4980
4981
4982Handle<Map> JSObject::GetElementsTransitionMap(Handle<JSObject> object,
4983 ElementsKind to_kind) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004984 Handle<Map> map(object->map());
4985 return Map::TransitionElementsTo(map, to_kind);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01004986}
4987
4988
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004989void JSProxy::Revoke(Handle<JSProxy> proxy) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004990 Isolate* isolate = proxy->GetIsolate();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004991 if (!proxy->IsRevoked()) proxy->set_handler(isolate->heap()->null_value());
4992 DCHECK(proxy->IsRevoked());
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00004993}
4994
4995
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004996Maybe<bool> JSProxy::HasProperty(Isolate* isolate, Handle<JSProxy> proxy,
4997 Handle<Name> name) {
4998 DCHECK(!name->IsPrivate());
Ben Murdochc5610432016-08-08 18:44:38 +01004999 STACK_CHECK(isolate, Nothing<bool>());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00005000 // 1. (Assert)
5001 // 2. Let handler be the value of the [[ProxyHandler]] internal slot of O.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005002 Handle<Object> handler(proxy->handler(), isolate);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00005003 // 3. If handler is null, throw a TypeError exception.
5004 // 4. Assert: Type(handler) is Object.
5005 if (proxy->IsRevoked()) {
5006 isolate->Throw(*isolate->factory()->NewTypeError(
5007 MessageTemplate::kProxyRevoked, isolate->factory()->has_string()));
5008 return Nothing<bool>();
5009 }
5010 // 5. Let target be the value of the [[ProxyTarget]] internal slot of O.
5011 Handle<JSReceiver> target(proxy->target(), isolate);
5012 // 6. Let trap be ? GetMethod(handler, "has").
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005013 Handle<Object> trap;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00005014 ASSIGN_RETURN_ON_EXCEPTION_VALUE(
5015 isolate, trap, Object::GetMethod(Handle<JSReceiver>::cast(handler),
5016 isolate->factory()->has_string()),
5017 Nothing<bool>());
5018 // 7. If trap is undefined, then
Ben Murdoch3ef787d2012-04-12 10:51:47 +01005019 if (trap->IsUndefined()) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00005020 // 7a. Return target.[[HasProperty]](P).
5021 return JSReceiver::HasProperty(target, name);
5022 }
5023 // 8. Let booleanTrapResult be ToBoolean(? Call(trap, handler, «target, P»)).
5024 Handle<Object> trap_result_obj;
5025 Handle<Object> args[] = {target, name};
5026 ASSIGN_RETURN_ON_EXCEPTION_VALUE(
5027 isolate, trap_result_obj,
5028 Execution::Call(isolate, trap, handler, arraysize(args), args),
5029 Nothing<bool>());
5030 bool boolean_trap_result = trap_result_obj->BooleanValue();
5031 // 9. If booleanTrapResult is false, then:
5032 if (!boolean_trap_result) {
5033 // 9a. Let targetDesc be ? target.[[GetOwnProperty]](P).
5034 PropertyDescriptor target_desc;
5035 Maybe<bool> target_found = JSReceiver::GetOwnPropertyDescriptor(
5036 isolate, target, name, &target_desc);
5037 MAYBE_RETURN(target_found, Nothing<bool>());
5038 // 9b. If targetDesc is not undefined, then:
5039 if (target_found.FromJust()) {
5040 // 9b i. If targetDesc.[[Configurable]] is false, throw a TypeError
5041 // exception.
5042 if (!target_desc.configurable()) {
5043 isolate->Throw(*isolate->factory()->NewTypeError(
5044 MessageTemplate::kProxyHasNonConfigurable, name));
5045 return Nothing<bool>();
5046 }
5047 // 9b ii. Let extensibleTarget be ? IsExtensible(target).
5048 Maybe<bool> extensible_target = JSReceiver::IsExtensible(target);
5049 MAYBE_RETURN(extensible_target, Nothing<bool>());
5050 // 9b iii. If extensibleTarget is false, throw a TypeError exception.
5051 if (!extensible_target.FromJust()) {
5052 isolate->Throw(*isolate->factory()->NewTypeError(
5053 MessageTemplate::kProxyHasNonExtensible, name));
5054 return Nothing<bool>();
5055 }
Ben Murdoch3ef787d2012-04-12 10:51:47 +01005056 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00005057 }
5058 // 10. Return booleanTrapResult.
5059 return Just(boolean_trap_result);
5060}
5061
5062
5063Maybe<bool> JSProxy::SetProperty(Handle<JSProxy> proxy, Handle<Name> name,
5064 Handle<Object> value, Handle<Object> receiver,
5065 LanguageMode language_mode) {
5066 DCHECK(!name->IsPrivate());
5067 Isolate* isolate = proxy->GetIsolate();
Ben Murdochc5610432016-08-08 18:44:38 +01005068 STACK_CHECK(isolate, Nothing<bool>());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00005069 Factory* factory = isolate->factory();
5070 Handle<String> trap_name = factory->set_string();
5071 ShouldThrow should_throw =
5072 is_sloppy(language_mode) ? DONT_THROW : THROW_ON_ERROR;
5073
5074 if (proxy->IsRevoked()) {
5075 isolate->Throw(
5076 *factory->NewTypeError(MessageTemplate::kProxyRevoked, trap_name));
5077 return Nothing<bool>();
5078 }
5079 Handle<JSReceiver> target(proxy->target(), isolate);
5080 Handle<JSReceiver> handler(JSReceiver::cast(proxy->handler()), isolate);
5081
5082 Handle<Object> trap;
5083 ASSIGN_RETURN_ON_EXCEPTION_VALUE(
5084 isolate, trap, Object::GetMethod(handler, trap_name), Nothing<bool>());
5085 if (trap->IsUndefined()) {
5086 LookupIterator it =
5087 LookupIterator::PropertyOrElement(isolate, receiver, name, target);
5088 return Object::SetSuperProperty(&it, value, language_mode,
5089 Object::MAY_BE_STORE_FROM_KEYED);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01005090 }
5091
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00005092 Handle<Object> trap_result;
5093 Handle<Object> args[] = {target, name, value, receiver};
5094 ASSIGN_RETURN_ON_EXCEPTION_VALUE(
5095 isolate, trap_result,
5096 Execution::Call(isolate, trap, handler, arraysize(args), args),
5097 Nothing<bool>());
5098 if (!trap_result->BooleanValue()) {
5099 RETURN_FAILURE(isolate, should_throw,
5100 NewTypeError(MessageTemplate::kProxyTrapReturnedFalsishFor,
5101 trap_name, name));
5102 }
5103
5104 // Enforce the invariant.
5105 PropertyDescriptor target_desc;
5106 Maybe<bool> owned =
5107 JSReceiver::GetOwnPropertyDescriptor(isolate, target, name, &target_desc);
5108 MAYBE_RETURN(owned, Nothing<bool>());
5109 if (owned.FromJust()) {
5110 bool inconsistent = PropertyDescriptor::IsDataDescriptor(&target_desc) &&
5111 !target_desc.configurable() &&
5112 !target_desc.writable() &&
5113 !value->SameValue(*target_desc.value());
5114 if (inconsistent) {
5115 isolate->Throw(*isolate->factory()->NewTypeError(
5116 MessageTemplate::kProxySetFrozenData, name));
5117 return Nothing<bool>();
5118 }
5119 inconsistent = PropertyDescriptor::IsAccessorDescriptor(&target_desc) &&
5120 !target_desc.configurable() &&
5121 target_desc.set()->IsUndefined();
5122 if (inconsistent) {
5123 isolate->Throw(*isolate->factory()->NewTypeError(
5124 MessageTemplate::kProxySetFrozenAccessor, name));
5125 return Nothing<bool>();
5126 }
5127 }
5128 return Just(true);
5129}
5130
5131
5132Maybe<bool> JSProxy::DeletePropertyOrElement(Handle<JSProxy> proxy,
5133 Handle<Name> name,
5134 LanguageMode language_mode) {
5135 DCHECK(!name->IsPrivate());
5136 ShouldThrow should_throw =
5137 is_sloppy(language_mode) ? DONT_THROW : THROW_ON_ERROR;
5138 Isolate* isolate = proxy->GetIsolate();
Ben Murdochc5610432016-08-08 18:44:38 +01005139 STACK_CHECK(isolate, Nothing<bool>());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00005140 Factory* factory = isolate->factory();
5141 Handle<String> trap_name = factory->deleteProperty_string();
5142
5143 if (proxy->IsRevoked()) {
5144 isolate->Throw(
5145 *factory->NewTypeError(MessageTemplate::kProxyRevoked, trap_name));
5146 return Nothing<bool>();
5147 }
5148 Handle<JSReceiver> target(proxy->target(), isolate);
5149 Handle<JSReceiver> handler(JSReceiver::cast(proxy->handler()), isolate);
5150
5151 Handle<Object> trap;
5152 ASSIGN_RETURN_ON_EXCEPTION_VALUE(
5153 isolate, trap, Object::GetMethod(handler, trap_name), Nothing<bool>());
5154 if (trap->IsUndefined()) {
5155 return JSReceiver::DeletePropertyOrElement(target, name, language_mode);
5156 }
5157
5158 Handle<Object> trap_result;
5159 Handle<Object> args[] = {target, name};
5160 ASSIGN_RETURN_ON_EXCEPTION_VALUE(
5161 isolate, trap_result,
5162 Execution::Call(isolate, trap, handler, arraysize(args), args),
5163 Nothing<bool>());
5164 if (!trap_result->BooleanValue()) {
5165 RETURN_FAILURE(isolate, should_throw,
5166 NewTypeError(MessageTemplate::kProxyTrapReturnedFalsishFor,
5167 trap_name, name));
5168 }
5169
5170 // Enforce the invariant.
5171 PropertyDescriptor target_desc;
5172 Maybe<bool> owned =
5173 JSReceiver::GetOwnPropertyDescriptor(isolate, target, name, &target_desc);
5174 MAYBE_RETURN(owned, Nothing<bool>());
5175 if (owned.FromJust() && !target_desc.configurable()) {
5176 isolate->Throw(*factory->NewTypeError(
5177 MessageTemplate::kProxyDeletePropertyNonConfigurable, name));
5178 return Nothing<bool>();
5179 }
5180 return Just(true);
5181}
5182
5183
5184// static
5185MaybeHandle<JSProxy> JSProxy::New(Isolate* isolate, Handle<Object> target,
5186 Handle<Object> handler) {
5187 if (!target->IsJSReceiver()) {
5188 THROW_NEW_ERROR(isolate, NewTypeError(MessageTemplate::kProxyNonObject),
5189 JSProxy);
5190 }
5191 if (target->IsJSProxy() && JSProxy::cast(*target)->IsRevoked()) {
5192 THROW_NEW_ERROR(isolate,
5193 NewTypeError(MessageTemplate::kProxyHandlerOrTargetRevoked),
5194 JSProxy);
5195 }
5196 if (!handler->IsJSReceiver()) {
5197 THROW_NEW_ERROR(isolate, NewTypeError(MessageTemplate::kProxyNonObject),
5198 JSProxy);
5199 }
5200 if (handler->IsJSProxy() && JSProxy::cast(*handler)->IsRevoked()) {
5201 THROW_NEW_ERROR(isolate,
5202 NewTypeError(MessageTemplate::kProxyHandlerOrTargetRevoked),
5203 JSProxy);
5204 }
5205 return isolate->factory()->NewJSProxy(Handle<JSReceiver>::cast(target),
5206 Handle<JSReceiver>::cast(handler));
5207}
5208
5209
5210// static
5211MaybeHandle<Context> JSProxy::GetFunctionRealm(Handle<JSProxy> proxy) {
5212 DCHECK(proxy->map()->is_constructor());
5213 if (proxy->IsRevoked()) {
5214 THROW_NEW_ERROR(proxy->GetIsolate(),
5215 NewTypeError(MessageTemplate::kProxyRevoked), Context);
5216 }
5217 Handle<JSReceiver> target(JSReceiver::cast(proxy->target()));
5218 return JSReceiver::GetFunctionRealm(target);
5219}
5220
5221
5222// static
5223MaybeHandle<Context> JSBoundFunction::GetFunctionRealm(
5224 Handle<JSBoundFunction> function) {
5225 DCHECK(function->map()->is_constructor());
5226 return JSReceiver::GetFunctionRealm(
5227 handle(function->bound_target_function()));
5228}
5229
Ben Murdochc5610432016-08-08 18:44:38 +01005230// static
5231MaybeHandle<String> JSBoundFunction::GetName(Isolate* isolate,
5232 Handle<JSBoundFunction> function) {
5233 Handle<String> prefix = isolate->factory()->bound__string();
5234 if (!function->bound_target_function()->IsJSFunction()) return prefix;
5235 Handle<JSFunction> target(JSFunction::cast(function->bound_target_function()),
5236 isolate);
5237 Handle<Object> target_name = JSFunction::GetName(isolate, target);
5238 if (!target_name->IsString()) return prefix;
5239 Factory* factory = isolate->factory();
5240 return factory->NewConsString(prefix, Handle<String>::cast(target_name));
5241}
5242
5243// static
5244Handle<Object> JSFunction::GetName(Isolate* isolate,
5245 Handle<JSFunction> function) {
5246 if (function->shared()->name_should_print_as_anonymous()) {
5247 return isolate->factory()->anonymous_string();
5248 }
5249 return handle(function->shared()->name(), isolate);
5250}
5251
5252// static
5253MaybeHandle<Smi> JSFunction::GetLength(Isolate* isolate,
5254 Handle<JSFunction> function) {
5255 int length = 0;
5256 if (function->shared()->is_compiled()) {
5257 length = function->shared()->length();
5258 } else {
5259 // If the function isn't compiled yet, the length is not computed
5260 // correctly yet. Compile it now and return the right length.
5261 if (Compiler::Compile(function, Compiler::KEEP_EXCEPTION)) {
5262 length = function->shared()->length();
5263 }
5264 if (isolate->has_pending_exception()) return MaybeHandle<Smi>();
5265 }
5266 return handle(Smi::FromInt(length), isolate);
5267}
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00005268
5269// static
5270Handle<Context> JSFunction::GetFunctionRealm(Handle<JSFunction> function) {
5271 DCHECK(function->map()->is_constructor());
5272 return handle(function->context()->native_context());
5273}
5274
5275
5276// static
5277MaybeHandle<Context> JSObject::GetFunctionRealm(Handle<JSObject> object) {
5278 DCHECK(object->map()->is_constructor());
5279 DCHECK(!object->IsJSFunction());
5280 return handle(object->GetCreationContext());
5281}
5282
5283
5284// static
5285MaybeHandle<Context> JSReceiver::GetFunctionRealm(Handle<JSReceiver> receiver) {
5286 if (receiver->IsJSProxy()) {
5287 return JSProxy::GetFunctionRealm(Handle<JSProxy>::cast(receiver));
5288 }
5289
5290 if (receiver->IsJSFunction()) {
5291 return JSFunction::GetFunctionRealm(Handle<JSFunction>::cast(receiver));
5292 }
5293
5294 if (receiver->IsJSBoundFunction()) {
5295 return JSBoundFunction::GetFunctionRealm(
5296 Handle<JSBoundFunction>::cast(receiver));
5297 }
5298
5299 return JSObject::GetFunctionRealm(Handle<JSObject>::cast(receiver));
5300}
5301
5302
5303Maybe<PropertyAttributes> JSProxy::GetPropertyAttributes(LookupIterator* it) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00005304 PropertyDescriptor desc;
5305 Maybe<bool> found = JSProxy::GetOwnPropertyDescriptor(
Ben Murdochda12d292016-06-02 14:46:10 +01005306 it->isolate(), it->GetHolder<JSProxy>(), it->GetName(), &desc);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00005307 MAYBE_RETURN(found, Nothing<PropertyAttributes>());
5308 if (!found.FromJust()) return Just(ABSENT);
5309 return Just(desc.ToAttributes());
Ben Murdoch3ef787d2012-04-12 10:51:47 +01005310}
5311
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00005312
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005313void JSObject::AllocateStorageForMap(Handle<JSObject> object, Handle<Map> map) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00005314 DCHECK(object->map()->GetInObjectProperties() ==
5315 map->GetInObjectProperties());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005316 ElementsKind obj_kind = object->map()->elements_kind();
5317 ElementsKind map_kind = map->elements_kind();
5318 if (map_kind != obj_kind) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00005319 ElementsKind to_kind = GetMoreGeneralElementsKind(map_kind, obj_kind);
5320 if (IsDictionaryElementsKind(obj_kind)) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005321 to_kind = obj_kind;
John Reck59135872010-11-02 12:39:01 -07005322 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005323 if (IsDictionaryElementsKind(to_kind)) {
5324 NormalizeElements(object);
Ben Murdoche0cee9b2011-05-25 10:26:03 +01005325 } else {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005326 TransitionElementsKind(object, to_kind);
Ben Murdoche0cee9b2011-05-25 10:26:03 +01005327 }
Ben Murdochc5610432016-08-08 18:44:38 +01005328 map = Map::ReconfigureElementsKind(map, to_kind);
Ben Murdoche0cee9b2011-05-25 10:26:03 +01005329 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005330 JSObject::MigrateToMap(object, map);
5331}
5332
5333
5334void JSObject::MigrateInstance(Handle<JSObject> object) {
5335 Handle<Map> original_map(object->map());
5336 Handle<Map> map = Map::Update(original_map);
5337 map->set_migration_target(true);
5338 MigrateToMap(object, map);
5339 if (FLAG_trace_migration) {
5340 object->PrintInstanceMigration(stdout, *original_map, *map);
5341 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00005342#if VERIFY_HEAP
5343 if (FLAG_verify_heap) {
5344 object->JSObjectVerify();
5345 }
5346#endif
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005347}
5348
5349
5350// static
5351bool JSObject::TryMigrateInstance(Handle<JSObject> object) {
5352 Isolate* isolate = object->GetIsolate();
5353 DisallowDeoptimization no_deoptimization(isolate);
5354 Handle<Map> original_map(object->map(), isolate);
5355 Handle<Map> new_map;
5356 if (!Map::TryUpdate(original_map).ToHandle(&new_map)) {
5357 return false;
5358 }
5359 JSObject::MigrateToMap(object, new_map);
5360 if (FLAG_trace_migration) {
5361 object->PrintInstanceMigration(stdout, *original_map, object->map());
5362 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00005363#if VERIFY_HEAP
5364 if (FLAG_verify_heap) {
5365 object->JSObjectVerify();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005366 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00005367#endif
5368 return true;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005369}
5370
5371
5372void JSObject::AddProperty(Handle<JSObject> object, Handle<Name> name,
5373 Handle<Object> value,
5374 PropertyAttributes attributes) {
Ben Murdochda12d292016-06-02 14:46:10 +01005375 LookupIterator it(object, name, object, LookupIterator::OWN_SKIP_INTERCEPTOR);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005376 CHECK_NE(LookupIterator::ACCESS_CHECK, it.state());
5377#ifdef DEBUG
5378 uint32_t index;
5379 DCHECK(!object->IsJSProxy());
5380 DCHECK(!name->AsArrayIndex(&index));
5381 Maybe<PropertyAttributes> maybe = GetPropertyAttributes(&it);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00005382 DCHECK(maybe.IsJust());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005383 DCHECK(!it.IsFound());
Ben Murdoch097c5b22016-05-18 11:27:45 +01005384 DCHECK(object->map()->is_extensible() || name->IsPrivate());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005385#endif
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00005386 CHECK(AddDataProperty(&it, value, attributes, THROW_ON_ERROR,
5387 CERTAINLY_NOT_STORE_FROM_KEYED)
5388 .IsJust());
5389}
5390
5391
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005392// Reconfigures a property to a data property with attributes, even if it is not
5393// reconfigurable.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00005394// Requires a LookupIterator that does not look at the prototype chain beyond
5395// hidden prototypes.
5396MaybeHandle<Object> JSObject::DefineOwnPropertyIgnoreAttributes(
5397 LookupIterator* it, Handle<Object> value, PropertyAttributes attributes,
Ben Murdoch097c5b22016-05-18 11:27:45 +01005398 AccessorInfoHandling handling) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00005399 MAYBE_RETURN_NULL(DefineOwnPropertyIgnoreAttributes(
5400 it, value, attributes, THROW_ON_ERROR, handling));
5401 return value;
5402}
5403
5404
5405Maybe<bool> JSObject::DefineOwnPropertyIgnoreAttributes(
5406 LookupIterator* it, Handle<Object> value, PropertyAttributes attributes,
Ben Murdoch097c5b22016-05-18 11:27:45 +01005407 ShouldThrow should_throw, AccessorInfoHandling handling) {
5408 it->UpdateProtector();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00005409 Handle<JSObject> object = Handle<JSObject>::cast(it->GetReceiver());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00005410
5411 for (; it->IsFound(); it->Next()) {
5412 switch (it->state()) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005413 case LookupIterator::JSPROXY:
5414 case LookupIterator::NOT_FOUND:
5415 case LookupIterator::TRANSITION:
5416 UNREACHABLE();
5417
5418 case LookupIterator::ACCESS_CHECK:
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00005419 if (!it->HasAccess()) {
5420 it->isolate()->ReportFailedAccessCheck(it->GetHolder<JSObject>());
5421 RETURN_VALUE_IF_SCHEDULED_EXCEPTION(it->isolate(), Nothing<bool>());
5422 return Just(true);
5423 }
5424 break;
5425
5426 // If there's an interceptor, try to store the property with the
5427 // interceptor.
5428 // In case of success, the attributes will have been reset to the default
5429 // attributes of the interceptor, rather than the incoming attributes.
5430 //
5431 // TODO(verwaest): JSProxy afterwards verify the attributes that the
5432 // JSProxy claims it has, and verifies that they are compatible. If not,
5433 // they throw. Here we should do the same.
5434 case LookupIterator::INTERCEPTOR:
5435 if (handling == DONT_FORCE_FIELD) {
Ben Murdoch097c5b22016-05-18 11:27:45 +01005436 Maybe<bool> result =
5437 JSObject::SetPropertyWithInterceptor(it, should_throw, value);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00005438 if (result.IsNothing() || result.FromJust()) return result;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005439 }
5440 break;
5441
5442 case LookupIterator::ACCESSOR: {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00005443 Handle<Object> accessors = it->GetAccessors();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005444
Ben Murdoch097c5b22016-05-18 11:27:45 +01005445 // Special handling for AccessorInfo, which behaves like a data
5446 // property.
5447 if (accessors->IsAccessorInfo() && handling == DONT_FORCE_FIELD) {
5448 PropertyAttributes current_attributes = it->property_attributes();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00005449 // Ensure the context isn't changed after calling into accessors.
5450 AssertNoContextChange ncc(it->isolate());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005451
Ben Murdoch097c5b22016-05-18 11:27:45 +01005452 // Update the attributes before calling the setter. The setter may
5453 // later change the shape of the property.
5454 if (current_attributes != attributes) {
5455 it->TransitionToAccessorPair(accessors, attributes);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005456 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005457
Ben Murdoch097c5b22016-05-18 11:27:45 +01005458 Maybe<bool> result =
5459 JSObject::SetPropertyWithAccessor(it, value, should_throw);
5460
5461 if (current_attributes == attributes || result.IsNothing()) {
5462 return result;
5463 }
5464
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00005465 } else {
5466 it->ReconfigureDataProperty(value, attributes);
5467 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005468
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00005469 return Just(true);
Iain Merrick75681382010-08-19 15:07:18 +01005470 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00005471 case LookupIterator::INTEGER_INDEXED_EXOTIC:
5472 return RedefineIncompatibleProperty(it->isolate(), it->GetName(), value,
5473 should_throw);
Steve Blocka7e24c12009-10-30 11:49:00 +00005474
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005475 case LookupIterator::DATA: {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005476 // Regular property update if the attributes match.
Ben Murdoch097c5b22016-05-18 11:27:45 +01005477 if (it->property_attributes() == attributes) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00005478 return SetDataProperty(it, value);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005479 }
Steve Blocka7e24c12009-10-30 11:49:00 +00005480
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00005481 // Special case: properties of typed arrays cannot be reconfigured to
5482 // non-writable nor to non-enumerable.
5483 if (it->IsElement() && object->HasFixedTypedArrayElements()) {
5484 return RedefineIncompatibleProperty(it->isolate(), it->GetName(),
5485 value, should_throw);
5486 }
5487
5488 // Reconfigure the data property if the attributes mismatch.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00005489 it->ReconfigureDataProperty(value, attributes);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01005490
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00005491 return Just(true);
Steve Blocka7e24c12009-10-30 11:49:00 +00005492 }
Steve Blocka7e24c12009-10-30 11:49:00 +00005493 }
5494 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005495
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00005496 return AddDataProperty(it, value, attributes, should_throw,
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005497 CERTAINLY_NOT_STORE_FROM_KEYED);
Steve Blocka7e24c12009-10-30 11:49:00 +00005498}
5499
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00005500MaybeHandle<Object> JSObject::SetOwnPropertyIgnoreAttributes(
5501 Handle<JSObject> object, Handle<Name> name, Handle<Object> value,
Ben Murdoch097c5b22016-05-18 11:27:45 +01005502 PropertyAttributes attributes) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00005503 DCHECK(!value->IsTheHole());
Ben Murdochda12d292016-06-02 14:46:10 +01005504 LookupIterator it(object, name, object, LookupIterator::OWN);
Ben Murdoch097c5b22016-05-18 11:27:45 +01005505 return DefineOwnPropertyIgnoreAttributes(&it, value, attributes);
Steve Blocka7e24c12009-10-30 11:49:00 +00005506}
5507
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00005508MaybeHandle<Object> JSObject::SetOwnElementIgnoreAttributes(
5509 Handle<JSObject> object, uint32_t index, Handle<Object> value,
Ben Murdoch097c5b22016-05-18 11:27:45 +01005510 PropertyAttributes attributes) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00005511 Isolate* isolate = object->GetIsolate();
Ben Murdochda12d292016-06-02 14:46:10 +01005512 LookupIterator it(isolate, object, index, object, LookupIterator::OWN);
Ben Murdoch097c5b22016-05-18 11:27:45 +01005513 return DefineOwnPropertyIgnoreAttributes(&it, value, attributes);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00005514}
5515
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00005516MaybeHandle<Object> JSObject::DefinePropertyOrElementIgnoreAttributes(
5517 Handle<JSObject> object, Handle<Name> name, Handle<Object> value,
Ben Murdoch097c5b22016-05-18 11:27:45 +01005518 PropertyAttributes attributes) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00005519 Isolate* isolate = object->GetIsolate();
Ben Murdochda12d292016-06-02 14:46:10 +01005520 LookupIterator it = LookupIterator::PropertyOrElement(
5521 isolate, object, name, object, LookupIterator::OWN);
Ben Murdoch097c5b22016-05-18 11:27:45 +01005522 return DefineOwnPropertyIgnoreAttributes(&it, value, attributes);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00005523}
5524
5525
5526Maybe<PropertyAttributes> JSObject::GetPropertyAttributesWithInterceptor(
5527 LookupIterator* it) {
5528 Isolate* isolate = it->isolate();
5529 // Make sure that the top context does not change when doing
5530 // callbacks or interceptor calls.
5531 AssertNoContextChange ncc(isolate);
5532 HandleScope scope(isolate);
5533
5534 Handle<JSObject> holder = it->GetHolder<JSObject>();
5535 Handle<InterceptorInfo> interceptor(it->GetInterceptor());
5536 if (!it->IsElement() && it->name()->IsSymbol() &&
5537 !interceptor->can_intercept_symbols()) {
5538 return Just(ABSENT);
Steve Blocka7e24c12009-10-30 11:49:00 +00005539 }
Ben Murdochda12d292016-06-02 14:46:10 +01005540 Handle<Object> receiver = it->GetReceiver();
5541 if (!receiver->IsJSReceiver()) {
5542 ASSIGN_RETURN_ON_EXCEPTION_VALUE(isolate, receiver,
5543 Object::ConvertReceiver(isolate, receiver),
5544 Nothing<PropertyAttributes>());
5545 }
5546 PropertyCallbackArguments args(isolate, interceptor->data(), *receiver,
5547 *holder, Object::DONT_THROW);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00005548 if (!interceptor->query()->IsUndefined()) {
Ben Murdochda12d292016-06-02 14:46:10 +01005549 Handle<Object> result;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00005550 if (it->IsElement()) {
5551 uint32_t index = it->index();
5552 v8::IndexedPropertyQueryCallback query =
5553 v8::ToCData<v8::IndexedPropertyQueryCallback>(interceptor->query());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00005554 result = args.Call(query, index);
5555 } else {
5556 Handle<Name> name = it->name();
5557 DCHECK(!name->IsPrivate());
5558 v8::GenericNamedPropertyQueryCallback query =
5559 v8::ToCData<v8::GenericNamedPropertyQueryCallback>(
5560 interceptor->query());
Ben Murdochda12d292016-06-02 14:46:10 +01005561 result = args.Call(query, name);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00005562 }
Ben Murdochda12d292016-06-02 14:46:10 +01005563 if (!result.is_null()) {
5564 int32_t value;
5565 CHECK(result->ToInt32(&value));
5566 return Just(static_cast<PropertyAttributes>(value));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00005567 }
5568 } else if (!interceptor->getter()->IsUndefined()) {
5569 // TODO(verwaest): Use GetPropertyWithInterceptor?
Ben Murdochda12d292016-06-02 14:46:10 +01005570 Handle<Object> result;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00005571 if (it->IsElement()) {
5572 uint32_t index = it->index();
5573 v8::IndexedPropertyGetterCallback getter =
5574 v8::ToCData<v8::IndexedPropertyGetterCallback>(interceptor->getter());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00005575 result = args.Call(getter, index);
5576 } else {
5577 Handle<Name> name = it->name();
5578 DCHECK(!name->IsPrivate());
5579 v8::GenericNamedPropertyGetterCallback getter =
5580 v8::ToCData<v8::GenericNamedPropertyGetterCallback>(
5581 interceptor->getter());
Ben Murdochda12d292016-06-02 14:46:10 +01005582 result = args.Call(getter, name);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00005583 }
Ben Murdochda12d292016-06-02 14:46:10 +01005584 if (!result.is_null()) return Just(DONT_ENUM);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00005585 }
5586
5587 RETURN_VALUE_IF_SCHEDULED_EXCEPTION(isolate, Nothing<PropertyAttributes>());
5588 return Just(ABSENT);
Steve Blocka7e24c12009-10-30 11:49:00 +00005589}
5590
5591
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005592Maybe<PropertyAttributes> JSReceiver::GetPropertyAttributes(
5593 LookupIterator* it) {
5594 for (; it->IsFound(); it->Next()) {
5595 switch (it->state()) {
5596 case LookupIterator::NOT_FOUND:
5597 case LookupIterator::TRANSITION:
5598 UNREACHABLE();
5599 case LookupIterator::JSPROXY:
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00005600 return JSProxy::GetPropertyAttributes(it);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005601 case LookupIterator::INTERCEPTOR: {
5602 Maybe<PropertyAttributes> result =
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00005603 JSObject::GetPropertyAttributesWithInterceptor(it);
5604 if (!result.IsJust()) return result;
5605 if (result.FromJust() != ABSENT) return result;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005606 break;
Kristian Monsen80d68ea2010-09-08 11:05:35 +01005607 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005608 case LookupIterator::ACCESS_CHECK:
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00005609 if (it->HasAccess()) break;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005610 return JSObject::GetPropertyAttributesWithFailedAccessCheck(it);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00005611 case LookupIterator::INTEGER_INDEXED_EXOTIC:
5612 return Just(ABSENT);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005613 case LookupIterator::ACCESSOR:
5614 case LookupIterator::DATA:
Ben Murdoch097c5b22016-05-18 11:27:45 +01005615 return Just(it->property_attributes());
Kristian Monsen80d68ea2010-09-08 11:05:35 +01005616 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005617 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00005618 return Just(ABSENT);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005619}
5620
5621
5622Handle<NormalizedMapCache> NormalizedMapCache::New(Isolate* isolate) {
5623 Handle<FixedArray> array(
5624 isolate->factory()->NewFixedArray(kEntries, TENURED));
5625 return Handle<NormalizedMapCache>::cast(array);
5626}
5627
5628
5629MaybeHandle<Map> NormalizedMapCache::Get(Handle<Map> fast_map,
5630 PropertyNormalizationMode mode) {
5631 DisallowHeapAllocation no_gc;
5632 Object* value = FixedArray::get(GetIndex(fast_map));
5633 if (!value->IsMap() ||
5634 !Map::cast(value)->EquivalentToForNormalization(*fast_map, mode)) {
5635 return MaybeHandle<Map>();
5636 }
5637 return handle(Map::cast(value));
5638}
5639
5640
5641void NormalizedMapCache::Set(Handle<Map> fast_map,
5642 Handle<Map> normalized_map) {
5643 DisallowHeapAllocation no_gc;
5644 DCHECK(normalized_map->is_dictionary_map());
5645 FixedArray::set(GetIndex(fast_map), *normalized_map);
Kristian Monsen80d68ea2010-09-08 11:05:35 +01005646}
5647
5648
Kristian Monsen80d68ea2010-09-08 11:05:35 +01005649void NormalizedMapCache::Clear() {
5650 int entries = length();
5651 for (int i = 0; i != entries; i++) {
5652 set_undefined(i);
5653 }
5654}
5655
5656
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005657void HeapObject::UpdateMapCodeCache(Handle<HeapObject> object,
5658 Handle<Name> name,
5659 Handle<Code> code) {
5660 Handle<Map> map(object->map());
5661 Map::UpdateCodeCache(map, name, code);
Kristian Monsen80d68ea2010-09-08 11:05:35 +01005662}
5663
5664
Ben Murdoch3ef787d2012-04-12 10:51:47 +01005665void JSObject::NormalizeProperties(Handle<JSObject> object,
5666 PropertyNormalizationMode mode,
Emily Bernierd0a1eb72015-03-24 16:35:39 -04005667 int expected_additional_properties,
5668 const char* reason) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005669 if (!object->HasFastProperties()) return;
5670
5671 Handle<Map> map(object->map());
Emily Bernierd0a1eb72015-03-24 16:35:39 -04005672 Handle<Map> new_map = Map::Normalize(map, mode, reason);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005673
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00005674 MigrateToMap(object, new_map, expected_additional_properties);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01005675}
5676
5677
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005678void JSObject::MigrateSlowToFast(Handle<JSObject> object,
Emily Bernierd0a1eb72015-03-24 16:35:39 -04005679 int unused_property_fields,
5680 const char* reason) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005681 if (object->HasFastProperties()) return;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00005682 DCHECK(!object->IsJSGlobalObject());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005683 Isolate* isolate = object->GetIsolate();
5684 Factory* factory = isolate->factory();
5685 Handle<NameDictionary> dictionary(object->property_dictionary());
5686
5687 // Make sure we preserve dictionary representation if there are too many
5688 // descriptors.
5689 int number_of_elements = dictionary->NumberOfElements();
5690 if (number_of_elements > kMaxNumberOfDescriptors) return;
5691
Emily Bernierd0a1eb72015-03-24 16:35:39 -04005692 Handle<FixedArray> iteration_order;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005693 if (number_of_elements != dictionary->NextEnumerationIndex()) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -04005694 iteration_order =
5695 NameDictionary::DoGenerateNewEnumerationIndices(dictionary);
5696 } else {
5697 iteration_order = NameDictionary::BuildIterationIndicesArray(dictionary);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005698 }
5699
Emily Bernierd0a1eb72015-03-24 16:35:39 -04005700 int instance_descriptor_length = iteration_order->length();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005701 int number_of_fields = 0;
5702
5703 // Compute the length of the instance descriptor.
Emily Bernierd0a1eb72015-03-24 16:35:39 -04005704 for (int i = 0; i < instance_descriptor_length; i++) {
5705 int index = Smi::cast(iteration_order->get(i))->value();
5706 DCHECK(dictionary->IsKey(dictionary->KeyAt(index)));
5707
5708 Object* value = dictionary->ValueAt(index);
5709 PropertyType type = dictionary->DetailsAt(index).type();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00005710 if (type == DATA && !value->IsJSFunction()) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -04005711 number_of_fields += 1;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005712 }
5713 }
5714
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00005715 Handle<Map> old_map(object->map(), isolate);
5716
5717 int inobject_props = old_map->GetInObjectProperties();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005718
5719 // Allocate new map.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00005720 Handle<Map> new_map = Map::CopyDropDescriptors(old_map);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005721 new_map->set_dictionary_map(false);
5722
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00005723 UpdatePrototypeUserRegistration(old_map, new_map, isolate);
5724
Emily Bernierd0a1eb72015-03-24 16:35:39 -04005725#if TRACE_MAPS
5726 if (FLAG_trace_maps) {
5727 PrintF("[TraceMaps: SlowToFast from= %p to= %p reason= %s ]\n",
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00005728 reinterpret_cast<void*>(*old_map), reinterpret_cast<void*>(*new_map),
5729 reason);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04005730 }
5731#endif
5732
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005733 if (instance_descriptor_length == 0) {
5734 DisallowHeapAllocation no_gc;
5735 DCHECK_LE(unused_property_fields, inobject_props);
5736 // Transform the object.
5737 new_map->set_unused_property_fields(inobject_props);
5738 object->synchronized_set_map(*new_map);
5739 object->set_properties(isolate->heap()->empty_fixed_array());
5740 // Check that it really works.
5741 DCHECK(object->HasFastProperties());
5742 return;
5743 }
5744
5745 // Allocate the instance descriptor.
5746 Handle<DescriptorArray> descriptors = DescriptorArray::Allocate(
Ben Murdoch097c5b22016-05-18 11:27:45 +01005747 isolate, instance_descriptor_length, 0, TENURED);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005748
5749 int number_of_allocated_fields =
5750 number_of_fields + unused_property_fields - inobject_props;
5751 if (number_of_allocated_fields < 0) {
5752 // There is enough inobject space for all fields (including unused).
5753 number_of_allocated_fields = 0;
5754 unused_property_fields = inobject_props - number_of_fields;
5755 }
5756
5757 // Allocate the fixed array for the fields.
5758 Handle<FixedArray> fields = factory->NewFixedArray(
5759 number_of_allocated_fields);
5760
5761 // Fill in the instance descriptor and the fields.
5762 int current_offset = 0;
Emily Bernierd0a1eb72015-03-24 16:35:39 -04005763 for (int i = 0; i < instance_descriptor_length; i++) {
5764 int index = Smi::cast(iteration_order->get(i))->value();
5765 Object* k = dictionary->KeyAt(index);
5766 DCHECK(dictionary->IsKey(k));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00005767 // Dictionary keys are internalized upon insertion.
5768 // TODO(jkummerow): Turn this into a DCHECK if it's not hit in the wild.
5769 CHECK(k->IsUniqueName());
5770 Handle<Name> key(Name::cast(k), isolate);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005771
Emily Bernierd0a1eb72015-03-24 16:35:39 -04005772 Object* value = dictionary->ValueAt(index);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005773
Emily Bernierd0a1eb72015-03-24 16:35:39 -04005774 PropertyDetails details = dictionary->DetailsAt(index);
5775 int enumeration_index = details.dictionary_index();
5776 PropertyType type = details.type();
5777
5778 if (value->IsJSFunction()) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00005779 DataConstantDescriptor d(key, handle(value, isolate),
5780 details.attributes());
Emily Bernierd0a1eb72015-03-24 16:35:39 -04005781 descriptors->Set(enumeration_index - 1, &d);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00005782 } else if (type == DATA) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -04005783 if (current_offset < inobject_props) {
5784 object->InObjectPropertyAtPut(current_offset, value,
5785 UPDATE_WRITE_BARRIER);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005786 } else {
Emily Bernierd0a1eb72015-03-24 16:35:39 -04005787 int offset = current_offset - inobject_props;
5788 fields->set(offset, value);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005789 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00005790 DataDescriptor d(key, current_offset, details.attributes(),
5791 // TODO(verwaest): value->OptimalRepresentation();
5792 Representation::Tagged());
Emily Bernierd0a1eb72015-03-24 16:35:39 -04005793 current_offset += d.GetDetails().field_width_in_words();
5794 descriptors->Set(enumeration_index - 1, &d);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00005795 } else if (type == ACCESSOR_CONSTANT) {
5796 AccessorConstantDescriptor d(key, handle(value, isolate),
5797 details.attributes());
Emily Bernierd0a1eb72015-03-24 16:35:39 -04005798 descriptors->Set(enumeration_index - 1, &d);
5799 } else {
5800 UNREACHABLE();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005801 }
5802 }
5803 DCHECK(current_offset == number_of_fields);
5804
5805 descriptors->Sort();
5806
Emily Bernierd0a1eb72015-03-24 16:35:39 -04005807 Handle<LayoutDescriptor> layout_descriptor = LayoutDescriptor::New(
5808 new_map, descriptors, descriptors->number_of_descriptors());
5809
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005810 DisallowHeapAllocation no_gc;
Emily Bernierd0a1eb72015-03-24 16:35:39 -04005811 new_map->InitializeDescriptors(*descriptors, *layout_descriptor);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005812 new_map->set_unused_property_fields(unused_property_fields);
5813
5814 // Transform the object.
5815 object->synchronized_set_map(*new_map);
5816
5817 object->set_properties(*fields);
5818 DCHECK(object->IsJSObject());
5819
5820 // Check that it really works.
5821 DCHECK(object->HasFastProperties());
Ben Murdoch3ef787d2012-04-12 10:51:47 +01005822}
5823
5824
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005825void JSObject::ResetElements(Handle<JSObject> object) {
5826 Isolate* isolate = object->GetIsolate();
5827 CHECK(object->map() != isolate->heap()->sloppy_arguments_elements_map());
5828 if (object->map()->has_dictionary_elements()) {
5829 Handle<SeededNumberDictionary> new_elements =
5830 SeededNumberDictionary::New(isolate, 0);
5831 object->set_elements(*new_elements);
5832 } else {
5833 object->set_elements(object->map()->GetInitialElements());
5834 }
5835}
5836
5837
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00005838void JSObject::RequireSlowElements(SeededNumberDictionary* dictionary) {
5839 if (dictionary->requires_slow_elements()) return;
5840 dictionary->set_requires_slow_elements();
5841 // TODO(verwaest): Remove this hack.
5842 if (map()->is_prototype_map()) {
5843 TypeFeedbackVector::ClearAllKeyedStoreICs(GetIsolate());
5844 }
5845}
5846
5847
Ben Murdoch3ef787d2012-04-12 10:51:47 +01005848Handle<SeededNumberDictionary> JSObject::NormalizeElements(
5849 Handle<JSObject> object) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00005850 DCHECK(!object->HasFixedTypedArrayElements());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005851 Isolate* isolate = object->GetIsolate();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00005852 bool is_arguments = object->HasSloppyArgumentsElements();
Ben Murdochda12d292016-06-02 14:46:10 +01005853 {
5854 DisallowHeapAllocation no_gc;
5855 FixedArrayBase* elements = object->elements();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00005856
Ben Murdochda12d292016-06-02 14:46:10 +01005857 if (is_arguments) {
5858 FixedArray* parameter_map = FixedArray::cast(elements);
5859 elements = FixedArrayBase::cast(parameter_map->get(1));
5860 }
5861
5862 if (elements->IsDictionary()) {
5863 return handle(SeededNumberDictionary::cast(elements), isolate);
5864 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00005865 }
Steve Blocka7e24c12009-10-30 11:49:00 +00005866
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005867 DCHECK(object->HasFastSmiOrObjectElements() ||
5868 object->HasFastDoubleElements() ||
Ben Murdoch097c5b22016-05-18 11:27:45 +01005869 object->HasFastArgumentsElements() ||
5870 object->HasFastStringWrapperElements());
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00005871
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00005872 Handle<SeededNumberDictionary> dictionary =
Ben Murdochda12d292016-06-02 14:46:10 +01005873 object->GetElementsAccessor()->Normalize(object);
Steve Blocka7e24c12009-10-30 11:49:00 +00005874
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00005875 // Switch to using the dictionary as the backing storage for elements.
Ben Murdoch097c5b22016-05-18 11:27:45 +01005876 ElementsKind target_kind = is_arguments
5877 ? SLOW_SLOPPY_ARGUMENTS_ELEMENTS
5878 : object->HasFastStringWrapperElements()
5879 ? SLOW_STRING_WRAPPER_ELEMENTS
5880 : DICTIONARY_ELEMENTS;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00005881 Handle<Map> new_map = JSObject::GetElementsTransitionMap(object, target_kind);
5882 // Set the new map first to satify the elements type assert in set_elements().
5883 JSObject::MigrateToMap(object, new_map);
5884
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00005885 if (is_arguments) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005886 FixedArray::cast(object->elements())->set(1, *dictionary);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00005887 } else {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005888 object->set_elements(*dictionary);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00005889 }
5890
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005891 isolate->counters()->elements_to_dictionary()->Increment();
Steve Blocka7e24c12009-10-30 11:49:00 +00005892
5893#ifdef DEBUG
5894 if (FLAG_trace_normalization) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005895 OFStream os(stdout);
5896 os << "Object elements have been normalized:\n";
5897 object->Print(os);
Steve Blocka7e24c12009-10-30 11:49:00 +00005898 }
5899#endif
5900
Ben Murdoch097c5b22016-05-18 11:27:45 +01005901 DCHECK(object->HasDictionaryElements() ||
5902 object->HasSlowArgumentsElements() ||
5903 object->HasSlowStringWrapperElements());
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00005904 return dictionary;
Steve Blocka7e24c12009-10-30 11:49:00 +00005905}
5906
5907
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005908static Smi* GenerateIdentityHash(Isolate* isolate) {
Ben Murdoch69a99ed2011-11-30 16:03:39 +00005909 int hash_value;
5910 int attempts = 0;
5911 do {
5912 // Generate a random 32-bit hash value but limit range to fit
5913 // within a smi.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005914 hash_value = isolate->random_number_generator()->NextInt() & Smi::kMaxValue;
Ben Murdoch69a99ed2011-11-30 16:03:39 +00005915 attempts++;
5916 } while (hash_value == 0 && attempts < 30);
5917 hash_value = hash_value != 0 ? hash_value : 1; // never return 0
5918
Ben Murdoch3ef787d2012-04-12 10:51:47 +01005919 return Smi::FromInt(hash_value);
5920}
5921
5922
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005923template<typename ProxyType>
5924static Handle<Smi> GetOrCreateIdentityHashHelper(Handle<ProxyType> proxy) {
5925 Isolate* isolate = proxy->GetIsolate();
Ben Murdoch3ef787d2012-04-12 10:51:47 +01005926
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005927 Handle<Object> maybe_hash(proxy->hash(), isolate);
5928 if (maybe_hash->IsSmi()) return Handle<Smi>::cast(maybe_hash);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01005929
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005930 Handle<Smi> hash(GenerateIdentityHash(isolate), isolate);
5931 proxy->set_hash(*hash);
Ben Murdoch69a99ed2011-11-30 16:03:39 +00005932 return hash;
5933}
5934
Ben Murdochda12d292016-06-02 14:46:10 +01005935// static
5936Handle<Object> JSObject::GetIdentityHash(Isolate* isolate,
5937 Handle<JSObject> object) {
5938 if (object->IsJSGlobalProxy()) {
5939 return handle(JSGlobalProxy::cast(*object)->hash(), isolate);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01005940 }
Ben Murdochda12d292016-06-02 14:46:10 +01005941 Handle<Name> hash_code_symbol = isolate->factory()->hash_code_symbol();
5942 return JSReceiver::GetDataProperty(object, hash_code_symbol);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005943}
5944
Ben Murdochda12d292016-06-02 14:46:10 +01005945// static
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005946Handle<Smi> JSObject::GetOrCreateIdentityHash(Handle<JSObject> object) {
5947 if (object->IsJSGlobalProxy()) {
5948 return GetOrCreateIdentityHashHelper(Handle<JSGlobalProxy>::cast(object));
5949 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005950 Isolate* isolate = object->GetIsolate();
5951
Ben Murdochda12d292016-06-02 14:46:10 +01005952 Handle<Name> hash_code_symbol = isolate->factory()->hash_code_symbol();
5953 LookupIterator it(object, hash_code_symbol, object, LookupIterator::OWN);
5954 if (it.IsFound()) {
5955 DCHECK_EQ(LookupIterator::DATA, it.state());
5956 Handle<Object> maybe_hash = it.GetDataValue();
5957 if (maybe_hash->IsSmi()) return Handle<Smi>::cast(maybe_hash);
5958 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005959
5960 Handle<Smi> hash(GenerateIdentityHash(isolate), isolate);
Ben Murdochda12d292016-06-02 14:46:10 +01005961 CHECK(AddDataProperty(&it, hash, NONE, THROW_ON_ERROR,
5962 CERTAINLY_NOT_STORE_FROM_KEYED)
5963 .IsJust());
Ben Murdoch3ef787d2012-04-12 10:51:47 +01005964 return hash;
5965}
5966
Ben Murdochda12d292016-06-02 14:46:10 +01005967// static
5968Handle<Object> JSProxy::GetIdentityHash(Isolate* isolate,
5969 Handle<JSProxy> proxy) {
5970 return handle(proxy->hash(), isolate);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01005971}
5972
5973
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005974Handle<Smi> JSProxy::GetOrCreateIdentityHash(Handle<JSProxy> proxy) {
5975 return GetOrCreateIdentityHashHelper(proxy);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01005976}
5977
5978
Ben Murdoch097c5b22016-05-18 11:27:45 +01005979Maybe<bool> JSObject::DeletePropertyWithInterceptor(LookupIterator* it,
5980 ShouldThrow should_throw) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00005981 Isolate* isolate = it->isolate();
5982 // Make sure that the top context does not change when doing callbacks or
5983 // interceptor calls.
5984 AssertNoContextChange ncc(isolate);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005985
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00005986 DCHECK_EQ(LookupIterator::INTERCEPTOR, it->state());
5987 Handle<InterceptorInfo> interceptor(it->GetInterceptor());
5988 if (interceptor->deleter()->IsUndefined()) return Nothing<bool>();
5989
5990 Handle<JSObject> holder = it->GetHolder<JSObject>();
Ben Murdochda12d292016-06-02 14:46:10 +01005991 Handle<Object> receiver = it->GetReceiver();
5992 if (!receiver->IsJSReceiver()) {
5993 ASSIGN_RETURN_ON_EXCEPTION_VALUE(isolate, receiver,
5994 Object::ConvertReceiver(isolate, receiver),
5995 Nothing<bool>());
5996 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00005997
Ben Murdochda12d292016-06-02 14:46:10 +01005998 PropertyCallbackArguments args(isolate, interceptor->data(), *receiver,
5999 *holder, should_throw);
6000 Handle<Object> result;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00006001 if (it->IsElement()) {
6002 uint32_t index = it->index();
6003 v8::IndexedPropertyDeleterCallback deleter =
6004 v8::ToCData<v8::IndexedPropertyDeleterCallback>(interceptor->deleter());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00006005 result = args.Call(deleter, index);
6006 } else if (it->name()->IsSymbol() && !interceptor->can_intercept_symbols()) {
6007 return Nothing<bool>();
6008 } else {
6009 Handle<Name> name = it->name();
6010 DCHECK(!name->IsPrivate());
6011 v8::GenericNamedPropertyDeleterCallback deleter =
6012 v8::ToCData<v8::GenericNamedPropertyDeleterCallback>(
6013 interceptor->deleter());
Ben Murdochda12d292016-06-02 14:46:10 +01006014 result = args.Call(deleter, name);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04006015 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006016
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00006017 RETURN_VALUE_IF_SCHEDULED_EXCEPTION(isolate, Nothing<bool>());
Ben Murdochda12d292016-06-02 14:46:10 +01006018 if (result.is_null()) return Nothing<bool>();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006019
6020 DCHECK(result->IsBoolean());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006021 // Rebox CustomArguments::kReturnValueOffset before returning.
Ben Murdochda12d292016-06-02 14:46:10 +01006022 return Just(result->IsTrue());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006023}
6024
6025
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00006026void JSReceiver::DeleteNormalizedProperty(Handle<JSReceiver> object,
6027 Handle<Name> name, int entry) {
6028 DCHECK(!object->HasFastProperties());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006029 Isolate* isolate = object->GetIsolate();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006030
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00006031 if (object->IsJSGlobalObject()) {
6032 // If we have a global object, invalidate the cell and swap in a new one.
6033 Handle<GlobalDictionary> dictionary(
6034 JSObject::cast(*object)->global_dictionary());
6035 DCHECK_NE(GlobalDictionary::kNotFound, entry);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006036
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00006037 auto cell = PropertyCell::InvalidateEntry(dictionary, entry);
6038 cell->set_value(isolate->heap()->the_hole_value());
6039 // TODO(ishell): InvalidateForDelete
6040 cell->set_property_details(
6041 cell->property_details().set_cell_type(PropertyCellType::kInvalidated));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006042 } else {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00006043 Handle<NameDictionary> dictionary(object->property_dictionary());
6044 DCHECK_NE(NameDictionary::kNotFound, entry);
Steve Blocka7e24c12009-10-30 11:49:00 +00006045
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00006046 NameDictionary::DeleteProperty(dictionary, entry);
6047 Handle<NameDictionary> new_properties =
6048 NameDictionary::Shrink(dictionary, name);
6049 object->set_properties(*new_properties);
Steve Blocka7e24c12009-10-30 11:49:00 +00006050 }
Steve Blocka7e24c12009-10-30 11:49:00 +00006051}
6052
6053
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00006054Maybe<bool> JSReceiver::DeleteProperty(LookupIterator* it,
6055 LanguageMode language_mode) {
Ben Murdoch097c5b22016-05-18 11:27:45 +01006056 it->UpdateProtector();
6057
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00006058 Isolate* isolate = it->isolate();
Steve Blocka7e24c12009-10-30 11:49:00 +00006059
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00006060 if (it->state() == LookupIterator::JSPROXY) {
6061 return JSProxy::DeletePropertyOrElement(it->GetHolder<JSProxy>(),
6062 it->GetName(), language_mode);
Steve Blocka7e24c12009-10-30 11:49:00 +00006063 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006064
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00006065 if (it->GetReceiver()->IsJSProxy()) {
6066 if (it->state() != LookupIterator::NOT_FOUND) {
6067 DCHECK_EQ(LookupIterator::DATA, it->state());
Ben Murdoch097c5b22016-05-18 11:27:45 +01006068 DCHECK(it->name()->IsPrivate());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00006069 it->Delete();
6070 }
6071 return Just(true);
6072 }
6073 Handle<JSObject> receiver = Handle<JSObject>::cast(it->GetReceiver());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006074
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00006075 for (; it->IsFound(); it->Next()) {
6076 switch (it->state()) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006077 case LookupIterator::JSPROXY:
6078 case LookupIterator::NOT_FOUND:
6079 case LookupIterator::TRANSITION:
6080 UNREACHABLE();
6081 case LookupIterator::ACCESS_CHECK:
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00006082 if (it->HasAccess()) break;
6083 isolate->ReportFailedAccessCheck(it->GetHolder<JSObject>());
6084 RETURN_VALUE_IF_SCHEDULED_EXCEPTION(isolate, Nothing<bool>());
6085 return Just(false);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006086 case LookupIterator::INTERCEPTOR: {
Ben Murdoch097c5b22016-05-18 11:27:45 +01006087 ShouldThrow should_throw =
6088 is_sloppy(language_mode) ? DONT_THROW : THROW_ON_ERROR;
6089 Maybe<bool> result =
6090 JSObject::DeletePropertyWithInterceptor(it, should_throw);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006091 // An exception was thrown in the interceptor. Propagate.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00006092 if (isolate->has_pending_exception()) return Nothing<bool>();
6093 // Delete with interceptor succeeded. Return result.
6094 // TODO(neis): In strict mode, we should probably throw if the
6095 // interceptor returns false.
6096 if (result.IsJust()) return result;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006097 break;
6098 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00006099 case LookupIterator::INTEGER_INDEXED_EXOTIC:
6100 return Just(true);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006101 case LookupIterator::DATA:
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006102 case LookupIterator::ACCESSOR: {
Ben Murdochda12d292016-06-02 14:46:10 +01006103 if (!it->IsConfigurable()) {
6104 // Fail if the property is not configurable.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00006105 if (is_strict(language_mode)) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00006106 isolate->Throw(*isolate->factory()->NewTypeError(
Ben Murdochda12d292016-06-02 14:46:10 +01006107 MessageTemplate::kStrictDeleteProperty, it->GetName(),
6108 receiver));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00006109 return Nothing<bool>();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006110 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00006111 return Just(false);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006112 }
6113
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00006114 it->Delete();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006115
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00006116 return Just(true);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006117 }
6118 }
6119 }
6120
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00006121 return Just(true);
Steve Blocka7e24c12009-10-30 11:49:00 +00006122}
6123
6124
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00006125Maybe<bool> JSReceiver::DeleteElement(Handle<JSReceiver> object, uint32_t index,
6126 LanguageMode language_mode) {
Ben Murdochda12d292016-06-02 14:46:10 +01006127 LookupIterator it(object->GetIsolate(), object, index, object,
Ben Murdochc5610432016-08-08 18:44:38 +01006128 LookupIterator::OWN);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00006129 return DeleteProperty(&it, language_mode);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01006130}
6131
6132
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00006133Maybe<bool> JSReceiver::DeleteProperty(Handle<JSReceiver> object,
6134 Handle<Name> name,
6135 LanguageMode language_mode) {
Ben Murdochc5610432016-08-08 18:44:38 +01006136 LookupIterator it(object, name, object, LookupIterator::OWN);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00006137 return DeleteProperty(&it, language_mode);
6138}
6139
6140
6141Maybe<bool> JSReceiver::DeletePropertyOrElement(Handle<JSReceiver> object,
6142 Handle<Name> name,
6143 LanguageMode language_mode) {
6144 LookupIterator it = LookupIterator::PropertyOrElement(
Ben Murdochc5610432016-08-08 18:44:38 +01006145 name->GetIsolate(), object, name, object, LookupIterator::OWN);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00006146 return DeleteProperty(&it, language_mode);
6147}
6148
6149
6150// ES6 7.1.14
Ben Murdochc5610432016-08-08 18:44:38 +01006151// static
6152MaybeHandle<Object> Object::ToPropertyKey(Isolate* isolate,
6153 Handle<Object> value) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00006154 // 1. Let key be ToPrimitive(argument, hint String).
6155 MaybeHandle<Object> maybe_key =
6156 Object::ToPrimitive(value, ToPrimitiveHint::kString);
6157 // 2. ReturnIfAbrupt(key).
6158 Handle<Object> key;
6159 if (!maybe_key.ToHandle(&key)) return key;
6160 // 3. If Type(key) is Symbol, then return key.
6161 if (key->IsSymbol()) return key;
6162 // 4. Return ToString(key).
6163 // Extending spec'ed behavior, we'd be happy to return an element index.
6164 if (key->IsSmi()) return key;
6165 if (key->IsHeapNumber()) {
6166 uint32_t uint_value;
6167 if (value->ToArrayLength(&uint_value) &&
6168 uint_value <= static_cast<uint32_t>(Smi::kMaxValue)) {
6169 return handle(Smi::FromInt(static_cast<int>(uint_value)), isolate);
6170 }
Ben Murdoch3ef787d2012-04-12 10:51:47 +01006171 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00006172 return Object::ToString(isolate, key);
6173}
6174
6175
6176// ES6 19.1.2.4
6177// static
6178Object* JSReceiver::DefineProperty(Isolate* isolate, Handle<Object> object,
6179 Handle<Object> key,
6180 Handle<Object> attributes) {
6181 // 1. If Type(O) is not Object, throw a TypeError exception.
6182 if (!object->IsJSReceiver()) {
6183 Handle<String> fun_name =
6184 isolate->factory()->InternalizeUtf8String("Object.defineProperty");
6185 THROW_NEW_ERROR_RETURN_FAILURE(
6186 isolate, NewTypeError(MessageTemplate::kCalledOnNonObject, fun_name));
6187 }
6188 // 2. Let key be ToPropertyKey(P).
6189 // 3. ReturnIfAbrupt(key).
6190 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, key, ToPropertyKey(isolate, key));
6191 // 4. Let desc be ToPropertyDescriptor(Attributes).
6192 // 5. ReturnIfAbrupt(desc).
6193 PropertyDescriptor desc;
6194 if (!PropertyDescriptor::ToPropertyDescriptor(isolate, attributes, &desc)) {
6195 return isolate->heap()->exception();
6196 }
6197 // 6. Let success be DefinePropertyOrThrow(O,key, desc).
6198 Maybe<bool> success = DefineOwnProperty(
6199 isolate, Handle<JSReceiver>::cast(object), key, &desc, THROW_ON_ERROR);
6200 // 7. ReturnIfAbrupt(success).
6201 MAYBE_RETURN(success, isolate->heap()->exception());
6202 CHECK(success.FromJust());
6203 // 8. Return O.
6204 return *object;
6205}
6206
6207
6208// ES6 19.1.2.3.1
6209// static
6210MaybeHandle<Object> JSReceiver::DefineProperties(Isolate* isolate,
6211 Handle<Object> object,
6212 Handle<Object> properties) {
6213 // 1. If Type(O) is not Object, throw a TypeError exception.
6214 if (!object->IsJSReceiver()) {
6215 Handle<String> fun_name =
6216 isolate->factory()->InternalizeUtf8String("Object.defineProperties");
6217 THROW_NEW_ERROR(isolate,
6218 NewTypeError(MessageTemplate::kCalledOnNonObject, fun_name),
6219 Object);
6220 }
6221 // 2. Let props be ToObject(Properties).
6222 // 3. ReturnIfAbrupt(props).
6223 Handle<JSReceiver> props;
6224 if (!Object::ToObject(isolate, properties).ToHandle(&props)) {
6225 THROW_NEW_ERROR(isolate,
6226 NewTypeError(MessageTemplate::kUndefinedOrNullToObject),
6227 Object);
6228 }
6229 // 4. Let keys be props.[[OwnPropertyKeys]]().
6230 // 5. ReturnIfAbrupt(keys).
6231 Handle<FixedArray> keys;
6232 ASSIGN_RETURN_ON_EXCEPTION(
Ben Murdoch097c5b22016-05-18 11:27:45 +01006233 isolate, keys, JSReceiver::GetKeys(props, OWN_ONLY, ALL_PROPERTIES),
6234 Object);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00006235 // 6. Let descriptors be an empty List.
6236 int capacity = keys->length();
6237 std::vector<PropertyDescriptor> descriptors(capacity);
6238 size_t descriptors_index = 0;
6239 // 7. Repeat for each element nextKey of keys in List order,
6240 for (int i = 0; i < keys->length(); ++i) {
6241 Handle<Object> next_key(keys->get(i), isolate);
6242 // 7a. Let propDesc be props.[[GetOwnProperty]](nextKey).
6243 // 7b. ReturnIfAbrupt(propDesc).
6244 bool success = false;
6245 LookupIterator it = LookupIterator::PropertyOrElement(
Ben Murdochc5610432016-08-08 18:44:38 +01006246 isolate, props, next_key, &success, LookupIterator::OWN);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00006247 DCHECK(success);
6248 Maybe<PropertyAttributes> maybe = JSReceiver::GetPropertyAttributes(&it);
6249 if (!maybe.IsJust()) return MaybeHandle<Object>();
6250 PropertyAttributes attrs = maybe.FromJust();
6251 // 7c. If propDesc is not undefined and propDesc.[[Enumerable]] is true:
6252 if (attrs == ABSENT) continue;
6253 if (attrs & DONT_ENUM) continue;
6254 // 7c i. Let descObj be Get(props, nextKey).
6255 // 7c ii. ReturnIfAbrupt(descObj).
6256 Handle<Object> desc_obj;
6257 ASSIGN_RETURN_ON_EXCEPTION(isolate, desc_obj, Object::GetProperty(&it),
6258 Object);
6259 // 7c iii. Let desc be ToPropertyDescriptor(descObj).
6260 success = PropertyDescriptor::ToPropertyDescriptor(
6261 isolate, desc_obj, &descriptors[descriptors_index]);
6262 // 7c iv. ReturnIfAbrupt(desc).
6263 if (!success) return MaybeHandle<Object>();
6264 // 7c v. Append the pair (a two element List) consisting of nextKey and
6265 // desc to the end of descriptors.
6266 descriptors[descriptors_index].set_name(next_key);
6267 descriptors_index++;
6268 }
6269 // 8. For each pair from descriptors in list order,
6270 for (size_t i = 0; i < descriptors_index; ++i) {
6271 PropertyDescriptor* desc = &descriptors[i];
6272 // 8a. Let P be the first element of pair.
6273 // 8b. Let desc be the second element of pair.
6274 // 8c. Let status be DefinePropertyOrThrow(O, P, desc).
6275 Maybe<bool> status =
6276 DefineOwnProperty(isolate, Handle<JSReceiver>::cast(object),
6277 desc->name(), desc, THROW_ON_ERROR);
6278 // 8d. ReturnIfAbrupt(status).
6279 if (!status.IsJust()) return MaybeHandle<Object>();
6280 CHECK(status.FromJust());
6281 }
6282 // 9. Return o.
6283 return object;
6284}
6285
6286
6287// static
6288Maybe<bool> JSReceiver::DefineOwnProperty(Isolate* isolate,
6289 Handle<JSReceiver> object,
6290 Handle<Object> key,
6291 PropertyDescriptor* desc,
6292 ShouldThrow should_throw) {
6293 if (object->IsJSArray()) {
6294 return JSArray::DefineOwnProperty(isolate, Handle<JSArray>::cast(object),
6295 key, desc, should_throw);
6296 }
6297 if (object->IsJSProxy()) {
6298 return JSProxy::DefineOwnProperty(isolate, Handle<JSProxy>::cast(object),
6299 key, desc, should_throw);
6300 }
6301 // TODO(jkummerow): Support Modules (ES6 9.4.6.6)
6302
6303 // OrdinaryDefineOwnProperty, by virtue of calling
6304 // DefineOwnPropertyIgnoreAttributes, can handle arguments (ES6 9.4.4.2)
6305 // and IntegerIndexedExotics (ES6 9.4.5.3), with one exception:
6306 // TODO(jkummerow): Setting an indexed accessor on a typed array should throw.
6307 return OrdinaryDefineOwnProperty(isolate, Handle<JSObject>::cast(object), key,
6308 desc, should_throw);
6309}
6310
6311
6312// static
6313Maybe<bool> JSReceiver::OrdinaryDefineOwnProperty(Isolate* isolate,
6314 Handle<JSObject> object,
6315 Handle<Object> key,
6316 PropertyDescriptor* desc,
6317 ShouldThrow should_throw) {
6318 bool success = false;
6319 DCHECK(key->IsName() || key->IsNumber()); // |key| is a PropertyKey...
6320 LookupIterator it = LookupIterator::PropertyOrElement(
Ben Murdochc5610432016-08-08 18:44:38 +01006321 isolate, object, key, &success, LookupIterator::OWN);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00006322 DCHECK(success); // ...so creating a LookupIterator can't fail.
6323
6324 // Deal with access checks first.
6325 if (it.state() == LookupIterator::ACCESS_CHECK) {
6326 if (!it.HasAccess()) {
6327 isolate->ReportFailedAccessCheck(it.GetHolder<JSObject>());
6328 RETURN_VALUE_IF_SCHEDULED_EXCEPTION(isolate, Nothing<bool>());
6329 return Just(true);
6330 }
6331 it.Next();
6332 }
6333
6334 return OrdinaryDefineOwnProperty(&it, desc, should_throw);
6335}
6336
6337
6338// ES6 9.1.6.1
6339// static
6340Maybe<bool> JSReceiver::OrdinaryDefineOwnProperty(LookupIterator* it,
6341 PropertyDescriptor* desc,
6342 ShouldThrow should_throw) {
6343 Isolate* isolate = it->isolate();
6344 // 1. Let current be O.[[GetOwnProperty]](P).
6345 // 2. ReturnIfAbrupt(current).
6346 PropertyDescriptor current;
6347 MAYBE_RETURN(GetOwnPropertyDescriptor(it, &current), Nothing<bool>());
6348
6349 // TODO(jkummerow/verwaest): It would be nice if we didn't have to reset
6350 // the iterator every time. Currently, the reasons why we need it are:
6351 // - handle interceptors correctly
6352 // - handle accessors correctly (which might change the holder's map)
6353 it->Restart();
6354 // 3. Let extensible be the value of the [[Extensible]] internal slot of O.
6355 Handle<JSObject> object = Handle<JSObject>::cast(it->GetReceiver());
6356 bool extensible = JSObject::IsExtensible(object);
6357
6358 return ValidateAndApplyPropertyDescriptor(isolate, it, extensible, desc,
6359 &current, should_throw);
6360}
6361
6362
6363// ES6 9.1.6.2
6364// static
6365Maybe<bool> JSReceiver::IsCompatiblePropertyDescriptor(
6366 Isolate* isolate, bool extensible, PropertyDescriptor* desc,
6367 PropertyDescriptor* current, Handle<Name> property_name,
6368 ShouldThrow should_throw) {
6369 // 1. Return ValidateAndApplyPropertyDescriptor(undefined, undefined,
6370 // Extensible, Desc, Current).
6371 return ValidateAndApplyPropertyDescriptor(
6372 isolate, NULL, extensible, desc, current, should_throw, property_name);
6373}
6374
6375
6376// ES6 9.1.6.3
6377// static
6378Maybe<bool> JSReceiver::ValidateAndApplyPropertyDescriptor(
6379 Isolate* isolate, LookupIterator* it, bool extensible,
6380 PropertyDescriptor* desc, PropertyDescriptor* current,
6381 ShouldThrow should_throw, Handle<Name> property_name) {
6382 // We either need a LookupIterator, or a property name.
6383 DCHECK((it == NULL) != property_name.is_null());
6384 Handle<JSObject> object;
6385 if (it != NULL) object = Handle<JSObject>::cast(it->GetReceiver());
6386 bool desc_is_data_descriptor = PropertyDescriptor::IsDataDescriptor(desc);
6387 bool desc_is_accessor_descriptor =
6388 PropertyDescriptor::IsAccessorDescriptor(desc);
6389 bool desc_is_generic_descriptor =
6390 PropertyDescriptor::IsGenericDescriptor(desc);
6391 // 1. (Assert)
6392 // 2. If current is undefined, then
6393 if (current->is_empty()) {
6394 // 2a. If extensible is false, return false.
6395 if (!extensible) {
6396 RETURN_FAILURE(isolate, should_throw,
6397 NewTypeError(MessageTemplate::kDefineDisallowed,
6398 it != NULL ? it->GetName() : property_name));
6399 }
6400 // 2c. If IsGenericDescriptor(Desc) or IsDataDescriptor(Desc) is true, then:
6401 // (This is equivalent to !IsAccessorDescriptor(desc).)
6402 DCHECK((desc_is_generic_descriptor || desc_is_data_descriptor) ==
6403 !desc_is_accessor_descriptor);
6404 if (!desc_is_accessor_descriptor) {
6405 // 2c i. If O is not undefined, create an own data property named P of
6406 // object O whose [[Value]], [[Writable]], [[Enumerable]] and
6407 // [[Configurable]] attribute values are described by Desc. If the value
6408 // of an attribute field of Desc is absent, the attribute of the newly
6409 // created property is set to its default value.
6410 if (it != NULL) {
6411 if (!desc->has_writable()) desc->set_writable(false);
6412 if (!desc->has_enumerable()) desc->set_enumerable(false);
6413 if (!desc->has_configurable()) desc->set_configurable(false);
6414 Handle<Object> value(
6415 desc->has_value()
6416 ? desc->value()
6417 : Handle<Object>::cast(isolate->factory()->undefined_value()));
6418 MaybeHandle<Object> result =
Ben Murdoch097c5b22016-05-18 11:27:45 +01006419 JSObject::DefineOwnPropertyIgnoreAttributes(it, value,
6420 desc->ToAttributes());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00006421 if (result.is_null()) return Nothing<bool>();
6422 }
6423 } else {
6424 // 2d. Else Desc must be an accessor Property Descriptor,
6425 DCHECK(desc_is_accessor_descriptor);
6426 // 2d i. If O is not undefined, create an own accessor property named P
6427 // of object O whose [[Get]], [[Set]], [[Enumerable]] and
6428 // [[Configurable]] attribute values are described by Desc. If the value
6429 // of an attribute field of Desc is absent, the attribute of the newly
6430 // created property is set to its default value.
6431 if (it != NULL) {
6432 if (!desc->has_enumerable()) desc->set_enumerable(false);
6433 if (!desc->has_configurable()) desc->set_configurable(false);
6434 Handle<Object> getter(
6435 desc->has_get()
6436 ? desc->get()
6437 : Handle<Object>::cast(isolate->factory()->null_value()));
6438 Handle<Object> setter(
6439 desc->has_set()
6440 ? desc->set()
6441 : Handle<Object>::cast(isolate->factory()->null_value()));
6442 MaybeHandle<Object> result =
6443 JSObject::DefineAccessor(it, getter, setter, desc->ToAttributes());
6444 if (result.is_null()) return Nothing<bool>();
6445 }
6446 }
6447 // 2e. Return true.
6448 return Just(true);
6449 }
6450 // 3. Return true, if every field in Desc is absent.
6451 // 4. Return true, if every field in Desc also occurs in current and the
6452 // value of every field in Desc is the same value as the corresponding field
6453 // in current when compared using the SameValue algorithm.
6454 if ((!desc->has_enumerable() ||
6455 desc->enumerable() == current->enumerable()) &&
6456 (!desc->has_configurable() ||
6457 desc->configurable() == current->configurable()) &&
6458 (!desc->has_value() ||
6459 (current->has_value() && current->value()->SameValue(*desc->value()))) &&
6460 (!desc->has_writable() ||
6461 (current->has_writable() && current->writable() == desc->writable())) &&
6462 (!desc->has_get() ||
6463 (current->has_get() && current->get()->SameValue(*desc->get()))) &&
6464 (!desc->has_set() ||
6465 (current->has_set() && current->set()->SameValue(*desc->set())))) {
6466 return Just(true);
6467 }
6468 // 5. If the [[Configurable]] field of current is false, then
6469 if (!current->configurable()) {
6470 // 5a. Return false, if the [[Configurable]] field of Desc is true.
6471 if (desc->has_configurable() && desc->configurable()) {
6472 RETURN_FAILURE(isolate, should_throw,
6473 NewTypeError(MessageTemplate::kRedefineDisallowed,
6474 it != NULL ? it->GetName() : property_name));
6475 }
6476 // 5b. Return false, if the [[Enumerable]] field of Desc is present and the
6477 // [[Enumerable]] fields of current and Desc are the Boolean negation of
6478 // each other.
6479 if (desc->has_enumerable() && desc->enumerable() != current->enumerable()) {
6480 RETURN_FAILURE(isolate, should_throw,
6481 NewTypeError(MessageTemplate::kRedefineDisallowed,
6482 it != NULL ? it->GetName() : property_name));
6483 }
6484 }
6485
6486 bool current_is_data_descriptor =
6487 PropertyDescriptor::IsDataDescriptor(current);
6488 // 6. If IsGenericDescriptor(Desc) is true, no further validation is required.
6489 if (desc_is_generic_descriptor) {
6490 // Nothing to see here.
6491
6492 // 7. Else if IsDataDescriptor(current) and IsDataDescriptor(Desc) have
6493 // different results, then:
6494 } else if (current_is_data_descriptor != desc_is_data_descriptor) {
6495 // 7a. Return false, if the [[Configurable]] field of current is false.
6496 if (!current->configurable()) {
6497 RETURN_FAILURE(isolate, should_throw,
6498 NewTypeError(MessageTemplate::kRedefineDisallowed,
6499 it != NULL ? it->GetName() : property_name));
6500 }
6501 // 7b. If IsDataDescriptor(current) is true, then:
6502 if (current_is_data_descriptor) {
6503 // 7b i. If O is not undefined, convert the property named P of object O
6504 // from a data property to an accessor property. Preserve the existing
6505 // values of the converted property's [[Configurable]] and [[Enumerable]]
6506 // attributes and set the rest of the property's attributes to their
6507 // default values.
6508 // --> Folded into step 10.
6509 } else {
6510 // 7c i. If O is not undefined, convert the property named P of object O
6511 // from an accessor property to a data property. Preserve the existing
6512 // values of the converted property’s [[Configurable]] and [[Enumerable]]
6513 // attributes and set the rest of the property’s attributes to their
6514 // default values.
6515 // --> Folded into step 10.
6516 }
6517
6518 // 8. Else if IsDataDescriptor(current) and IsDataDescriptor(Desc) are both
6519 // true, then:
6520 } else if (current_is_data_descriptor && desc_is_data_descriptor) {
6521 // 8a. If the [[Configurable]] field of current is false, then:
6522 if (!current->configurable()) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00006523 // 8a i. Return false, if the [[Writable]] field of current is false and
6524 // the [[Writable]] field of Desc is true.
6525 if (!current->writable() && desc->has_writable() && desc->writable()) {
6526 RETURN_FAILURE(
6527 isolate, should_throw,
6528 NewTypeError(MessageTemplate::kRedefineDisallowed,
6529 it != NULL ? it->GetName() : property_name));
6530 }
6531 // 8a ii. If the [[Writable]] field of current is false, then:
6532 if (!current->writable()) {
6533 // 8a ii 1. Return false, if the [[Value]] field of Desc is present and
6534 // SameValue(Desc.[[Value]], current.[[Value]]) is false.
6535 if (desc->has_value() && !desc->value()->SameValue(*current->value())) {
6536 RETURN_FAILURE(
6537 isolate, should_throw,
6538 NewTypeError(MessageTemplate::kRedefineDisallowed,
6539 it != NULL ? it->GetName() : property_name));
6540 }
6541 }
6542 }
6543 } else {
6544 // 9. Else IsAccessorDescriptor(current) and IsAccessorDescriptor(Desc)
6545 // are both true,
6546 DCHECK(PropertyDescriptor::IsAccessorDescriptor(current) &&
6547 desc_is_accessor_descriptor);
6548 // 9a. If the [[Configurable]] field of current is false, then:
6549 if (!current->configurable()) {
6550 // 9a i. Return false, if the [[Set]] field of Desc is present and
6551 // SameValue(Desc.[[Set]], current.[[Set]]) is false.
6552 if (desc->has_set() && !desc->set()->SameValue(*current->set())) {
6553 RETURN_FAILURE(
6554 isolate, should_throw,
6555 NewTypeError(MessageTemplate::kRedefineDisallowed,
6556 it != NULL ? it->GetName() : property_name));
6557 }
6558 // 9a ii. Return false, if the [[Get]] field of Desc is present and
6559 // SameValue(Desc.[[Get]], current.[[Get]]) is false.
6560 if (desc->has_get() && !desc->get()->SameValue(*current->get())) {
6561 RETURN_FAILURE(
6562 isolate, should_throw,
6563 NewTypeError(MessageTemplate::kRedefineDisallowed,
6564 it != NULL ? it->GetName() : property_name));
6565 }
6566 }
6567 }
6568
6569 // 10. If O is not undefined, then:
6570 if (it != NULL) {
6571 // 10a. For each field of Desc that is present, set the corresponding
6572 // attribute of the property named P of object O to the value of the field.
6573 PropertyAttributes attrs = NONE;
6574
6575 if (desc->has_enumerable()) {
6576 attrs = static_cast<PropertyAttributes>(
6577 attrs | (desc->enumerable() ? NONE : DONT_ENUM));
6578 } else {
6579 attrs = static_cast<PropertyAttributes>(
6580 attrs | (current->enumerable() ? NONE : DONT_ENUM));
6581 }
6582 if (desc->has_configurable()) {
6583 attrs = static_cast<PropertyAttributes>(
6584 attrs | (desc->configurable() ? NONE : DONT_DELETE));
6585 } else {
6586 attrs = static_cast<PropertyAttributes>(
6587 attrs | (current->configurable() ? NONE : DONT_DELETE));
6588 }
6589 if (desc_is_data_descriptor ||
6590 (desc_is_generic_descriptor && current_is_data_descriptor)) {
6591 if (desc->has_writable()) {
6592 attrs = static_cast<PropertyAttributes>(
6593 attrs | (desc->writable() ? NONE : READ_ONLY));
6594 } else {
6595 attrs = static_cast<PropertyAttributes>(
6596 attrs | (current->writable() ? NONE : READ_ONLY));
6597 }
6598 Handle<Object> value(
6599 desc->has_value() ? desc->value()
6600 : current->has_value()
6601 ? current->value()
6602 : Handle<Object>::cast(
6603 isolate->factory()->undefined_value()));
Ben Murdoch097c5b22016-05-18 11:27:45 +01006604 MaybeHandle<Object> result =
6605 JSObject::DefineOwnPropertyIgnoreAttributes(it, value, attrs);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00006606 if (result.is_null()) return Nothing<bool>();
6607 } else {
6608 DCHECK(desc_is_accessor_descriptor ||
6609 (desc_is_generic_descriptor &&
6610 PropertyDescriptor::IsAccessorDescriptor(current)));
6611 Handle<Object> getter(
6612 desc->has_get()
6613 ? desc->get()
6614 : current->has_get()
6615 ? current->get()
6616 : Handle<Object>::cast(isolate->factory()->null_value()));
6617 Handle<Object> setter(
6618 desc->has_set()
6619 ? desc->set()
6620 : current->has_set()
6621 ? current->set()
6622 : Handle<Object>::cast(isolate->factory()->null_value()));
6623 MaybeHandle<Object> result =
6624 JSObject::DefineAccessor(it, getter, setter, attrs);
6625 if (result.is_null()) return Nothing<bool>();
6626 }
6627 }
6628
6629 // 11. Return true.
6630 return Just(true);
6631}
6632
6633
6634// static
6635Maybe<bool> JSReceiver::CreateDataProperty(LookupIterator* it,
6636 Handle<Object> value,
6637 ShouldThrow should_throw) {
6638 DCHECK(!it->check_prototype_chain());
6639 Handle<JSReceiver> receiver = Handle<JSReceiver>::cast(it->GetReceiver());
6640 Isolate* isolate = receiver->GetIsolate();
6641
6642 if (receiver->IsJSObject()) {
Ben Murdochda12d292016-06-02 14:46:10 +01006643 return JSObject::CreateDataProperty(it, value, should_throw); // Shortcut.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00006644 }
6645
6646 PropertyDescriptor new_desc;
6647 new_desc.set_value(value);
6648 new_desc.set_writable(true);
6649 new_desc.set_enumerable(true);
6650 new_desc.set_configurable(true);
6651
6652 return JSReceiver::DefineOwnProperty(isolate, receiver, it->GetName(),
6653 &new_desc, should_throw);
6654}
6655
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00006656Maybe<bool> JSObject::CreateDataProperty(LookupIterator* it,
Ben Murdochda12d292016-06-02 14:46:10 +01006657 Handle<Object> value,
6658 ShouldThrow should_throw) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00006659 DCHECK(it->GetReceiver()->IsJSObject());
6660 MAYBE_RETURN(JSReceiver::GetPropertyAttributes(it), Nothing<bool>());
Ben Murdochda12d292016-06-02 14:46:10 +01006661 Handle<JSReceiver> receiver = Handle<JSReceiver>::cast(it->GetReceiver());
6662 Isolate* isolate = receiver->GetIsolate();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00006663
6664 if (it->IsFound()) {
Ben Murdochda12d292016-06-02 14:46:10 +01006665 Maybe<PropertyAttributes> attributes = GetPropertyAttributes(it);
6666 MAYBE_RETURN(attributes, Nothing<bool>());
6667 if ((attributes.FromJust() & DONT_DELETE) != 0) {
6668 RETURN_FAILURE(
6669 isolate, should_throw,
6670 NewTypeError(MessageTemplate::kRedefineDisallowed, it->GetName()));
6671 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00006672 } else {
Ben Murdochda12d292016-06-02 14:46:10 +01006673 if (!JSObject::IsExtensible(Handle<JSObject>::cast(it->GetReceiver()))) {
6674 RETURN_FAILURE(
6675 isolate, should_throw,
6676 NewTypeError(MessageTemplate::kDefineDisallowed, it->GetName()));
6677 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00006678 }
6679
Ben Murdoch097c5b22016-05-18 11:27:45 +01006680 RETURN_ON_EXCEPTION_VALUE(it->isolate(),
6681 DefineOwnPropertyIgnoreAttributes(it, value, NONE),
6682 Nothing<bool>());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00006683
6684 return Just(true);
6685}
6686
6687
6688// TODO(jkummerow): Consider unification with FastAsArrayLength() in
6689// accessors.cc.
6690bool PropertyKeyToArrayLength(Handle<Object> value, uint32_t* length) {
6691 DCHECK(value->IsNumber() || value->IsName());
6692 if (value->ToArrayLength(length)) return true;
6693 if (value->IsString()) return String::cast(*value)->AsArrayIndex(length);
6694 return false;
6695}
6696
6697
6698bool PropertyKeyToArrayIndex(Handle<Object> index_obj, uint32_t* output) {
6699 return PropertyKeyToArrayLength(index_obj, output) && *output != kMaxUInt32;
6700}
6701
6702
6703// ES6 9.4.2.1
6704// static
6705Maybe<bool> JSArray::DefineOwnProperty(Isolate* isolate, Handle<JSArray> o,
6706 Handle<Object> name,
6707 PropertyDescriptor* desc,
6708 ShouldThrow should_throw) {
6709 // 1. Assert: IsPropertyKey(P) is true. ("P" is |name|.)
6710 // 2. If P is "length", then:
6711 // TODO(jkummerow): Check if we need slow string comparison.
6712 if (*name == isolate->heap()->length_string()) {
6713 // 2a. Return ArraySetLength(A, Desc).
6714 return ArraySetLength(isolate, o, desc, should_throw);
6715 }
6716 // 3. Else if P is an array index, then:
6717 uint32_t index = 0;
6718 if (PropertyKeyToArrayIndex(name, &index)) {
6719 // 3a. Let oldLenDesc be OrdinaryGetOwnProperty(A, "length").
6720 PropertyDescriptor old_len_desc;
6721 Maybe<bool> success = GetOwnPropertyDescriptor(
6722 isolate, o, isolate->factory()->length_string(), &old_len_desc);
6723 // 3b. (Assert)
6724 DCHECK(success.FromJust());
6725 USE(success);
6726 // 3c. Let oldLen be oldLenDesc.[[Value]].
6727 uint32_t old_len = 0;
6728 CHECK(old_len_desc.value()->ToArrayLength(&old_len));
6729 // 3d. Let index be ToUint32(P).
6730 // (Already done above.)
6731 // 3e. (Assert)
6732 // 3f. If index >= oldLen and oldLenDesc.[[Writable]] is false,
6733 // return false.
6734 if (index >= old_len && old_len_desc.has_writable() &&
6735 !old_len_desc.writable()) {
6736 RETURN_FAILURE(isolate, should_throw,
6737 NewTypeError(MessageTemplate::kDefineDisallowed, name));
6738 }
6739 // 3g. Let succeeded be OrdinaryDefineOwnProperty(A, P, Desc).
6740 Maybe<bool> succeeded =
6741 OrdinaryDefineOwnProperty(isolate, o, name, desc, should_throw);
6742 // 3h. Assert: succeeded is not an abrupt completion.
6743 // In our case, if should_throw == THROW_ON_ERROR, it can be!
6744 // 3i. If succeeded is false, return false.
6745 if (succeeded.IsNothing() || !succeeded.FromJust()) return succeeded;
6746 // 3j. If index >= oldLen, then:
6747 if (index >= old_len) {
6748 // 3j i. Set oldLenDesc.[[Value]] to index + 1.
6749 old_len_desc.set_value(isolate->factory()->NewNumberFromUint(index + 1));
6750 // 3j ii. Let succeeded be
6751 // OrdinaryDefineOwnProperty(A, "length", oldLenDesc).
6752 succeeded = OrdinaryDefineOwnProperty(isolate, o,
6753 isolate->factory()->length_string(),
6754 &old_len_desc, should_throw);
6755 // 3j iii. Assert: succeeded is true.
6756 DCHECK(succeeded.FromJust());
6757 USE(succeeded);
6758 }
6759 // 3k. Return true.
6760 return Just(true);
6761 }
6762
6763 // 4. Return OrdinaryDefineOwnProperty(A, P, Desc).
6764 return OrdinaryDefineOwnProperty(isolate, o, name, desc, should_throw);
6765}
6766
6767
6768// Part of ES6 9.4.2.4 ArraySetLength.
6769// static
6770bool JSArray::AnythingToArrayLength(Isolate* isolate,
6771 Handle<Object> length_object,
6772 uint32_t* output) {
6773 // Fast path: check numbers and strings that can be converted directly
6774 // and unobservably.
6775 if (length_object->ToArrayLength(output)) return true;
6776 if (length_object->IsString() &&
6777 Handle<String>::cast(length_object)->AsArrayIndex(output)) {
6778 return true;
6779 }
6780 // Slow path: follow steps in ES6 9.4.2.4 "ArraySetLength".
6781 // 3. Let newLen be ToUint32(Desc.[[Value]]).
6782 Handle<Object> uint32_v;
6783 if (!Object::ToUint32(isolate, length_object).ToHandle(&uint32_v)) {
6784 // 4. ReturnIfAbrupt(newLen).
6785 return false;
6786 }
6787 // 5. Let numberLen be ToNumber(Desc.[[Value]]).
6788 Handle<Object> number_v;
6789 if (!Object::ToNumber(length_object).ToHandle(&number_v)) {
6790 // 6. ReturnIfAbrupt(newLen).
6791 return false;
6792 }
6793 // 7. If newLen != numberLen, throw a RangeError exception.
6794 if (uint32_v->Number() != number_v->Number()) {
6795 Handle<Object> exception =
6796 isolate->factory()->NewRangeError(MessageTemplate::kInvalidArrayLength);
6797 isolate->Throw(*exception);
6798 return false;
6799 }
6800 CHECK(uint32_v->ToArrayLength(output));
6801 return true;
6802}
6803
6804
6805// ES6 9.4.2.4
6806// static
6807Maybe<bool> JSArray::ArraySetLength(Isolate* isolate, Handle<JSArray> a,
6808 PropertyDescriptor* desc,
6809 ShouldThrow should_throw) {
6810 // 1. If the [[Value]] field of Desc is absent, then
6811 if (!desc->has_value()) {
6812 // 1a. Return OrdinaryDefineOwnProperty(A, "length", Desc).
6813 return OrdinaryDefineOwnProperty(
6814 isolate, a, isolate->factory()->length_string(), desc, should_throw);
6815 }
6816 // 2. Let newLenDesc be a copy of Desc.
6817 // (Actual copying is not necessary.)
6818 PropertyDescriptor* new_len_desc = desc;
6819 // 3. - 7. Convert Desc.[[Value]] to newLen.
6820 uint32_t new_len = 0;
6821 if (!AnythingToArrayLength(isolate, desc->value(), &new_len)) {
6822 DCHECK(isolate->has_pending_exception());
6823 return Nothing<bool>();
6824 }
6825 // 8. Set newLenDesc.[[Value]] to newLen.
6826 // (Done below, if needed.)
6827 // 9. Let oldLenDesc be OrdinaryGetOwnProperty(A, "length").
6828 PropertyDescriptor old_len_desc;
6829 Maybe<bool> success = GetOwnPropertyDescriptor(
6830 isolate, a, isolate->factory()->length_string(), &old_len_desc);
6831 // 10. (Assert)
6832 DCHECK(success.FromJust());
6833 USE(success);
6834 // 11. Let oldLen be oldLenDesc.[[Value]].
6835 uint32_t old_len = 0;
6836 CHECK(old_len_desc.value()->ToArrayLength(&old_len));
6837 // 12. If newLen >= oldLen, then
6838 if (new_len >= old_len) {
6839 // 8. Set newLenDesc.[[Value]] to newLen.
6840 // 12a. Return OrdinaryDefineOwnProperty(A, "length", newLenDesc).
6841 new_len_desc->set_value(isolate->factory()->NewNumberFromUint(new_len));
6842 return OrdinaryDefineOwnProperty(isolate, a,
6843 isolate->factory()->length_string(),
6844 new_len_desc, should_throw);
6845 }
6846 // 13. If oldLenDesc.[[Writable]] is false, return false.
6847 if (!old_len_desc.writable()) {
6848 RETURN_FAILURE(isolate, should_throw,
6849 NewTypeError(MessageTemplate::kRedefineDisallowed,
6850 isolate->factory()->length_string()));
6851 }
6852 // 14. If newLenDesc.[[Writable]] is absent or has the value true,
6853 // let newWritable be true.
6854 bool new_writable = false;
6855 if (!new_len_desc->has_writable() || new_len_desc->writable()) {
6856 new_writable = true;
6857 } else {
6858 // 15. Else,
6859 // 15a. Need to defer setting the [[Writable]] attribute to false in case
6860 // any elements cannot be deleted.
6861 // 15b. Let newWritable be false. (It's initialized as "false" anyway.)
6862 // 15c. Set newLenDesc.[[Writable]] to true.
6863 // (Not needed.)
6864 }
6865 // Most of steps 16 through 19 is implemented by JSArray::SetLength.
Ben Murdochc5610432016-08-08 18:44:38 +01006866 JSArray::SetLength(a, new_len);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00006867 // Steps 19d-ii, 20.
6868 if (!new_writable) {
6869 PropertyDescriptor readonly;
6870 readonly.set_writable(false);
6871 Maybe<bool> success = OrdinaryDefineOwnProperty(
6872 isolate, a, isolate->factory()->length_string(), &readonly,
6873 should_throw);
6874 DCHECK(success.FromJust());
6875 USE(success);
6876 }
6877 uint32_t actual_new_len = 0;
6878 CHECK(a->length()->ToArrayLength(&actual_new_len));
6879 // Steps 19d-v, 21. Return false if there were non-deletable elements.
6880 bool result = actual_new_len == new_len;
6881 if (!result) {
6882 RETURN_FAILURE(
6883 isolate, should_throw,
6884 NewTypeError(MessageTemplate::kStrictDeleteProperty,
6885 isolate->factory()->NewNumberFromUint(actual_new_len - 1),
6886 a));
6887 }
6888 return Just(result);
6889}
6890
6891
6892// ES6 9.5.6
6893// static
6894Maybe<bool> JSProxy::DefineOwnProperty(Isolate* isolate, Handle<JSProxy> proxy,
6895 Handle<Object> key,
6896 PropertyDescriptor* desc,
6897 ShouldThrow should_throw) {
Ben Murdochc5610432016-08-08 18:44:38 +01006898 STACK_CHECK(isolate, Nothing<bool>());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00006899 if (key->IsSymbol() && Handle<Symbol>::cast(key)->IsPrivate()) {
Ben Murdoch097c5b22016-05-18 11:27:45 +01006900 return SetPrivateProperty(isolate, proxy, Handle<Symbol>::cast(key), desc,
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00006901 should_throw);
6902 }
6903 Handle<String> trap_name = isolate->factory()->defineProperty_string();
6904 // 1. Assert: IsPropertyKey(P) is true.
6905 DCHECK(key->IsName() || key->IsNumber());
6906 // 2. Let handler be the value of the [[ProxyHandler]] internal slot of O.
6907 Handle<Object> handler(proxy->handler(), isolate);
6908 // 3. If handler is null, throw a TypeError exception.
6909 // 4. Assert: Type(handler) is Object.
6910 if (proxy->IsRevoked()) {
6911 isolate->Throw(*isolate->factory()->NewTypeError(
6912 MessageTemplate::kProxyRevoked, trap_name));
6913 return Nothing<bool>();
6914 }
6915 // 5. Let target be the value of the [[ProxyTarget]] internal slot of O.
6916 Handle<JSReceiver> target(proxy->target(), isolate);
6917 // 6. Let trap be ? GetMethod(handler, "defineProperty").
6918 Handle<Object> trap;
6919 ASSIGN_RETURN_ON_EXCEPTION_VALUE(
6920 isolate, trap,
6921 Object::GetMethod(Handle<JSReceiver>::cast(handler), trap_name),
6922 Nothing<bool>());
6923 // 7. If trap is undefined, then:
6924 if (trap->IsUndefined()) {
6925 // 7a. Return target.[[DefineOwnProperty]](P, Desc).
6926 return JSReceiver::DefineOwnProperty(isolate, target, key, desc,
6927 should_throw);
6928 }
6929 // 8. Let descObj be FromPropertyDescriptor(Desc).
6930 Handle<Object> desc_obj = desc->ToObject(isolate);
6931 // 9. Let booleanTrapResult be
6932 // ToBoolean(? Call(trap, handler, «target, P, descObj»)).
6933 Handle<Name> property_name =
6934 key->IsName()
6935 ? Handle<Name>::cast(key)
6936 : Handle<Name>::cast(isolate->factory()->NumberToString(key));
6937 // Do not leak private property names.
6938 DCHECK(!property_name->IsPrivate());
6939 Handle<Object> trap_result_obj;
6940 Handle<Object> args[] = {target, property_name, desc_obj};
6941 ASSIGN_RETURN_ON_EXCEPTION_VALUE(
6942 isolate, trap_result_obj,
6943 Execution::Call(isolate, trap, handler, arraysize(args), args),
6944 Nothing<bool>());
6945 // 10. If booleanTrapResult is false, return false.
6946 if (!trap_result_obj->BooleanValue()) {
6947 RETURN_FAILURE(isolate, should_throw,
6948 NewTypeError(MessageTemplate::kProxyTrapReturnedFalsishFor,
6949 trap_name, property_name));
6950 }
6951 // 11. Let targetDesc be ? target.[[GetOwnProperty]](P).
6952 PropertyDescriptor target_desc;
6953 Maybe<bool> target_found =
6954 JSReceiver::GetOwnPropertyDescriptor(isolate, target, key, &target_desc);
6955 MAYBE_RETURN(target_found, Nothing<bool>());
6956 // 12. Let extensibleTarget be ? IsExtensible(target).
6957 Maybe<bool> maybe_extensible = JSReceiver::IsExtensible(target);
6958 MAYBE_RETURN(maybe_extensible, Nothing<bool>());
6959 bool extensible_target = maybe_extensible.FromJust();
6960 // 13. If Desc has a [[Configurable]] field and if Desc.[[Configurable]]
6961 // is false, then:
6962 // 13a. Let settingConfigFalse be true.
6963 // 14. Else let settingConfigFalse be false.
6964 bool setting_config_false = desc->has_configurable() && !desc->configurable();
6965 // 15. If targetDesc is undefined, then
6966 if (!target_found.FromJust()) {
6967 // 15a. If extensibleTarget is false, throw a TypeError exception.
6968 if (!extensible_target) {
6969 isolate->Throw(*isolate->factory()->NewTypeError(
6970 MessageTemplate::kProxyDefinePropertyNonExtensible, property_name));
6971 return Nothing<bool>();
6972 }
6973 // 15b. If settingConfigFalse is true, throw a TypeError exception.
6974 if (setting_config_false) {
6975 isolate->Throw(*isolate->factory()->NewTypeError(
6976 MessageTemplate::kProxyDefinePropertyNonConfigurable, property_name));
6977 return Nothing<bool>();
6978 }
6979 } else {
6980 // 16. Else targetDesc is not undefined,
6981 // 16a. If IsCompatiblePropertyDescriptor(extensibleTarget, Desc,
6982 // targetDesc) is false, throw a TypeError exception.
6983 Maybe<bool> valid =
6984 IsCompatiblePropertyDescriptor(isolate, extensible_target, desc,
6985 &target_desc, property_name, DONT_THROW);
6986 MAYBE_RETURN(valid, Nothing<bool>());
6987 if (!valid.FromJust()) {
6988 isolate->Throw(*isolate->factory()->NewTypeError(
6989 MessageTemplate::kProxyDefinePropertyIncompatible, property_name));
6990 return Nothing<bool>();
6991 }
6992 // 16b. If settingConfigFalse is true and targetDesc.[[Configurable]] is
6993 // true, throw a TypeError exception.
6994 if (setting_config_false && target_desc.configurable()) {
6995 isolate->Throw(*isolate->factory()->NewTypeError(
6996 MessageTemplate::kProxyDefinePropertyNonConfigurable, property_name));
6997 return Nothing<bool>();
6998 }
6999 }
7000 // 17. Return true.
7001 return Just(true);
7002}
7003
7004
7005// static
Ben Murdoch097c5b22016-05-18 11:27:45 +01007006Maybe<bool> JSProxy::SetPrivateProperty(Isolate* isolate, Handle<JSProxy> proxy,
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00007007 Handle<Symbol> private_name,
7008 PropertyDescriptor* desc,
7009 ShouldThrow should_throw) {
7010 // Despite the generic name, this can only add private data properties.
7011 if (!PropertyDescriptor::IsDataDescriptor(desc) ||
7012 desc->ToAttributes() != DONT_ENUM) {
7013 RETURN_FAILURE(isolate, should_throw,
7014 NewTypeError(MessageTemplate::kProxyPrivate));
7015 }
7016 DCHECK(proxy->map()->is_dictionary_map());
7017 Handle<Object> value =
7018 desc->has_value()
7019 ? desc->value()
7020 : Handle<Object>::cast(isolate->factory()->undefined_value());
7021
Ben Murdochda12d292016-06-02 14:46:10 +01007022 LookupIterator it(proxy, private_name, proxy);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00007023
7024 if (it.IsFound()) {
7025 DCHECK_EQ(LookupIterator::DATA, it.state());
Ben Murdoch097c5b22016-05-18 11:27:45 +01007026 DCHECK_EQ(DONT_ENUM, it.property_attributes());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00007027 it.WriteDataValue(value);
7028 return Just(true);
7029 }
7030
7031 Handle<NameDictionary> dict(proxy->property_dictionary());
7032 PropertyDetails details(DONT_ENUM, DATA, 0, PropertyCellType::kNoCell);
7033 Handle<NameDictionary> result =
7034 NameDictionary::Add(dict, private_name, value, details);
7035 if (!dict.is_identical_to(result)) proxy->set_properties(*result);
7036 return Just(true);
7037}
7038
7039
7040// static
7041Maybe<bool> JSReceiver::GetOwnPropertyDescriptor(Isolate* isolate,
7042 Handle<JSReceiver> object,
7043 Handle<Object> key,
7044 PropertyDescriptor* desc) {
7045 bool success = false;
7046 DCHECK(key->IsName() || key->IsNumber()); // |key| is a PropertyKey...
7047 LookupIterator it = LookupIterator::PropertyOrElement(
Ben Murdochc5610432016-08-08 18:44:38 +01007048 isolate, object, key, &success, LookupIterator::OWN);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00007049 DCHECK(success); // ...so creating a LookupIterator can't fail.
7050 return GetOwnPropertyDescriptor(&it, desc);
7051}
7052
7053
7054// ES6 9.1.5.1
7055// Returns true on success, false if the property didn't exist, nothing if
7056// an exception was thrown.
7057// static
7058Maybe<bool> JSReceiver::GetOwnPropertyDescriptor(LookupIterator* it,
7059 PropertyDescriptor* desc) {
7060 Isolate* isolate = it->isolate();
7061 // "Virtual" dispatch.
7062 if (it->IsFound() && it->GetHolder<JSReceiver>()->IsJSProxy()) {
7063 return JSProxy::GetOwnPropertyDescriptor(isolate, it->GetHolder<JSProxy>(),
7064 it->GetName(), desc);
7065 }
7066
7067 // 1. (Assert)
7068 // 2. If O does not have an own property with key P, return undefined.
7069 Maybe<PropertyAttributes> maybe = JSObject::GetPropertyAttributes(it);
7070 MAYBE_RETURN(maybe, Nothing<bool>());
7071 PropertyAttributes attrs = maybe.FromJust();
7072 if (attrs == ABSENT) return Just(false);
7073 DCHECK(!isolate->has_pending_exception());
7074
7075 // 3. Let D be a newly created Property Descriptor with no fields.
7076 DCHECK(desc->is_empty());
7077 // 4. Let X be O's own property whose key is P.
7078 // 5. If X is a data property, then
7079 bool is_accessor_pair = it->state() == LookupIterator::ACCESSOR &&
7080 it->GetAccessors()->IsAccessorPair();
7081 if (!is_accessor_pair) {
7082 // 5a. Set D.[[Value]] to the value of X's [[Value]] attribute.
7083 Handle<Object> value;
Ben Murdochda12d292016-06-02 14:46:10 +01007084 if (!Object::GetProperty(it).ToHandle(&value)) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00007085 DCHECK(isolate->has_pending_exception());
7086 return Nothing<bool>();
7087 }
7088 desc->set_value(value);
7089 // 5b. Set D.[[Writable]] to the value of X's [[Writable]] attribute
7090 desc->set_writable((attrs & READ_ONLY) == 0);
7091 } else {
7092 // 6. Else X is an accessor property, so
7093 Handle<AccessorPair> accessors =
7094 Handle<AccessorPair>::cast(it->GetAccessors());
7095 // 6a. Set D.[[Get]] to the value of X's [[Get]] attribute.
Ben Murdoch097c5b22016-05-18 11:27:45 +01007096 desc->set_get(AccessorPair::GetComponent(accessors, ACCESSOR_GETTER));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00007097 // 6b. Set D.[[Set]] to the value of X's [[Set]] attribute.
Ben Murdoch097c5b22016-05-18 11:27:45 +01007098 desc->set_set(AccessorPair::GetComponent(accessors, ACCESSOR_SETTER));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00007099 }
7100
7101 // 7. Set D.[[Enumerable]] to the value of X's [[Enumerable]] attribute.
7102 desc->set_enumerable((attrs & DONT_ENUM) == 0);
7103 // 8. Set D.[[Configurable]] to the value of X's [[Configurable]] attribute.
7104 desc->set_configurable((attrs & DONT_DELETE) == 0);
7105 // 9. Return D.
7106 DCHECK(PropertyDescriptor::IsAccessorDescriptor(desc) !=
7107 PropertyDescriptor::IsDataDescriptor(desc));
7108 return Just(true);
7109}
7110
7111
7112// ES6 9.5.5
7113// static
7114Maybe<bool> JSProxy::GetOwnPropertyDescriptor(Isolate* isolate,
7115 Handle<JSProxy> proxy,
7116 Handle<Name> name,
7117 PropertyDescriptor* desc) {
7118 DCHECK(!name->IsPrivate());
Ben Murdochc5610432016-08-08 18:44:38 +01007119 STACK_CHECK(isolate, Nothing<bool>());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00007120
7121 Handle<String> trap_name =
7122 isolate->factory()->getOwnPropertyDescriptor_string();
7123 // 1. (Assert)
7124 // 2. Let handler be the value of the [[ProxyHandler]] internal slot of O.
7125 Handle<Object> handler(proxy->handler(), isolate);
7126 // 3. If handler is null, throw a TypeError exception.
7127 // 4. Assert: Type(handler) is Object.
7128 if (proxy->IsRevoked()) {
7129 isolate->Throw(*isolate->factory()->NewTypeError(
7130 MessageTemplate::kProxyRevoked, trap_name));
7131 return Nothing<bool>();
7132 }
7133 // 5. Let target be the value of the [[ProxyTarget]] internal slot of O.
7134 Handle<JSReceiver> target(proxy->target(), isolate);
7135 // 6. Let trap be ? GetMethod(handler, "getOwnPropertyDescriptor").
7136 Handle<Object> trap;
7137 ASSIGN_RETURN_ON_EXCEPTION_VALUE(
7138 isolate, trap,
7139 Object::GetMethod(Handle<JSReceiver>::cast(handler), trap_name),
7140 Nothing<bool>());
7141 // 7. If trap is undefined, then
7142 if (trap->IsUndefined()) {
7143 // 7a. Return target.[[GetOwnProperty]](P).
7144 return JSReceiver::GetOwnPropertyDescriptor(isolate, target, name, desc);
7145 }
7146 // 8. Let trapResultObj be ? Call(trap, handler, «target, P»).
7147 Handle<Object> trap_result_obj;
7148 Handle<Object> args[] = {target, name};
7149 ASSIGN_RETURN_ON_EXCEPTION_VALUE(
7150 isolate, trap_result_obj,
7151 Execution::Call(isolate, trap, handler, arraysize(args), args),
7152 Nothing<bool>());
7153 // 9. If Type(trapResultObj) is neither Object nor Undefined, throw a
7154 // TypeError exception.
7155 if (!trap_result_obj->IsJSReceiver() && !trap_result_obj->IsUndefined()) {
7156 isolate->Throw(*isolate->factory()->NewTypeError(
7157 MessageTemplate::kProxyGetOwnPropertyDescriptorInvalid, name));
7158 return Nothing<bool>();
7159 }
7160 // 10. Let targetDesc be ? target.[[GetOwnProperty]](P).
7161 PropertyDescriptor target_desc;
7162 Maybe<bool> found =
7163 JSReceiver::GetOwnPropertyDescriptor(isolate, target, name, &target_desc);
7164 MAYBE_RETURN(found, Nothing<bool>());
7165 // 11. If trapResultObj is undefined, then
7166 if (trap_result_obj->IsUndefined()) {
7167 // 11a. If targetDesc is undefined, return undefined.
7168 if (!found.FromJust()) return Just(false);
7169 // 11b. If targetDesc.[[Configurable]] is false, throw a TypeError
7170 // exception.
7171 if (!target_desc.configurable()) {
7172 isolate->Throw(*isolate->factory()->NewTypeError(
7173 MessageTemplate::kProxyGetOwnPropertyDescriptorUndefined, name));
7174 return Nothing<bool>();
7175 }
7176 // 11c. Let extensibleTarget be ? IsExtensible(target).
7177 Maybe<bool> extensible_target = JSReceiver::IsExtensible(target);
7178 MAYBE_RETURN(extensible_target, Nothing<bool>());
7179 // 11d. (Assert)
7180 // 11e. If extensibleTarget is false, throw a TypeError exception.
7181 if (!extensible_target.FromJust()) {
7182 isolate->Throw(*isolate->factory()->NewTypeError(
7183 MessageTemplate::kProxyGetOwnPropertyDescriptorNonExtensible, name));
7184 return Nothing<bool>();
7185 }
7186 // 11f. Return undefined.
7187 return Just(false);
7188 }
7189 // 12. Let extensibleTarget be ? IsExtensible(target).
7190 Maybe<bool> extensible_target = JSReceiver::IsExtensible(target);
7191 MAYBE_RETURN(extensible_target, Nothing<bool>());
7192 // 13. Let resultDesc be ? ToPropertyDescriptor(trapResultObj).
7193 if (!PropertyDescriptor::ToPropertyDescriptor(isolate, trap_result_obj,
7194 desc)) {
7195 DCHECK(isolate->has_pending_exception());
7196 return Nothing<bool>();
7197 }
7198 // 14. Call CompletePropertyDescriptor(resultDesc).
7199 PropertyDescriptor::CompletePropertyDescriptor(isolate, desc);
7200 // 15. Let valid be IsCompatiblePropertyDescriptor (extensibleTarget,
7201 // resultDesc, targetDesc).
7202 Maybe<bool> valid =
7203 IsCompatiblePropertyDescriptor(isolate, extensible_target.FromJust(),
7204 desc, &target_desc, name, DONT_THROW);
7205 MAYBE_RETURN(valid, Nothing<bool>());
7206 // 16. If valid is false, throw a TypeError exception.
7207 if (!valid.FromJust()) {
7208 isolate->Throw(*isolate->factory()->NewTypeError(
7209 MessageTemplate::kProxyGetOwnPropertyDescriptorIncompatible, name));
7210 return Nothing<bool>();
7211 }
7212 // 17. If resultDesc.[[Configurable]] is false, then
7213 if (!desc->configurable()) {
7214 // 17a. If targetDesc is undefined or targetDesc.[[Configurable]] is true:
7215 if (target_desc.is_empty() || target_desc.configurable()) {
7216 // 17a i. Throw a TypeError exception.
7217 isolate->Throw(*isolate->factory()->NewTypeError(
7218 MessageTemplate::kProxyGetOwnPropertyDescriptorNonConfigurable,
7219 name));
7220 return Nothing<bool>();
7221 }
7222 }
7223 // 18. Return resultDesc.
7224 return Just(true);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01007225}
7226
7227
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00007228bool JSObject::ReferencesObjectFromElements(FixedArray* elements,
7229 ElementsKind kind,
7230 Object* object) {
Ben Murdoch097c5b22016-05-18 11:27:45 +01007231 if (IsFastObjectElementsKind(kind) || kind == FAST_STRING_WRAPPER_ELEMENTS) {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00007232 int length = IsJSArray()
7233 ? Smi::cast(JSArray::cast(this)->length())->value()
7234 : elements->length();
7235 for (int i = 0; i < length; ++i) {
7236 Object* element = elements->get(i);
7237 if (!element->IsTheHole() && element == object) return true;
7238 }
7239 } else {
Ben Murdoch097c5b22016-05-18 11:27:45 +01007240 DCHECK(kind == DICTIONARY_ELEMENTS || kind == SLOW_STRING_WRAPPER_ELEMENTS);
Ben Murdochc7cc0282012-03-05 14:35:55 +00007241 Object* key =
7242 SeededNumberDictionary::cast(elements)->SlowReverseLookup(object);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00007243 if (!key->IsUndefined()) return true;
7244 }
7245 return false;
7246}
7247
7248
Steve Blocka7e24c12009-10-30 11:49:00 +00007249// Check whether this object references another object.
7250bool JSObject::ReferencesObject(Object* obj) {
Ben Murdoch8b112d22011-06-08 16:22:53 +01007251 Map* map_of_this = map();
Ben Murdoch3ef787d2012-04-12 10:51:47 +01007252 Heap* heap = GetHeap();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007253 DisallowHeapAllocation no_allocation;
Steve Blocka7e24c12009-10-30 11:49:00 +00007254
7255 // Is the object the constructor for this object?
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00007256 if (map_of_this->GetConstructor() == obj) {
Steve Blocka7e24c12009-10-30 11:49:00 +00007257 return true;
7258 }
7259
7260 // Is the object the prototype for this object?
Ben Murdoch8b112d22011-06-08 16:22:53 +01007261 if (map_of_this->prototype() == obj) {
Steve Blocka7e24c12009-10-30 11:49:00 +00007262 return true;
7263 }
7264
7265 // Check if the object is among the named properties.
7266 Object* key = SlowReverseLookup(obj);
Steve Block44f0eee2011-05-26 01:26:41 +01007267 if (!key->IsUndefined()) {
Steve Blocka7e24c12009-10-30 11:49:00 +00007268 return true;
7269 }
7270
7271 // Check if the object is among the indexed properties.
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00007272 ElementsKind kind = GetElementsKind();
7273 switch (kind) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007274 // Raw pixels and external arrays do not reference other
7275 // objects.
7276#define TYPED_ARRAY_CASE(Type, type, TYPE, ctype, size) \
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007277 case TYPE##_ELEMENTS: \
Steve Blocka7e24c12009-10-30 11:49:00 +00007278 break;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007279
7280 TYPED_ARRAYS(TYPED_ARRAY_CASE)
7281#undef TYPED_ARRAY_CASE
7282
7283 case FAST_DOUBLE_ELEMENTS:
7284 case FAST_HOLEY_DOUBLE_ELEMENTS:
7285 break;
7286 case FAST_SMI_ELEMENTS:
7287 case FAST_HOLEY_SMI_ELEMENTS:
Ben Murdoch3ef787d2012-04-12 10:51:47 +01007288 break;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00007289 case FAST_ELEMENTS:
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007290 case FAST_HOLEY_ELEMENTS:
Ben Murdoch097c5b22016-05-18 11:27:45 +01007291 case DICTIONARY_ELEMENTS:
7292 case FAST_STRING_WRAPPER_ELEMENTS:
7293 case SLOW_STRING_WRAPPER_ELEMENTS: {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00007294 FixedArray* elements = FixedArray::cast(this->elements());
7295 if (ReferencesObjectFromElements(elements, kind, obj)) return true;
Steve Blocka7e24c12009-10-30 11:49:00 +00007296 break;
7297 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00007298 case FAST_SLOPPY_ARGUMENTS_ELEMENTS:
7299 case SLOW_SLOPPY_ARGUMENTS_ELEMENTS: {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00007300 FixedArray* parameter_map = FixedArray::cast(elements());
7301 // Check the mapped parameters.
7302 int length = parameter_map->length();
7303 for (int i = 2; i < length; ++i) {
7304 Object* value = parameter_map->get(i);
7305 if (!value->IsTheHole() && value == obj) return true;
7306 }
7307 // Check the arguments.
7308 FixedArray* arguments = FixedArray::cast(parameter_map->get(1));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007309 kind = arguments->IsDictionary() ? DICTIONARY_ELEMENTS :
7310 FAST_HOLEY_ELEMENTS;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00007311 if (ReferencesObjectFromElements(arguments, kind, obj)) return true;
Steve Blocka7e24c12009-10-30 11:49:00 +00007312 break;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00007313 }
Ben Murdoch097c5b22016-05-18 11:27:45 +01007314 case NO_ELEMENTS:
7315 break;
Steve Blocka7e24c12009-10-30 11:49:00 +00007316 }
7317
Steve Block6ded16b2010-05-10 14:33:55 +01007318 // For functions check the context.
7319 if (IsJSFunction()) {
Steve Blocka7e24c12009-10-30 11:49:00 +00007320 // Get the constructor function for arguments array.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007321 Map* arguments_map =
7322 heap->isolate()->context()->native_context()->sloppy_arguments_map();
Steve Blocka7e24c12009-10-30 11:49:00 +00007323 JSFunction* arguments_function =
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00007324 JSFunction::cast(arguments_map->GetConstructor());
Steve Blocka7e24c12009-10-30 11:49:00 +00007325
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007326 // Get the context and don't check if it is the native context.
Steve Blocka7e24c12009-10-30 11:49:00 +00007327 JSFunction* f = JSFunction::cast(this);
7328 Context* context = f->context();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007329 if (context->IsNativeContext()) {
Steve Blocka7e24c12009-10-30 11:49:00 +00007330 return false;
7331 }
7332
7333 // Check the non-special context slots.
7334 for (int i = Context::MIN_CONTEXT_SLOTS; i < context->length(); i++) {
7335 // Only check JS objects.
7336 if (context->get(i)->IsJSObject()) {
7337 JSObject* ctxobj = JSObject::cast(context->get(i));
7338 // If it is an arguments array check the content.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00007339 if (ctxobj->map()->GetConstructor() == arguments_function) {
Steve Blocka7e24c12009-10-30 11:49:00 +00007340 if (ctxobj->ReferencesObject(obj)) {
7341 return true;
7342 }
7343 } else if (ctxobj == obj) {
7344 return true;
7345 }
7346 }
7347 }
7348
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00007349 // Check the context extension (if any) if it can have references.
7350 if (context->has_extension() && !context->IsCatchContext()) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00007351 // With harmony scoping, a JSFunction may have a script context.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007352 // TODO(mvstanton): walk into the ScopeInfo.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00007353 if (context->IsScriptContext()) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007354 return false;
7355 }
7356
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00007357 return context->extension_object()->ReferencesObject(obj);
Steve Blocka7e24c12009-10-30 11:49:00 +00007358 }
7359 }
7360
7361 // No references to object.
7362 return false;
7363}
7364
7365
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00007366Maybe<bool> JSReceiver::SetIntegrityLevel(Handle<JSReceiver> receiver,
7367 IntegrityLevel level,
7368 ShouldThrow should_throw) {
7369 DCHECK(level == SEALED || level == FROZEN);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01007370
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00007371 if (receiver->IsJSObject()) {
7372 Handle<JSObject> object = Handle<JSObject>::cast(receiver);
Ben Murdochc5610432016-08-08 18:44:38 +01007373 if (!object->HasSloppyArgumentsElements()) { // Fast path.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00007374 if (level == SEALED) {
7375 return JSObject::PreventExtensionsWithTransition<SEALED>(object,
7376 should_throw);
7377 } else {
7378 return JSObject::PreventExtensionsWithTransition<FROZEN>(object,
7379 should_throw);
7380 }
7381 }
Emily Bernierd0a1eb72015-03-24 16:35:39 -04007382 }
7383
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00007384 Isolate* isolate = receiver->GetIsolate();
7385
7386 MAYBE_RETURN(JSReceiver::PreventExtensions(receiver, should_throw),
7387 Nothing<bool>());
7388
7389 Handle<FixedArray> keys;
7390 ASSIGN_RETURN_ON_EXCEPTION_VALUE(
7391 isolate, keys, JSReceiver::OwnPropertyKeys(receiver), Nothing<bool>());
7392
7393 PropertyDescriptor no_conf;
7394 no_conf.set_configurable(false);
7395
7396 PropertyDescriptor no_conf_no_write;
7397 no_conf_no_write.set_configurable(false);
7398 no_conf_no_write.set_writable(false);
7399
7400 if (level == SEALED) {
7401 for (int i = 0; i < keys->length(); ++i) {
7402 Handle<Object> key(keys->get(i), isolate);
7403 MAYBE_RETURN(
7404 DefineOwnProperty(isolate, receiver, key, &no_conf, THROW_ON_ERROR),
7405 Nothing<bool>());
7406 }
7407 return Just(true);
7408 }
7409
7410 for (int i = 0; i < keys->length(); ++i) {
7411 Handle<Object> key(keys->get(i), isolate);
7412 PropertyDescriptor current_desc;
7413 Maybe<bool> owned = JSReceiver::GetOwnPropertyDescriptor(
7414 isolate, receiver, key, &current_desc);
7415 MAYBE_RETURN(owned, Nothing<bool>());
7416 if (owned.FromJust()) {
7417 PropertyDescriptor desc =
7418 PropertyDescriptor::IsAccessorDescriptor(&current_desc)
7419 ? no_conf
7420 : no_conf_no_write;
7421 MAYBE_RETURN(
7422 DefineOwnProperty(isolate, receiver, key, &desc, THROW_ON_ERROR),
7423 Nothing<bool>());
7424 }
7425 }
7426 return Just(true);
7427}
7428
7429
7430Maybe<bool> JSReceiver::TestIntegrityLevel(Handle<JSReceiver> object,
7431 IntegrityLevel level) {
7432 DCHECK(level == SEALED || level == FROZEN);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04007433 Isolate* isolate = object->GetIsolate();
7434
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00007435 Maybe<bool> extensible = JSReceiver::IsExtensible(object);
7436 MAYBE_RETURN(extensible, Nothing<bool>());
7437 if (extensible.FromJust()) return Just(false);
7438
7439 Handle<FixedArray> keys;
7440 ASSIGN_RETURN_ON_EXCEPTION_VALUE(
7441 isolate, keys, JSReceiver::OwnPropertyKeys(object), Nothing<bool>());
7442
7443 for (int i = 0; i < keys->length(); ++i) {
7444 Handle<Object> key(keys->get(i), isolate);
7445 PropertyDescriptor current_desc;
7446 Maybe<bool> owned = JSReceiver::GetOwnPropertyDescriptor(
7447 isolate, object, key, &current_desc);
7448 MAYBE_RETURN(owned, Nothing<bool>());
7449 if (owned.FromJust()) {
7450 if (current_desc.configurable()) return Just(false);
7451 if (level == FROZEN &&
7452 PropertyDescriptor::IsDataDescriptor(&current_desc) &&
7453 current_desc.writable()) {
7454 return Just(false);
7455 }
7456 }
Ben Murdoche0cee9b2011-05-25 10:26:03 +01007457 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00007458 return Just(true);
7459}
7460
7461
7462Maybe<bool> JSReceiver::PreventExtensions(Handle<JSReceiver> object,
7463 ShouldThrow should_throw) {
7464 if (object->IsJSProxy()) {
7465 return JSProxy::PreventExtensions(Handle<JSProxy>::cast(object),
7466 should_throw);
7467 }
7468 DCHECK(object->IsJSObject());
7469 return JSObject::PreventExtensions(Handle<JSObject>::cast(object),
7470 should_throw);
7471}
7472
7473
7474Maybe<bool> JSProxy::PreventExtensions(Handle<JSProxy> proxy,
7475 ShouldThrow should_throw) {
7476 Isolate* isolate = proxy->GetIsolate();
Ben Murdochc5610432016-08-08 18:44:38 +01007477 STACK_CHECK(isolate, Nothing<bool>());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00007478 Factory* factory = isolate->factory();
7479 Handle<String> trap_name = factory->preventExtensions_string();
7480
7481 if (proxy->IsRevoked()) {
7482 isolate->Throw(
7483 *factory->NewTypeError(MessageTemplate::kProxyRevoked, trap_name));
7484 return Nothing<bool>();
7485 }
7486 Handle<JSReceiver> target(proxy->target(), isolate);
7487 Handle<JSReceiver> handler(JSReceiver::cast(proxy->handler()), isolate);
7488
7489 Handle<Object> trap;
7490 ASSIGN_RETURN_ON_EXCEPTION_VALUE(
7491 isolate, trap, Object::GetMethod(handler, trap_name), Nothing<bool>());
7492 if (trap->IsUndefined()) {
7493 return JSReceiver::PreventExtensions(target, should_throw);
7494 }
7495
7496 Handle<Object> trap_result;
7497 Handle<Object> args[] = {target};
7498 ASSIGN_RETURN_ON_EXCEPTION_VALUE(
7499 isolate, trap_result,
7500 Execution::Call(isolate, trap, handler, arraysize(args), args),
7501 Nothing<bool>());
7502 if (!trap_result->BooleanValue()) {
7503 RETURN_FAILURE(
7504 isolate, should_throw,
7505 NewTypeError(MessageTemplate::kProxyTrapReturnedFalsish, trap_name));
7506 }
7507
7508 // Enforce the invariant.
7509 Maybe<bool> target_result = JSReceiver::IsExtensible(target);
7510 MAYBE_RETURN(target_result, Nothing<bool>());
7511 if (target_result.FromJust()) {
7512 isolate->Throw(*factory->NewTypeError(
7513 MessageTemplate::kProxyPreventExtensionsExtensible));
7514 return Nothing<bool>();
7515 }
7516 return Just(true);
7517}
7518
7519
7520Maybe<bool> JSObject::PreventExtensions(Handle<JSObject> object,
7521 ShouldThrow should_throw) {
7522 Isolate* isolate = object->GetIsolate();
7523
Ben Murdochc5610432016-08-08 18:44:38 +01007524 if (!object->HasSloppyArgumentsElements()) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00007525 return PreventExtensionsWithTransition<NONE>(object, should_throw);
7526 }
7527
7528 if (object->IsAccessCheckNeeded() &&
7529 !isolate->MayAccess(handle(isolate->context()), object)) {
7530 isolate->ReportFailedAccessCheck(object);
7531 RETURN_VALUE_IF_SCHEDULED_EXCEPTION(isolate, Nothing<bool>());
7532 RETURN_FAILURE(isolate, should_throw,
7533 NewTypeError(MessageTemplate::kNoAccess));
7534 }
7535
7536 if (!object->map()->is_extensible()) return Just(true);
Ben Murdoche0cee9b2011-05-25 10:26:03 +01007537
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007538 if (object->IsJSGlobalProxy()) {
7539 PrototypeIterator iter(isolate, object);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00007540 if (iter.IsAtEnd()) return Just(true);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007541 DCHECK(PrototypeIterator::GetCurrent(iter)->IsJSGlobalObject());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00007542 return PreventExtensions(PrototypeIterator::GetCurrent<JSObject>(iter),
7543 should_throw);
Steve Block1e0659c2011-05-24 12:43:12 +01007544 }
7545
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00007546 if (!object->HasFixedTypedArrayElements()) {
7547 // If there are fast elements we normalize.
7548 Handle<SeededNumberDictionary> dictionary = NormalizeElements(object);
7549 DCHECK(object->HasDictionaryElements() ||
7550 object->HasSlowArgumentsElements());
7551
7552 // Make sure that we never go back to fast case.
7553 object->RequireSlowElements(*dictionary);
Ben Murdoch257744e2011-11-30 15:57:28 +00007554 }
7555
Steve Block8defd9f2010-07-08 12:39:36 +01007556 // Do a map transition, other objects with this map may still
7557 // be extensible.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007558 // TODO(adamk): Extend the NormalizedMapCache to handle non-extensible maps.
Emily Bernierd0a1eb72015-03-24 16:35:39 -04007559 Handle<Map> new_map = Map::Copy(handle(object->map()), "PreventExtensions");
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007560
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00007561 new_map->set_is_extensible(false);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007562 JSObject::MigrateToMap(object, new_map);
7563 DCHECK(!object->map()->is_extensible());
7564
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00007565 return Just(true);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007566}
7567
7568
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00007569Maybe<bool> JSReceiver::IsExtensible(Handle<JSReceiver> object) {
7570 if (object->IsJSProxy()) {
7571 return JSProxy::IsExtensible(Handle<JSProxy>::cast(object));
Emily Bernierd0a1eb72015-03-24 16:35:39 -04007572 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00007573 return Just(JSObject::IsExtensible(Handle<JSObject>::cast(object)));
7574}
7575
7576
7577Maybe<bool> JSProxy::IsExtensible(Handle<JSProxy> proxy) {
7578 Isolate* isolate = proxy->GetIsolate();
Ben Murdochc5610432016-08-08 18:44:38 +01007579 STACK_CHECK(isolate, Nothing<bool>());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00007580 Factory* factory = isolate->factory();
7581 Handle<String> trap_name = factory->isExtensible_string();
7582
7583 if (proxy->IsRevoked()) {
7584 isolate->Throw(
7585 *factory->NewTypeError(MessageTemplate::kProxyRevoked, trap_name));
7586 return Nothing<bool>();
7587 }
7588 Handle<JSReceiver> target(proxy->target(), isolate);
7589 Handle<JSReceiver> handler(JSReceiver::cast(proxy->handler()), isolate);
7590
7591 Handle<Object> trap;
7592 ASSIGN_RETURN_ON_EXCEPTION_VALUE(
7593 isolate, trap, Object::GetMethod(handler, trap_name), Nothing<bool>());
7594 if (trap->IsUndefined()) {
7595 return JSReceiver::IsExtensible(target);
7596 }
7597
7598 Handle<Object> trap_result;
7599 Handle<Object> args[] = {target};
7600 ASSIGN_RETURN_ON_EXCEPTION_VALUE(
7601 isolate, trap_result,
7602 Execution::Call(isolate, trap, handler, arraysize(args), args),
7603 Nothing<bool>());
7604
7605 // Enforce the invariant.
7606 Maybe<bool> target_result = JSReceiver::IsExtensible(target);
7607 MAYBE_RETURN(target_result, Nothing<bool>());
7608 if (target_result.FromJust() != trap_result->BooleanValue()) {
7609 isolate->Throw(
7610 *factory->NewTypeError(MessageTemplate::kProxyIsExtensibleInconsistent,
7611 factory->ToBoolean(target_result.FromJust())));
7612 return Nothing<bool>();
7613 }
7614 return target_result;
7615}
7616
7617
7618bool JSObject::IsExtensible(Handle<JSObject> object) {
7619 Isolate* isolate = object->GetIsolate();
7620 if (object->IsAccessCheckNeeded() &&
7621 !isolate->MayAccess(handle(isolate->context()), object)) {
7622 return true;
7623 }
7624 if (object->IsJSGlobalProxy()) {
7625 PrototypeIterator iter(isolate, *object);
7626 if (iter.IsAtEnd()) return false;
7627 DCHECK(iter.GetCurrent()->IsJSGlobalObject());
7628 return iter.GetCurrent<JSObject>()->map()->is_extensible();
7629 }
7630 return object->map()->is_extensible();
Emily Bernierd0a1eb72015-03-24 16:35:39 -04007631}
7632
7633
7634template <typename Dictionary>
7635static void ApplyAttributesToDictionary(Dictionary* dictionary,
7636 const PropertyAttributes attributes) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007637 int capacity = dictionary->Capacity();
7638 for (int i = 0; i < capacity; i++) {
7639 Object* k = dictionary->KeyAt(i);
7640 if (dictionary->IsKey(k) &&
7641 !(k->IsSymbol() && Symbol::cast(k)->is_private())) {
7642 PropertyDetails details = dictionary->DetailsAt(i);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04007643 int attrs = attributes;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007644 // READ_ONLY is an invalid attribute for JS setters/getters.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00007645 if ((attributes & READ_ONLY) && details.type() == ACCESSOR_CONSTANT) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007646 Object* v = dictionary->ValueAt(i);
7647 if (v->IsPropertyCell()) v = PropertyCell::cast(v)->value();
Emily Bernierd0a1eb72015-03-24 16:35:39 -04007648 if (v->IsAccessorPair()) attrs &= ~READ_ONLY;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007649 }
7650 details = details.CopyAddAttributes(
7651 static_cast<PropertyAttributes>(attrs));
7652 dictionary->DetailsAtPut(i, details);
7653 }
7654 }
7655}
7656
7657
Emily Bernierd0a1eb72015-03-24 16:35:39 -04007658template <PropertyAttributes attrs>
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00007659Maybe<bool> JSObject::PreventExtensionsWithTransition(
7660 Handle<JSObject> object, ShouldThrow should_throw) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -04007661 STATIC_ASSERT(attrs == NONE || attrs == SEALED || attrs == FROZEN);
7662
7663 // Sealing/freezing sloppy arguments should be handled elsewhere.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007664 DCHECK(!object->HasSloppyArgumentsElements());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007665
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007666 Isolate* isolate = object->GetIsolate();
7667 if (object->IsAccessCheckNeeded() &&
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00007668 !isolate->MayAccess(handle(isolate->context()), object)) {
7669 isolate->ReportFailedAccessCheck(object);
7670 RETURN_VALUE_IF_SCHEDULED_EXCEPTION(isolate, Nothing<bool>());
7671 RETURN_FAILURE(isolate, should_throw,
7672 NewTypeError(MessageTemplate::kNoAccess));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007673 }
7674
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00007675 if (attrs == NONE && !object->map()->is_extensible()) return Just(true);
7676
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007677 if (object->IsJSGlobalProxy()) {
7678 PrototypeIterator iter(isolate, object);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00007679 if (iter.IsAtEnd()) return Just(true);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007680 DCHECK(PrototypeIterator::GetCurrent(iter)->IsJSGlobalObject());
Emily Bernierd0a1eb72015-03-24 16:35:39 -04007681 return PreventExtensionsWithTransition<attrs>(
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00007682 PrototypeIterator::GetCurrent<JSObject>(iter), should_throw);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007683 }
7684
7685 Handle<SeededNumberDictionary> new_element_dictionary;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00007686 if (!object->HasFixedTypedArrayElements() &&
Ben Murdoch097c5b22016-05-18 11:27:45 +01007687 !object->HasDictionaryElements() &&
7688 !object->HasSlowStringWrapperElements()) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00007689 int length =
7690 object->IsJSArray()
7691 ? Smi::cast(Handle<JSArray>::cast(object)->length())->value()
7692 : object->elements()->length();
7693 new_element_dictionary =
7694 length == 0 ? isolate->factory()->empty_slow_element_dictionary()
Ben Murdochda12d292016-06-02 14:46:10 +01007695 : object->GetElementsAccessor()->Normalize(object);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04007696 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007697
Emily Bernierd0a1eb72015-03-24 16:35:39 -04007698 Handle<Symbol> transition_marker;
7699 if (attrs == NONE) {
7700 transition_marker = isolate->factory()->nonextensible_symbol();
7701 } else if (attrs == SEALED) {
7702 transition_marker = isolate->factory()->sealed_symbol();
7703 } else {
7704 DCHECK(attrs == FROZEN);
7705 transition_marker = isolate->factory()->frozen_symbol();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007706 }
7707
7708 Handle<Map> old_map(object->map(), isolate);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00007709 Map* transition =
7710 TransitionArray::SearchSpecial(*old_map, *transition_marker);
7711 if (transition != NULL) {
7712 Handle<Map> transition_map(transition, isolate);
7713 DCHECK(transition_map->has_dictionary_elements() ||
Ben Murdoch097c5b22016-05-18 11:27:45 +01007714 transition_map->has_fixed_typed_array_elements() ||
7715 transition_map->elements_kind() == SLOW_STRING_WRAPPER_ELEMENTS);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007716 DCHECK(!transition_map->is_extensible());
7717 JSObject::MigrateToMap(object, transition_map);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00007718 } else if (TransitionArray::CanHaveMoreTransitions(old_map)) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -04007719 // Create a new descriptor array with the appropriate property attributes
7720 Handle<Map> new_map = Map::CopyForPreventExtensions(
7721 old_map, attrs, transition_marker, "CopyForPreventExtensions");
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007722 JSObject::MigrateToMap(object, new_map);
7723 } else {
7724 DCHECK(old_map->is_dictionary_map() || !old_map->is_prototype_map());
7725 // Slow path: need to normalize properties for safety
Emily Bernierd0a1eb72015-03-24 16:35:39 -04007726 NormalizeProperties(object, CLEAR_INOBJECT_PROPERTIES, 0,
7727 "SlowPreventExtensions");
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007728
7729 // Create a new map, since other objects with this map may be extensible.
7730 // TODO(adamk): Extend the NormalizedMapCache to handle non-extensible maps.
Emily Bernierd0a1eb72015-03-24 16:35:39 -04007731 Handle<Map> new_map =
7732 Map::Copy(handle(object->map()), "SlowCopyForPreventExtensions");
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007733 new_map->set_is_extensible(false);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00007734 if (!new_element_dictionary.is_null()) {
Ben Murdoch097c5b22016-05-18 11:27:45 +01007735 ElementsKind new_kind =
7736 IsStringWrapperElementsKind(old_map->elements_kind())
7737 ? SLOW_STRING_WRAPPER_ELEMENTS
7738 : DICTIONARY_ELEMENTS;
7739 new_map->set_elements_kind(new_kind);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00007740 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007741 JSObject::MigrateToMap(object, new_map);
7742
Emily Bernierd0a1eb72015-03-24 16:35:39 -04007743 if (attrs != NONE) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00007744 if (object->IsJSGlobalObject()) {
7745 ApplyAttributesToDictionary(object->global_dictionary(), attrs);
7746 } else {
7747 ApplyAttributesToDictionary(object->property_dictionary(), attrs);
7748 }
Emily Bernierd0a1eb72015-03-24 16:35:39 -04007749 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007750 }
7751
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00007752 // Both seal and preventExtensions always go through without modifications to
7753 // typed array elements. Freeze works only if there are no actual elements.
7754 if (object->HasFixedTypedArrayElements()) {
7755 if (attrs == FROZEN &&
7756 JSArrayBufferView::cast(*object)->byte_length()->Number() > 0) {
7757 isolate->Throw(*isolate->factory()->NewTypeError(
7758 MessageTemplate::kCannotFreezeArrayBufferView));
7759 return Nothing<bool>();
7760 }
7761 return Just(true);
7762 }
7763
Ben Murdoch097c5b22016-05-18 11:27:45 +01007764 DCHECK(object->map()->has_dictionary_elements() ||
7765 object->map()->elements_kind() == SLOW_STRING_WRAPPER_ELEMENTS);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007766 if (!new_element_dictionary.is_null()) {
7767 object->set_elements(*new_element_dictionary);
7768 }
7769
7770 if (object->elements() != isolate->heap()->empty_slow_element_dictionary()) {
7771 SeededNumberDictionary* dictionary = object->element_dictionary();
7772 // Make sure we never go back to the fast case
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00007773 object->RequireSlowElements(dictionary);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04007774 if (attrs != NONE) {
7775 ApplyAttributesToDictionary(dictionary, attrs);
7776 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007777 }
7778
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00007779 return Just(true);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04007780}
7781
7782
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007783Handle<Object> JSObject::FastPropertyAt(Handle<JSObject> object,
7784 Representation representation,
7785 FieldIndex index) {
7786 Isolate* isolate = object->GetIsolate();
Emily Bernierd0a1eb72015-03-24 16:35:39 -04007787 if (object->IsUnboxedDoubleField(index)) {
7788 double value = object->RawFastDoublePropertyAt(index);
7789 return isolate->factory()->NewHeapNumber(value);
7790 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007791 Handle<Object> raw_value(object->RawFastPropertyAt(index), isolate);
7792 return Object::WrapForRead(isolate, raw_value, representation);
7793}
7794
Ben Murdochda12d292016-06-02 14:46:10 +01007795template <class ContextObject>
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007796class JSObjectWalkVisitor {
7797 public:
7798 JSObjectWalkVisitor(ContextObject* site_context, bool copying,
7799 JSObject::DeepCopyHints hints)
7800 : site_context_(site_context),
7801 copying_(copying),
7802 hints_(hints) {}
7803
7804 MUST_USE_RESULT MaybeHandle<JSObject> StructureWalk(Handle<JSObject> object);
7805
7806 protected:
7807 MUST_USE_RESULT inline MaybeHandle<JSObject> VisitElementOrProperty(
7808 Handle<JSObject> object,
7809 Handle<JSObject> value) {
7810 Handle<AllocationSite> current_site = site_context()->EnterNewScope();
7811 MaybeHandle<JSObject> copy_of_value = StructureWalk(value);
7812 site_context()->ExitScope(current_site, value);
7813 return copy_of_value;
7814 }
7815
7816 inline ContextObject* site_context() { return site_context_; }
7817 inline Isolate* isolate() { return site_context()->isolate(); }
7818
7819 inline bool copying() const { return copying_; }
7820
7821 private:
7822 ContextObject* site_context_;
7823 const bool copying_;
7824 const JSObject::DeepCopyHints hints_;
7825};
7826
Ben Murdochda12d292016-06-02 14:46:10 +01007827template <class ContextObject>
7828MaybeHandle<JSObject> JSObjectWalkVisitor<ContextObject>::StructureWalk(
7829 Handle<JSObject> object) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007830 Isolate* isolate = this->isolate();
7831 bool copying = this->copying();
7832 bool shallow = hints_ == JSObject::kObjectIsShallow;
7833
7834 if (!shallow) {
7835 StackLimitCheck check(isolate);
7836
7837 if (check.HasOverflowed()) {
7838 isolate->StackOverflow();
7839 return MaybeHandle<JSObject>();
7840 }
7841 }
7842
7843 if (object->map()->is_deprecated()) {
7844 JSObject::MigrateInstance(object);
7845 }
7846
7847 Handle<JSObject> copy;
7848 if (copying) {
Ben Murdochda12d292016-06-02 14:46:10 +01007849 // JSFunction objects are not allowed to be in normal boilerplates at all.
7850 DCHECK(!object->IsJSFunction());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007851 Handle<AllocationSite> site_to_pass;
7852 if (site_context()->ShouldCreateMemento(object)) {
7853 site_to_pass = site_context()->current();
7854 }
7855 copy = isolate->factory()->CopyJSObjectWithAllocationSite(
7856 object, site_to_pass);
7857 } else {
7858 copy = object;
7859 }
7860
7861 DCHECK(copying || copy.is_identical_to(object));
7862
7863 ElementsKind kind = copy->GetElementsKind();
7864 if (copying && IsFastSmiOrObjectElementsKind(kind) &&
7865 FixedArray::cast(copy->elements())->map() ==
7866 isolate->heap()->fixed_cow_array_map()) {
7867 isolate->counters()->cow_arrays_created_runtime()->Increment();
7868 }
7869
7870 if (!shallow) {
7871 HandleScope scope(isolate);
7872
7873 // Deep copy own properties.
7874 if (copy->HasFastProperties()) {
7875 Handle<DescriptorArray> descriptors(copy->map()->instance_descriptors());
7876 int limit = copy->map()->NumberOfOwnDescriptors();
7877 for (int i = 0; i < limit; i++) {
7878 PropertyDetails details = descriptors->GetDetails(i);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00007879 if (details.type() != DATA) continue;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007880 FieldIndex index = FieldIndex::ForDescriptor(copy->map(), i);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04007881 if (object->IsUnboxedDoubleField(index)) {
7882 if (copying) {
7883 double value = object->RawFastDoublePropertyAt(index);
7884 copy->RawFastDoublePropertyAtPut(index, value);
7885 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007886 } else {
Emily Bernierd0a1eb72015-03-24 16:35:39 -04007887 Handle<Object> value(object->RawFastPropertyAt(index), isolate);
7888 if (value->IsJSObject()) {
7889 ASSIGN_RETURN_ON_EXCEPTION(
7890 isolate, value,
7891 VisitElementOrProperty(copy, Handle<JSObject>::cast(value)),
7892 JSObject);
7893 if (copying) {
7894 copy->FastPropertyAtPut(index, *value);
7895 }
7896 } else {
7897 if (copying) {
7898 Representation representation = details.representation();
7899 value = Object::NewStorageFor(isolate, value, representation);
7900 copy->FastPropertyAtPut(index, *value);
7901 }
7902 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007903 }
7904 }
7905 } else {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00007906 // Only deep copy fields from the object literal expression.
7907 // In particular, don't try to copy the length attribute of
7908 // an array.
7909 PropertyFilter filter = static_cast<PropertyFilter>(
7910 ONLY_WRITABLE | ONLY_ENUMERABLE | ONLY_CONFIGURABLE);
Ben Murdoch097c5b22016-05-18 11:27:45 +01007911 KeyAccumulator accumulator(isolate, OWN_ONLY, filter);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00007912 accumulator.NextPrototype();
Ben Murdochc5610432016-08-08 18:44:38 +01007913 accumulator.CollectOwnPropertyNames(copy);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00007914 Handle<FixedArray> names = accumulator.GetKeys();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007915 for (int i = 0; i < names->length(); i++) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00007916 DCHECK(names->get(i)->IsName());
7917 Handle<Name> name(Name::cast(names->get(i)));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007918 Handle<Object> value =
Ben Murdochda12d292016-06-02 14:46:10 +01007919 JSObject::GetProperty(copy, name).ToHandleChecked();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007920 if (value->IsJSObject()) {
7921 Handle<JSObject> result;
7922 ASSIGN_RETURN_ON_EXCEPTION(
7923 isolate, result,
7924 VisitElementOrProperty(copy, Handle<JSObject>::cast(value)),
7925 JSObject);
7926 if (copying) {
7927 // Creating object copy for literals. No strict mode needed.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00007928 JSObject::SetProperty(copy, name, result, SLOPPY).Assert();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007929 }
7930 }
7931 }
7932 }
7933
7934 // Deep copy own elements.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007935 switch (kind) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007936 case FAST_ELEMENTS:
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007937 case FAST_HOLEY_ELEMENTS: {
7938 Handle<FixedArray> elements(FixedArray::cast(copy->elements()));
7939 if (elements->map() == isolate->heap()->fixed_cow_array_map()) {
7940#ifdef DEBUG
7941 for (int i = 0; i < elements->length(); i++) {
7942 DCHECK(!elements->get(i)->IsJSObject());
7943 }
7944#endif
7945 } else {
7946 for (int i = 0; i < elements->length(); i++) {
7947 Handle<Object> value(elements->get(i), isolate);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007948 if (value->IsJSObject()) {
7949 Handle<JSObject> result;
7950 ASSIGN_RETURN_ON_EXCEPTION(
7951 isolate, result,
7952 VisitElementOrProperty(copy, Handle<JSObject>::cast(value)),
7953 JSObject);
7954 if (copying) {
7955 elements->set(i, *result);
7956 }
7957 }
7958 }
7959 }
7960 break;
7961 }
7962 case DICTIONARY_ELEMENTS: {
7963 Handle<SeededNumberDictionary> element_dictionary(
7964 copy->element_dictionary());
7965 int capacity = element_dictionary->Capacity();
7966 for (int i = 0; i < capacity; i++) {
7967 Object* k = element_dictionary->KeyAt(i);
7968 if (element_dictionary->IsKey(k)) {
7969 Handle<Object> value(element_dictionary->ValueAt(i), isolate);
7970 if (value->IsJSObject()) {
7971 Handle<JSObject> result;
7972 ASSIGN_RETURN_ON_EXCEPTION(
7973 isolate, result,
7974 VisitElementOrProperty(copy, Handle<JSObject>::cast(value)),
7975 JSObject);
7976 if (copying) {
7977 element_dictionary->ValueAtPut(i, *result);
7978 }
7979 }
7980 }
7981 }
7982 break;
7983 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00007984 case FAST_SLOPPY_ARGUMENTS_ELEMENTS:
7985 case SLOW_SLOPPY_ARGUMENTS_ELEMENTS:
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007986 UNIMPLEMENTED();
7987 break;
Ben Murdoch097c5b22016-05-18 11:27:45 +01007988 case FAST_STRING_WRAPPER_ELEMENTS:
7989 case SLOW_STRING_WRAPPER_ELEMENTS:
7990 UNREACHABLE();
7991 break;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007992
7993#define TYPED_ARRAY_CASE(Type, type, TYPE, ctype, size) \
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007994 case TYPE##_ELEMENTS: \
7995
7996 TYPED_ARRAYS(TYPED_ARRAY_CASE)
7997#undef TYPED_ARRAY_CASE
Ben Murdoch097c5b22016-05-18 11:27:45 +01007998 // Typed elements cannot be created using an object literal.
7999 UNREACHABLE();
8000 break;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00008001
Ben Murdoch097c5b22016-05-18 11:27:45 +01008002 case FAST_SMI_ELEMENTS:
8003 case FAST_HOLEY_SMI_ELEMENTS:
Ben Murdochb8a8cc12014-11-26 15:28:44 +00008004 case FAST_DOUBLE_ELEMENTS:
8005 case FAST_HOLEY_DOUBLE_ELEMENTS:
Ben Murdoch097c5b22016-05-18 11:27:45 +01008006 case NO_ELEMENTS:
Ben Murdochb8a8cc12014-11-26 15:28:44 +00008007 // No contained objects, nothing to do.
8008 break;
8009 }
8010 }
8011
8012 return copy;
8013}
8014
8015
8016MaybeHandle<JSObject> JSObject::DeepWalk(
8017 Handle<JSObject> object,
8018 AllocationSiteCreationContext* site_context) {
Ben Murdochda12d292016-06-02 14:46:10 +01008019 JSObjectWalkVisitor<AllocationSiteCreationContext> v(site_context, false,
8020 kNoHints);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00008021 MaybeHandle<JSObject> result = v.StructureWalk(object);
8022 Handle<JSObject> for_assert;
8023 DCHECK(!result.ToHandle(&for_assert) || for_assert.is_identical_to(object));
8024 return result;
8025}
8026
8027
8028MaybeHandle<JSObject> JSObject::DeepCopy(
8029 Handle<JSObject> object,
8030 AllocationSiteUsageContext* site_context,
8031 DeepCopyHints hints) {
Ben Murdochda12d292016-06-02 14:46:10 +01008032 JSObjectWalkVisitor<AllocationSiteUsageContext> v(site_context, true, hints);
Ben Murdoch097c5b22016-05-18 11:27:45 +01008033 MaybeHandle<JSObject> copy = v.StructureWalk(object);
8034 Handle<JSObject> for_assert;
8035 DCHECK(!copy.ToHandle(&for_assert) || !for_assert.is_identical_to(object));
8036 return copy;
8037}
Steve Block8defd9f2010-07-08 12:39:36 +01008038
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00008039// static
8040MaybeHandle<Object> JSReceiver::ToPrimitive(Handle<JSReceiver> receiver,
8041 ToPrimitiveHint hint) {
8042 Isolate* const isolate = receiver->GetIsolate();
8043 Handle<Object> exotic_to_prim;
8044 ASSIGN_RETURN_ON_EXCEPTION(
8045 isolate, exotic_to_prim,
8046 GetMethod(receiver, isolate->factory()->to_primitive_symbol()), Object);
8047 if (!exotic_to_prim->IsUndefined()) {
8048 Handle<Object> hint_string;
8049 switch (hint) {
8050 case ToPrimitiveHint::kDefault:
8051 hint_string = isolate->factory()->default_string();
8052 break;
8053 case ToPrimitiveHint::kNumber:
8054 hint_string = isolate->factory()->number_string();
8055 break;
8056 case ToPrimitiveHint::kString:
8057 hint_string = isolate->factory()->string_string();
8058 break;
8059 }
8060 Handle<Object> result;
8061 ASSIGN_RETURN_ON_EXCEPTION(
8062 isolate, result,
8063 Execution::Call(isolate, exotic_to_prim, receiver, 1, &hint_string),
8064 Object);
8065 if (result->IsPrimitive()) return result;
8066 THROW_NEW_ERROR(isolate,
8067 NewTypeError(MessageTemplate::kCannotConvertToPrimitive),
8068 Object);
8069 }
8070 return OrdinaryToPrimitive(receiver, (hint == ToPrimitiveHint::kString)
8071 ? OrdinaryToPrimitiveHint::kString
8072 : OrdinaryToPrimitiveHint::kNumber);
8073}
8074
8075
8076// static
8077MaybeHandle<Object> JSReceiver::OrdinaryToPrimitive(
8078 Handle<JSReceiver> receiver, OrdinaryToPrimitiveHint hint) {
8079 Isolate* const isolate = receiver->GetIsolate();
8080 Handle<String> method_names[2];
8081 switch (hint) {
8082 case OrdinaryToPrimitiveHint::kNumber:
8083 method_names[0] = isolate->factory()->valueOf_string();
8084 method_names[1] = isolate->factory()->toString_string();
8085 break;
8086 case OrdinaryToPrimitiveHint::kString:
8087 method_names[0] = isolate->factory()->toString_string();
8088 method_names[1] = isolate->factory()->valueOf_string();
8089 break;
8090 }
8091 for (Handle<String> name : method_names) {
8092 Handle<Object> method;
8093 ASSIGN_RETURN_ON_EXCEPTION(isolate, method,
8094 JSReceiver::GetProperty(receiver, name), Object);
8095 if (method->IsCallable()) {
8096 Handle<Object> result;
8097 ASSIGN_RETURN_ON_EXCEPTION(
8098 isolate, result, Execution::Call(isolate, method, receiver, 0, NULL),
8099 Object);
8100 if (result->IsPrimitive()) return result;
8101 }
8102 }
8103 THROW_NEW_ERROR(isolate,
8104 NewTypeError(MessageTemplate::kCannotConvertToPrimitive),
8105 Object);
8106}
8107
8108
8109// TODO(cbruni/jkummerow): Consider moving this into elements.cc.
Ben Murdochda12d292016-06-02 14:46:10 +01008110bool JSObject::HasEnumerableElements() {
8111 // TODO(cbruni): cleanup
8112 JSObject* object = this;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00008113 switch (object->GetElementsKind()) {
8114 case FAST_SMI_ELEMENTS:
8115 case FAST_ELEMENTS:
8116 case FAST_DOUBLE_ELEMENTS: {
8117 int length = object->IsJSArray()
8118 ? Smi::cast(JSArray::cast(object)->length())->value()
8119 : object->elements()->length();
8120 return length > 0;
8121 }
8122 case FAST_HOLEY_SMI_ELEMENTS:
8123 case FAST_HOLEY_ELEMENTS: {
8124 FixedArray* elements = FixedArray::cast(object->elements());
8125 int length = object->IsJSArray()
8126 ? Smi::cast(JSArray::cast(object)->length())->value()
8127 : elements->length();
8128 for (int i = 0; i < length; i++) {
8129 if (!elements->is_the_hole(i)) return true;
8130 }
8131 return false;
8132 }
8133 case FAST_HOLEY_DOUBLE_ELEMENTS: {
8134 int length = object->IsJSArray()
8135 ? Smi::cast(JSArray::cast(object)->length())->value()
8136 : object->elements()->length();
8137 // Zero-length arrays would use the empty FixedArray...
8138 if (length == 0) return false;
8139 // ...so only cast to FixedDoubleArray otherwise.
8140 FixedDoubleArray* elements = FixedDoubleArray::cast(object->elements());
8141 for (int i = 0; i < length; i++) {
8142 if (!elements->is_the_hole(i)) return true;
8143 }
8144 return false;
8145 }
8146#define TYPED_ARRAY_CASE(Type, type, TYPE, ctype, size) \
8147 case TYPE##_ELEMENTS:
8148
8149 TYPED_ARRAYS(TYPED_ARRAY_CASE)
8150#undef TYPED_ARRAY_CASE
8151 {
8152 int length = object->elements()->length();
8153 return length > 0;
8154 }
8155 case DICTIONARY_ELEMENTS: {
8156 SeededNumberDictionary* elements =
8157 SeededNumberDictionary::cast(object->elements());
8158 return elements->NumberOfElementsFilterAttributes(ONLY_ENUMERABLE) > 0;
8159 }
8160 case FAST_SLOPPY_ARGUMENTS_ELEMENTS:
8161 case SLOW_SLOPPY_ARGUMENTS_ELEMENTS:
8162 // We're approximating non-empty arguments objects here.
8163 return true;
Ben Murdoch097c5b22016-05-18 11:27:45 +01008164 case FAST_STRING_WRAPPER_ELEMENTS:
8165 case SLOW_STRING_WRAPPER_ELEMENTS:
8166 if (String::cast(JSValue::cast(object)->value())->length() > 0) {
8167 return true;
8168 }
8169 return object->elements()->length() > 0;
8170 case NO_ELEMENTS:
8171 return false;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00008172 }
8173 UNREACHABLE();
8174 return true;
8175}
8176
Steve Blocka7e24c12009-10-30 11:49:00 +00008177
Ben Murdochb8a8cc12014-11-26 15:28:44 +00008178int Map::NumberOfDescribedProperties(DescriptorFlag which,
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00008179 PropertyFilter filter) {
Steve Blocka7e24c12009-10-30 11:49:00 +00008180 int result = 0;
8181 DescriptorArray* descs = instance_descriptors();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00008182 int limit = which == ALL_DESCRIPTORS
8183 ? descs->number_of_descriptors()
8184 : NumberOfOwnDescriptors();
8185 for (int i = 0; i < limit; i++) {
8186 if ((descs->GetDetails(i).attributes() & filter) == 0 &&
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00008187 !descs->GetKey(i)->FilterKey(filter)) {
Ben Murdoch3ef787d2012-04-12 10:51:47 +01008188 result++;
8189 }
Steve Blocka7e24c12009-10-30 11:49:00 +00008190 }
8191 return result;
8192}
8193
8194
Steve Blocka7e24c12009-10-30 11:49:00 +00008195int Map::NextFreePropertyIndex() {
Emily Bernierd0a1eb72015-03-24 16:35:39 -04008196 int free_index = 0;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00008197 int number_of_own_descriptors = NumberOfOwnDescriptors();
Steve Blocka7e24c12009-10-30 11:49:00 +00008198 DescriptorArray* descs = instance_descriptors();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00008199 for (int i = 0; i < number_of_own_descriptors; i++) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -04008200 PropertyDetails details = descs->GetDetails(i);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00008201 if (details.location() == kField) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -04008202 int candidate = details.field_index() + details.field_width_in_words();
8203 if (candidate > free_index) free_index = candidate;
Steve Blocka7e24c12009-10-30 11:49:00 +00008204 }
8205 }
Emily Bernierd0a1eb72015-03-24 16:35:39 -04008206 return free_index;
Steve Blocka7e24c12009-10-30 11:49:00 +00008207}
8208
8209
Ben Murdoch097c5b22016-05-18 11:27:45 +01008210bool Map::OnlyHasSimpleProperties() {
8211 // Wrapped string elements aren't explicitly stored in the elements backing
8212 // store, but are loaded indirectly from the underlying string.
8213 return !IsStringWrapperElementsKind(elements_kind()) &&
Ben Murdochda12d292016-06-02 14:46:10 +01008214 instance_type() > LAST_SPECIAL_RECEIVER_TYPE &&
8215 !has_hidden_prototype() && !is_dictionary_map();
Ben Murdoch097c5b22016-05-18 11:27:45 +01008216}
Ben Murdochb8a8cc12014-11-26 15:28:44 +00008217
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00008218MaybeHandle<FixedArray> JSReceiver::GetKeys(Handle<JSReceiver> object,
8219 KeyCollectionType type,
8220 PropertyFilter filter,
Ben Murdochda12d292016-06-02 14:46:10 +01008221 GetKeysConversion keys_conversion,
8222 bool filter_proxy_keys) {
Ben Murdochc5610432016-08-08 18:44:38 +01008223 return KeyAccumulator::GetKeys(object, type, filter, keys_conversion,
8224 filter_proxy_keys);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01008225}
8226
Ben Murdochda12d292016-06-02 14:46:10 +01008227MUST_USE_RESULT Maybe<bool> FastGetOwnValuesOrEntries(
8228 Isolate* isolate, Handle<JSReceiver> receiver, bool get_entries,
8229 Handle<FixedArray>* result) {
8230 Handle<Map> map(JSReceiver::cast(*receiver)->map(), isolate);
8231
8232 if (!map->IsJSObjectMap()) return Just(false);
8233 if (!map->OnlyHasSimpleProperties()) return Just(false);
8234
8235 Handle<JSObject> object(JSObject::cast(*receiver));
8236
8237 Handle<DescriptorArray> descriptors(map->instance_descriptors(), isolate);
8238 int number_of_own_descriptors = map->NumberOfOwnDescriptors();
8239 int number_of_own_elements =
8240 object->GetElementsAccessor()->GetCapacity(*object, object->elements());
8241 Handle<FixedArray> values_or_entries = isolate->factory()->NewFixedArray(
8242 number_of_own_descriptors + number_of_own_elements);
8243 int count = 0;
8244
8245 if (object->elements() != isolate->heap()->empty_fixed_array()) {
8246 MAYBE_RETURN(object->GetElementsAccessor()->CollectValuesOrEntries(
8247 isolate, object, values_or_entries, get_entries, &count,
8248 ENUMERABLE_STRINGS),
8249 Nothing<bool>());
8250 }
8251
8252 bool stable = object->map() == *map;
8253
8254 for (int index = 0; index < number_of_own_descriptors; index++) {
8255 Handle<Name> next_key(descriptors->GetKey(index), isolate);
8256 if (!next_key->IsString()) continue;
8257 Handle<Object> prop_value;
8258
8259 // Directly decode from the descriptor array if |from| did not change shape.
8260 if (stable) {
8261 PropertyDetails details = descriptors->GetDetails(index);
8262 if (!details.IsEnumerable()) continue;
8263 if (details.kind() == kData) {
8264 if (details.location() == kDescriptor) {
8265 prop_value = handle(descriptors->GetValue(index), isolate);
8266 } else {
8267 Representation representation = details.representation();
8268 FieldIndex field_index = FieldIndex::ForDescriptor(*map, index);
8269 prop_value =
8270 JSObject::FastPropertyAt(object, representation, field_index);
8271 }
8272 } else {
8273 ASSIGN_RETURN_ON_EXCEPTION_VALUE(
8274 isolate, prop_value, JSReceiver::GetProperty(object, next_key),
8275 Nothing<bool>());
8276 stable = object->map() == *map;
8277 }
8278 } else {
8279 // If the map did change, do a slower lookup. We are still guaranteed that
8280 // the object has a simple shape, and that the key is a name.
8281 LookupIterator it(object, next_key, LookupIterator::OWN_SKIP_INTERCEPTOR);
8282 if (!it.IsFound()) continue;
8283 DCHECK(it.state() == LookupIterator::DATA ||
8284 it.state() == LookupIterator::ACCESSOR);
8285 if (!it.IsEnumerable()) continue;
8286 ASSIGN_RETURN_ON_EXCEPTION_VALUE(
8287 isolate, prop_value, Object::GetProperty(&it), Nothing<bool>());
8288 }
8289
8290 if (get_entries) {
8291 prop_value = MakeEntryPair(isolate, next_key, prop_value);
8292 }
8293
8294 values_or_entries->set(count, *prop_value);
8295 count++;
8296 }
8297
8298 if (count < values_or_entries->length()) values_or_entries->Shrink(count);
8299 *result = values_or_entries;
8300 return Just(true);
8301}
8302
Ben Murdoch097c5b22016-05-18 11:27:45 +01008303MaybeHandle<FixedArray> GetOwnValuesOrEntries(Isolate* isolate,
8304 Handle<JSReceiver> object,
8305 PropertyFilter filter,
8306 bool get_entries) {
Ben Murdochda12d292016-06-02 14:46:10 +01008307 Handle<FixedArray> values_or_entries;
8308 if (filter == ENUMERABLE_STRINGS) {
8309 Maybe<bool> fast_values_or_entries = FastGetOwnValuesOrEntries(
8310 isolate, object, get_entries, &values_or_entries);
8311 if (fast_values_or_entries.IsNothing()) return MaybeHandle<FixedArray>();
8312 if (fast_values_or_entries.FromJust()) return values_or_entries;
8313 }
8314
Ben Murdoch097c5b22016-05-18 11:27:45 +01008315 PropertyFilter key_filter =
8316 static_cast<PropertyFilter>(filter & ~ONLY_ENUMERABLE);
8317 KeyAccumulator accumulator(isolate, OWN_ONLY, key_filter);
Ben Murdochc5610432016-08-08 18:44:38 +01008318 MAYBE_RETURN(accumulator.CollectKeys(object, object),
Ben Murdoch097c5b22016-05-18 11:27:45 +01008319 MaybeHandle<FixedArray>());
8320 Handle<FixedArray> keys = accumulator.GetKeys(CONVERT_TO_STRING);
Ben Murdoch097c5b22016-05-18 11:27:45 +01008321
Ben Murdochda12d292016-06-02 14:46:10 +01008322 values_or_entries = isolate->factory()->NewFixedArray(keys->length());
Ben Murdoch097c5b22016-05-18 11:27:45 +01008323 int length = 0;
8324
8325 for (int i = 0; i < keys->length(); ++i) {
8326 Handle<Name> key = Handle<Name>::cast(handle(keys->get(i), isolate));
8327
8328 if (filter & ONLY_ENUMERABLE) {
8329 PropertyDescriptor descriptor;
8330 Maybe<bool> did_get_descriptor = JSReceiver::GetOwnPropertyDescriptor(
8331 isolate, object, key, &descriptor);
8332 MAYBE_RETURN(did_get_descriptor, MaybeHandle<FixedArray>());
8333 if (!did_get_descriptor.FromJust() || !descriptor.enumerable()) continue;
8334 }
8335
8336 Handle<Object> value;
8337 ASSIGN_RETURN_ON_EXCEPTION_VALUE(
8338 isolate, value, JSReceiver::GetPropertyOrElement(object, key),
8339 MaybeHandle<FixedArray>());
8340
8341 if (get_entries) {
8342 Handle<FixedArray> entry_storage =
8343 isolate->factory()->NewUninitializedFixedArray(2);
8344 entry_storage->set(0, *key);
8345 entry_storage->set(1, *value);
8346 value = isolate->factory()->NewJSArrayWithElements(entry_storage,
8347 FAST_ELEMENTS, 2);
8348 }
8349
8350 values_or_entries->set(length, *value);
8351 length++;
8352 }
8353 if (length < values_or_entries->length()) values_or_entries->Shrink(length);
8354 return values_or_entries;
8355}
8356
8357MaybeHandle<FixedArray> JSReceiver::GetOwnValues(Handle<JSReceiver> object,
8358 PropertyFilter filter) {
8359 return GetOwnValuesOrEntries(object->GetIsolate(), object, filter, false);
8360}
8361
8362MaybeHandle<FixedArray> JSReceiver::GetOwnEntries(Handle<JSReceiver> object,
8363 PropertyFilter filter) {
8364 return GetOwnValuesOrEntries(object->GetIsolate(), object, filter, true);
8365}
Ben Murdoch3ef787d2012-04-12 10:51:47 +01008366
Ben Murdochb8a8cc12014-11-26 15:28:44 +00008367bool Map::DictionaryElementsInPrototypeChainOnly() {
8368 if (IsDictionaryElementsKind(elements_kind())) {
8369 return false;
8370 }
8371
8372 for (PrototypeIterator iter(this); !iter.IsAtEnd(); iter.Advance()) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00008373 // Be conservative, don't walk into proxies.
8374 if (iter.GetCurrent()->IsJSProxy()) return true;
8375 // String wrappers have non-configurable, non-writable elements.
8376 if (iter.GetCurrent()->IsStringWrapper()) return true;
8377 JSObject* current = iter.GetCurrent<JSObject>();
8378
8379 if (current->HasDictionaryElements() &&
8380 current->element_dictionary()->requires_slow_elements()) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00008381 return true;
8382 }
8383
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00008384 if (current->HasSlowArgumentsElements()) {
8385 FixedArray* parameter_map = FixedArray::cast(current->elements());
8386 Object* arguments = parameter_map->get(1);
8387 if (SeededNumberDictionary::cast(arguments)->requires_slow_elements()) {
8388 return true;
8389 }
Steve Blocka7e24c12009-10-30 11:49:00 +00008390 }
8391 }
8392
Ben Murdochb8a8cc12014-11-26 15:28:44 +00008393 return false;
Leon Clarkef7060e22010-06-03 12:02:55 +01008394}
8395
8396
Ben Murdochb8a8cc12014-11-26 15:28:44 +00008397MaybeHandle<Object> JSObject::DefineAccessor(Handle<JSObject> object,
8398 Handle<Name> name,
8399 Handle<Object> getter,
8400 Handle<Object> setter,
8401 PropertyAttributes attributes) {
8402 Isolate* isolate = object->GetIsolate();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00008403
8404 LookupIterator it = LookupIterator::PropertyOrElement(
Ben Murdochc5610432016-08-08 18:44:38 +01008405 isolate, object, name, LookupIterator::OWN_SKIP_INTERCEPTOR);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00008406 return DefineAccessor(&it, getter, setter, attributes);
8407}
8408
8409
8410MaybeHandle<Object> JSObject::DefineAccessor(LookupIterator* it,
8411 Handle<Object> getter,
8412 Handle<Object> setter,
8413 PropertyAttributes attributes) {
8414 Isolate* isolate = it->isolate();
8415
Ben Murdochda12d292016-06-02 14:46:10 +01008416 it->UpdateProtector();
8417
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00008418 if (it->state() == LookupIterator::ACCESS_CHECK) {
8419 if (!it->HasAccess()) {
8420 isolate->ReportFailedAccessCheck(it->GetHolder<JSObject>());
8421 RETURN_EXCEPTION_IF_SCHEDULED_EXCEPTION(isolate, Object);
8422 return isolate->factory()->undefined_value();
8423 }
8424 it->Next();
Steve Blocka7e24c12009-10-30 11:49:00 +00008425 }
8426
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00008427 Handle<JSObject> object = Handle<JSObject>::cast(it->GetReceiver());
8428 // Ignore accessors on typed arrays.
8429 if (it->IsElement() && object->HasFixedTypedArrayElements()) {
8430 return it->factory()->undefined_value();
Steve Blocka7e24c12009-10-30 11:49:00 +00008431 }
8432
Ben Murdoch097c5b22016-05-18 11:27:45 +01008433 DCHECK(getter->IsCallable() || getter->IsUndefined() || getter->IsNull() ||
8434 getter->IsFunctionTemplateInfo());
8435 DCHECK(setter->IsCallable() || setter->IsUndefined() || setter->IsNull() ||
8436 getter->IsFunctionTemplateInfo());
Ben Murdochc5610432016-08-08 18:44:38 +01008437 it->TransitionToAccessorProperty(getter, setter, attributes);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00008438
8439 return isolate->factory()->undefined_value();
Steve Blocka7e24c12009-10-30 11:49:00 +00008440}
8441
8442
Ben Murdochb8a8cc12014-11-26 15:28:44 +00008443MaybeHandle<Object> JSObject::SetAccessor(Handle<JSObject> object,
8444 Handle<AccessorInfo> info) {
8445 Isolate* isolate = object->GetIsolate();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00008446 Handle<Name> name(Name::cast(info->name()), isolate);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00008447
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00008448 LookupIterator it = LookupIterator::PropertyOrElement(
Ben Murdochc5610432016-08-08 18:44:38 +01008449 isolate, object, name, LookupIterator::OWN_SKIP_INTERCEPTOR);
Leon Clarkef7060e22010-06-03 12:02:55 +01008450
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00008451 // Duplicate ACCESS_CHECK outside of GetPropertyAttributes for the case that
8452 // the FailedAccessCheckCallbackFunction doesn't throw an exception.
8453 //
8454 // TODO(verwaest): Force throw an exception if the callback doesn't, so we can
8455 // remove reliance on default return values.
8456 if (it.state() == LookupIterator::ACCESS_CHECK) {
8457 if (!it.HasAccess()) {
8458 isolate->ReportFailedAccessCheck(object);
8459 RETURN_EXCEPTION_IF_SCHEDULED_EXCEPTION(isolate, Object);
8460 return it.factory()->undefined_value();
Leon Clarkef7060e22010-06-03 12:02:55 +01008461 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00008462 it.Next();
Leon Clarkef7060e22010-06-03 12:02:55 +01008463 }
8464
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00008465 // Ignore accessors on typed arrays.
8466 if (it.IsElement() && object->HasFixedTypedArrayElements()) {
8467 return it.factory()->undefined_value();
8468 }
8469
8470 CHECK(GetPropertyAttributes(&it).IsJust());
8471
8472 // ES5 forbids turning a property into an accessor if it's not
8473 // configurable. See 8.6.1 (Table 5).
8474 if (it.IsFound() && !it.IsConfigurable()) {
8475 return it.factory()->undefined_value();
8476 }
8477
8478 it.TransitionToAccessorPair(info, info->property_attributes());
8479
Ben Murdochb8a8cc12014-11-26 15:28:44 +00008480 return object;
Leon Clarkef7060e22010-06-03 12:02:55 +01008481}
8482
Steve Blocka7e24c12009-10-30 11:49:00 +00008483Object* JSObject::SlowReverseLookup(Object* value) {
8484 if (HasFastProperties()) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00008485 int number_of_own_descriptors = map()->NumberOfOwnDescriptors();
Steve Blocka7e24c12009-10-30 11:49:00 +00008486 DescriptorArray* descs = map()->instance_descriptors();
Emily Bernierd0a1eb72015-03-24 16:35:39 -04008487 bool value_is_number = value->IsNumber();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00008488 for (int i = 0; i < number_of_own_descriptors; i++) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00008489 if (descs->GetType(i) == DATA) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -04008490 FieldIndex field_index = FieldIndex::ForDescriptor(map(), i);
8491 if (IsUnboxedDoubleField(field_index)) {
8492 if (value_is_number) {
8493 double property = RawFastDoublePropertyAt(field_index);
8494 if (property == value->Number()) {
8495 return descs->GetKey(i);
8496 }
8497 }
8498 } else {
8499 Object* property = RawFastPropertyAt(field_index);
8500 if (field_index.is_double()) {
8501 DCHECK(property->IsMutableHeapNumber());
8502 if (value_is_number && property->Number() == value->Number()) {
8503 return descs->GetKey(i);
8504 }
8505 } else if (property == value) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00008506 return descs->GetKey(i);
8507 }
Steve Blocka7e24c12009-10-30 11:49:00 +00008508 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00008509 } else if (descs->GetType(i) == DATA_CONSTANT) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00008510 if (descs->GetConstant(i) == value) {
Steve Blocka7e24c12009-10-30 11:49:00 +00008511 return descs->GetKey(i);
8512 }
8513 }
8514 }
Ben Murdoch8b112d22011-06-08 16:22:53 +01008515 return GetHeap()->undefined_value();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00008516 } else if (IsJSGlobalObject()) {
8517 return global_dictionary()->SlowReverseLookup(value);
Steve Blocka7e24c12009-10-30 11:49:00 +00008518 } else {
8519 return property_dictionary()->SlowReverseLookup(value);
8520 }
8521}
8522
8523
Ben Murdochb8a8cc12014-11-26 15:28:44 +00008524Handle<Map> Map::RawCopy(Handle<Map> map, int instance_size) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00008525 Isolate* isolate = map->GetIsolate();
8526 Handle<Map> result =
8527 isolate->factory()->NewMap(map->instance_type(), instance_size);
8528 Handle<Object> prototype(map->prototype(), isolate);
8529 Map::SetPrototype(result, prototype);
8530 result->set_constructor_or_backpointer(map->GetConstructor());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00008531 result->set_bit_field(map->bit_field());
8532 result->set_bit_field2(map->bit_field2());
8533 int new_bit_field3 = map->bit_field3();
8534 new_bit_field3 = OwnsDescriptors::update(new_bit_field3, true);
8535 new_bit_field3 = NumberOfOwnDescriptorsBits::update(new_bit_field3, 0);
8536 new_bit_field3 = EnumLengthBits::update(new_bit_field3,
8537 kInvalidEnumCacheSentinel);
8538 new_bit_field3 = Deprecated::update(new_bit_field3, false);
8539 if (!map->is_dictionary_map()) {
8540 new_bit_field3 = IsUnstable::update(new_bit_field3, false);
John Reck59135872010-11-02 12:39:01 -07008541 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00008542 result->set_bit_field3(new_bit_field3);
Steve Blocka7e24c12009-10-30 11:49:00 +00008543 return result;
8544}
8545
8546
Emily Bernierd0a1eb72015-03-24 16:35:39 -04008547Handle<Map> Map::Normalize(Handle<Map> fast_map, PropertyNormalizationMode mode,
8548 const char* reason) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00008549 DCHECK(!fast_map->is_dictionary_map());
8550
8551 Isolate* isolate = fast_map->GetIsolate();
8552 Handle<Object> maybe_cache(isolate->native_context()->normalized_map_cache(),
8553 isolate);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00008554 bool use_cache = !fast_map->is_prototype_map() && !maybe_cache->IsUndefined();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00008555 Handle<NormalizedMapCache> cache;
8556 if (use_cache) cache = Handle<NormalizedMapCache>::cast(maybe_cache);
8557
8558 Handle<Map> new_map;
8559 if (use_cache && cache->Get(fast_map, mode).ToHandle(&new_map)) {
8560#ifdef VERIFY_HEAP
8561 if (FLAG_verify_heap) new_map->DictionaryMapVerify();
8562#endif
8563#ifdef ENABLE_SLOW_DCHECKS
8564 if (FLAG_enable_slow_asserts) {
8565 // The cached map should match newly created normalized map bit-by-bit,
8566 // except for the code cache, which can contain some ics which can be
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00008567 // applied to the shared map, dependent code and weak cell cache.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00008568 Handle<Map> fresh = Map::CopyNormalized(fast_map, mode);
8569
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00008570 if (new_map->is_prototype_map()) {
8571 // For prototype maps, the PrototypeInfo is not copied.
8572 DCHECK(memcmp(fresh->address(), new_map->address(),
8573 kTransitionsOrPrototypeInfoOffset) == 0);
8574 DCHECK(fresh->raw_transitions() == Smi::FromInt(0));
8575 STATIC_ASSERT(kDescriptorsOffset ==
8576 kTransitionsOrPrototypeInfoOffset + kPointerSize);
8577 DCHECK(memcmp(HeapObject::RawField(*fresh, kDescriptorsOffset),
8578 HeapObject::RawField(*new_map, kDescriptorsOffset),
8579 kCodeCacheOffset - kDescriptorsOffset) == 0);
8580 } else {
8581 DCHECK(memcmp(fresh->address(), new_map->address(),
8582 Map::kCodeCacheOffset) == 0);
8583 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00008584 STATIC_ASSERT(Map::kDependentCodeOffset ==
8585 Map::kCodeCacheOffset + kPointerSize);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00008586 STATIC_ASSERT(Map::kWeakCellCacheOffset ==
8587 Map::kDependentCodeOffset + kPointerSize);
8588 int offset = Map::kWeakCellCacheOffset + kPointerSize;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00008589 DCHECK(memcmp(fresh->address() + offset,
8590 new_map->address() + offset,
8591 Map::kSize - offset) == 0);
8592 }
8593#endif
8594 } else {
8595 new_map = Map::CopyNormalized(fast_map, mode);
8596 if (use_cache) {
8597 cache->Set(fast_map, new_map);
Ben Murdoch097c5b22016-05-18 11:27:45 +01008598 isolate->counters()->maps_normalized()->Increment();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00008599 }
Emily Bernierd0a1eb72015-03-24 16:35:39 -04008600#if TRACE_MAPS
8601 if (FLAG_trace_maps) {
8602 PrintF("[TraceMaps: Normalize from= %p to= %p reason= %s ]\n",
8603 reinterpret_cast<void*>(*fast_map),
8604 reinterpret_cast<void*>(*new_map), reason);
8605 }
8606#endif
Ben Murdochb8a8cc12014-11-26 15:28:44 +00008607 }
8608 fast_map->NotifyLeafMapLayoutChange();
8609 return new_map;
8610}
8611
8612
8613Handle<Map> Map::CopyNormalized(Handle<Map> map,
8614 PropertyNormalizationMode mode) {
8615 int new_instance_size = map->instance_size();
Kristian Monsen80d68ea2010-09-08 11:05:35 +01008616 if (mode == CLEAR_INOBJECT_PROPERTIES) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00008617 new_instance_size -= map->GetInObjectProperties() * kPointerSize;
Kristian Monsen80d68ea2010-09-08 11:05:35 +01008618 }
8619
Ben Murdochb8a8cc12014-11-26 15:28:44 +00008620 Handle<Map> result = RawCopy(map, new_instance_size);
Kristian Monsen80d68ea2010-09-08 11:05:35 +01008621
8622 if (mode != CLEAR_INOBJECT_PROPERTIES) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00008623 result->SetInObjectProperties(map->GetInObjectProperties());
Kristian Monsen80d68ea2010-09-08 11:05:35 +01008624 }
8625
Ben Murdochb8a8cc12014-11-26 15:28:44 +00008626 result->set_dictionary_map(true);
8627 result->set_migration_target(false);
Ben Murdoch097c5b22016-05-18 11:27:45 +01008628 result->set_construction_counter(kNoSlackTracking);
Kristian Monsen80d68ea2010-09-08 11:05:35 +01008629
Ben Murdochb8a8cc12014-11-26 15:28:44 +00008630#ifdef VERIFY_HEAP
8631 if (FLAG_verify_heap) result->DictionaryMapVerify();
Kristian Monsen80d68ea2010-09-08 11:05:35 +01008632#endif
8633
8634 return result;
8635}
8636
8637
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00008638Handle<Map> Map::CopyInitialMap(Handle<Map> map, int instance_size,
8639 int in_object_properties,
8640 int unused_property_fields) {
8641#ifdef DEBUG
8642 Isolate* isolate = map->GetIsolate();
Ben Murdochda12d292016-06-02 14:46:10 +01008643 // Strict function maps have Function as a constructor but the
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00008644 // Function's initial map is a sloppy function map. Same holds for
8645 // GeneratorFunction and its initial map.
8646 Object* constructor = map->GetConstructor();
8647 DCHECK(constructor->IsJSFunction());
8648 DCHECK(*map == JSFunction::cast(constructor)->initial_map() ||
8649 *map == *isolate->strict_function_map() ||
Ben Murdochda12d292016-06-02 14:46:10 +01008650 *map == *isolate->strict_generator_function_map());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00008651#endif
8652 // Initial maps must always own their descriptors and it's descriptor array
8653 // does not contain descriptors that do not belong to the map.
8654 DCHECK(map->owns_descriptors());
8655 DCHECK_EQ(map->NumberOfOwnDescriptors(),
8656 map->instance_descriptors()->number_of_descriptors());
8657
8658 Handle<Map> result = RawCopy(map, instance_size);
8659
8660 // Please note instance_type and instance_size are set when allocated.
8661 result->SetInObjectProperties(in_object_properties);
8662 result->set_unused_property_fields(unused_property_fields);
8663
8664 int number_of_own_descriptors = map->NumberOfOwnDescriptors();
8665 if (number_of_own_descriptors > 0) {
8666 // The copy will use the same descriptors array.
8667 result->UpdateDescriptors(map->instance_descriptors(),
8668 map->GetLayoutDescriptor());
8669 result->SetNumberOfOwnDescriptors(number_of_own_descriptors);
8670
8671 DCHECK_EQ(result->NumberOfFields(),
8672 in_object_properties - unused_property_fields);
8673 }
8674
8675 return result;
8676}
8677
8678
Ben Murdochb8a8cc12014-11-26 15:28:44 +00008679Handle<Map> Map::CopyDropDescriptors(Handle<Map> map) {
8680 Handle<Map> result = RawCopy(map, map->instance_size());
8681
8682 // Please note instance_type and instance_size are set when allocated.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00008683 if (map->IsJSObjectMap()) {
8684 result->SetInObjectProperties(map->GetInObjectProperties());
8685 result->set_unused_property_fields(map->unused_property_fields());
8686 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00008687 result->ClearCodeCache(map->GetHeap());
8688 map->NotifyLeafMapLayoutChange();
8689 return result;
8690}
8691
8692
8693Handle<Map> Map::ShareDescriptor(Handle<Map> map,
8694 Handle<DescriptorArray> descriptors,
8695 Descriptor* descriptor) {
8696 // Sanity check. This path is only to be taken if the map owns its descriptor
8697 // array, implying that its NumberOfOwnDescriptors equals the number of
8698 // descriptors in the descriptor array.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00008699 DCHECK_EQ(map->NumberOfOwnDescriptors(),
8700 map->instance_descriptors()->number_of_descriptors());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00008701
8702 Handle<Map> result = CopyDropDescriptors(map);
8703 Handle<Name> name = descriptor->GetKey();
8704
8705 // Ensure there's space for the new descriptor in the shared descriptor array.
8706 if (descriptors->NumberOfSlackDescriptors() == 0) {
8707 int old_size = descriptors->number_of_descriptors();
8708 if (old_size == 0) {
8709 descriptors = DescriptorArray::Allocate(map->GetIsolate(), 0, 1);
8710 } else {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00008711 int slack = SlackForArraySize(old_size, kMaxNumberOfDescriptors);
8712 EnsureDescriptorSlack(map, slack);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00008713 descriptors = handle(map->instance_descriptors());
8714 }
John Reck59135872010-11-02 12:39:01 -07008715 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00008716
Emily Bernierd0a1eb72015-03-24 16:35:39 -04008717 Handle<LayoutDescriptor> layout_descriptor =
8718 FLAG_unbox_double_fields
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00008719 ? LayoutDescriptor::ShareAppend(map, descriptor->GetDetails())
Emily Bernierd0a1eb72015-03-24 16:35:39 -04008720 : handle(LayoutDescriptor::FastPointerLayout(), map->GetIsolate());
8721
Ben Murdochb8a8cc12014-11-26 15:28:44 +00008722 {
8723 DisallowHeapAllocation no_gc;
8724 descriptors->Append(descriptor);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04008725 result->InitializeDescriptors(*descriptors, *layout_descriptor);
John Reck59135872010-11-02 12:39:01 -07008726 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00008727
8728 DCHECK(result->NumberOfOwnDescriptors() == map->NumberOfOwnDescriptors() + 1);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04008729 ConnectTransition(map, result, name, SIMPLE_PROPERTY_TRANSITION);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00008730
8731 return result;
8732}
8733
8734
Emily Bernierd0a1eb72015-03-24 16:35:39 -04008735#if TRACE_MAPS
8736
8737// static
8738void Map::TraceTransition(const char* what, Map* from, Map* to, Name* name) {
8739 if (FLAG_trace_maps) {
8740 PrintF("[TraceMaps: %s from= %p to= %p name= ", what,
8741 reinterpret_cast<void*>(from), reinterpret_cast<void*>(to));
8742 name->NameShortPrint();
8743 PrintF(" ]\n");
8744 }
8745}
8746
8747
8748// static
8749void Map::TraceAllTransitions(Map* map) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00008750 Object* transitions = map->raw_transitions();
8751 int num_transitions = TransitionArray::NumberOfTransitions(transitions);
8752 for (int i = -0; i < num_transitions; ++i) {
8753 Map* target = TransitionArray::GetTarget(transitions, i);
8754 Name* key = TransitionArray::GetKey(transitions, i);
8755 Map::TraceTransition("Transition", map, target, key);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04008756 Map::TraceAllTransitions(target);
8757 }
8758}
8759
8760#endif // TRACE_MAPS
8761
8762
Ben Murdochb8a8cc12014-11-26 15:28:44 +00008763void Map::ConnectTransition(Handle<Map> parent, Handle<Map> child,
8764 Handle<Name> name, SimpleTransitionFlag flag) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00008765 if (!parent->GetBackPointer()->IsUndefined()) {
8766 parent->set_owns_descriptors(false);
8767 } else {
8768 // |parent| is initial map and it must keep the ownership, there must be no
8769 // descriptors in the descriptors array that do not belong to the map.
8770 DCHECK(parent->owns_descriptors());
8771 DCHECK_EQ(parent->NumberOfOwnDescriptors(),
8772 parent->instance_descriptors()->number_of_descriptors());
8773 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00008774 if (parent->is_prototype_map()) {
8775 DCHECK(child->is_prototype_map());
Emily Bernierd0a1eb72015-03-24 16:35:39 -04008776#if TRACE_MAPS
8777 Map::TraceTransition("NoTransition", *parent, *child, *name);
8778#endif
Ben Murdochb8a8cc12014-11-26 15:28:44 +00008779 } else {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00008780 TransitionArray::Insert(parent, name, child, flag);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04008781#if TRACE_MAPS
8782 Map::TraceTransition("Transition", *parent, *child, *name);
8783#endif
Ben Murdochb8a8cc12014-11-26 15:28:44 +00008784 }
8785}
8786
8787
Emily Bernierd0a1eb72015-03-24 16:35:39 -04008788Handle<Map> Map::CopyReplaceDescriptors(
8789 Handle<Map> map, Handle<DescriptorArray> descriptors,
8790 Handle<LayoutDescriptor> layout_descriptor, TransitionFlag flag,
8791 MaybeHandle<Name> maybe_name, const char* reason,
8792 SimpleTransitionFlag simple_flag) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00008793 DCHECK(descriptors->IsSortedNoDuplicates());
8794
8795 Handle<Map> result = CopyDropDescriptors(map);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00008796
8797 if (!map->is_prototype_map()) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00008798 if (flag == INSERT_TRANSITION &&
8799 TransitionArray::CanHaveMoreTransitions(map)) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -04008800 result->InitializeDescriptors(*descriptors, *layout_descriptor);
8801
Ben Murdochb8a8cc12014-11-26 15:28:44 +00008802 Handle<Name> name;
8803 CHECK(maybe_name.ToHandle(&name));
8804 ConnectTransition(map, result, name, simple_flag);
8805 } else {
8806 int length = descriptors->number_of_descriptors();
8807 for (int i = 0; i < length; i++) {
8808 descriptors->SetRepresentation(i, Representation::Tagged());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00008809 if (descriptors->GetDetails(i).type() == DATA) {
Ben Murdoch097c5b22016-05-18 11:27:45 +01008810 descriptors->SetValue(i, FieldType::Any());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00008811 }
8812 }
Emily Bernierd0a1eb72015-03-24 16:35:39 -04008813 result->InitializeDescriptors(*descriptors,
8814 LayoutDescriptor::FastPointerLayout());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00008815 }
Emily Bernierd0a1eb72015-03-24 16:35:39 -04008816 } else {
8817 result->InitializeDescriptors(*descriptors, *layout_descriptor);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00008818 }
Emily Bernierd0a1eb72015-03-24 16:35:39 -04008819#if TRACE_MAPS
8820 if (FLAG_trace_maps &&
8821 // Mirror conditions above that did not call ConnectTransition().
8822 (map->is_prototype_map() ||
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00008823 !(flag == INSERT_TRANSITION &&
8824 TransitionArray::CanHaveMoreTransitions(map)))) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -04008825 PrintF("[TraceMaps: ReplaceDescriptors from= %p to= %p reason= %s ]\n",
8826 reinterpret_cast<void*>(*map), reinterpret_cast<void*>(*result),
8827 reason);
8828 }
8829#endif
Ben Murdochb8a8cc12014-11-26 15:28:44 +00008830
8831 return result;
8832}
8833
8834
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00008835// Creates transition tree starting from |split_map| and adding all descriptors
8836// starting from descriptor with index |split_map|.NumberOfOwnDescriptors().
8837// The way how it is done is tricky because of GC and special descriptors
8838// marking logic.
8839Handle<Map> Map::AddMissingTransitions(
8840 Handle<Map> split_map, Handle<DescriptorArray> descriptors,
Emily Bernierd0a1eb72015-03-24 16:35:39 -04008841 Handle<LayoutDescriptor> full_layout_descriptor) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00008842 DCHECK(descriptors->IsSortedNoDuplicates());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00008843 int split_nof = split_map->NumberOfOwnDescriptors();
8844 int nof_descriptors = descriptors->number_of_descriptors();
8845 DCHECK_LT(split_nof, nof_descriptors);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00008846
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00008847 // Start with creating last map which will own full descriptors array.
8848 // This is necessary to guarantee that GC will mark the whole descriptor
8849 // array if any of the allocations happening below fail.
8850 // Number of unused properties is temporarily incorrect and the layout
8851 // descriptor could unnecessarily be in slow mode but we will fix after
8852 // all the other intermediate maps are created.
8853 Handle<Map> last_map = CopyDropDescriptors(split_map);
8854 last_map->InitializeDescriptors(*descriptors, *full_layout_descriptor);
8855 last_map->set_unused_property_fields(0);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00008856
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00008857 // During creation of intermediate maps we violate descriptors sharing
8858 // invariant since the last map is not yet connected to the transition tree
8859 // we create here. But it is safe because GC never trims map's descriptors
8860 // if there are no dead transitions from that map and this is exactly the
8861 // case for all the intermediate maps we create here.
8862 Handle<Map> map = split_map;
8863 for (int i = split_nof; i < nof_descriptors - 1; ++i) {
8864 Handle<Map> new_map = CopyDropDescriptors(map);
8865 InstallDescriptors(map, new_map, i, descriptors, full_layout_descriptor);
8866 map = new_map;
8867 }
8868 map->NotifyLeafMapLayoutChange();
8869 InstallDescriptors(map, last_map, nof_descriptors - 1, descriptors,
8870 full_layout_descriptor);
8871 return last_map;
8872}
Ben Murdochb8a8cc12014-11-26 15:28:44 +00008873
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00008874
8875// Since this method is used to rewrite an existing transition tree, it can
8876// always insert transitions without checking.
8877void Map::InstallDescriptors(Handle<Map> parent, Handle<Map> child,
8878 int new_descriptor,
8879 Handle<DescriptorArray> descriptors,
8880 Handle<LayoutDescriptor> full_layout_descriptor) {
8881 DCHECK(descriptors->IsSortedNoDuplicates());
8882
8883 child->set_instance_descriptors(*descriptors);
8884 child->SetNumberOfOwnDescriptors(new_descriptor + 1);
8885
8886 int unused_property_fields = parent->unused_property_fields();
Emily Bernierd0a1eb72015-03-24 16:35:39 -04008887 PropertyDetails details = descriptors->GetDetails(new_descriptor);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00008888 if (details.location() == kField) {
8889 unused_property_fields = parent->unused_property_fields() - 1;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00008890 if (unused_property_fields < 0) {
8891 unused_property_fields += JSObject::kFieldsAdded;
8892 }
8893 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00008894 child->set_unused_property_fields(unused_property_fields);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00008895
Emily Bernierd0a1eb72015-03-24 16:35:39 -04008896 if (FLAG_unbox_double_fields) {
8897 Handle<LayoutDescriptor> layout_descriptor =
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00008898 LayoutDescriptor::AppendIfFastOrUseFull(parent, details,
Emily Bernierd0a1eb72015-03-24 16:35:39 -04008899 full_layout_descriptor);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00008900 child->set_layout_descriptor(*layout_descriptor);
8901#ifdef VERIFY_HEAP
8902 // TODO(ishell): remove these checks from VERIFY_HEAP mode.
8903 if (FLAG_verify_heap) {
8904 CHECK(child->layout_descriptor()->IsConsistentWithMap(*child));
8905 }
8906#else
8907 SLOW_DCHECK(child->layout_descriptor()->IsConsistentWithMap(*child));
8908#endif
8909 child->set_visitor_id(Heap::GetStaticVisitorIdForMap(*child));
Emily Bernierd0a1eb72015-03-24 16:35:39 -04008910 }
8911
Ben Murdochb8a8cc12014-11-26 15:28:44 +00008912 Handle<Name> name = handle(descriptors->GetKey(new_descriptor));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00008913 ConnectTransition(parent, child, name, SIMPLE_PROPERTY_TRANSITION);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00008914}
8915
8916
8917Handle<Map> Map::CopyAsElementsKind(Handle<Map> map, ElementsKind kind,
8918 TransitionFlag flag) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00008919 Map* maybe_elements_transition_map = NULL;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00008920 if (flag == INSERT_TRANSITION) {
Ben Murdochc5610432016-08-08 18:44:38 +01008921 // Ensure we are requested to add elements kind transition "near the root".
8922 DCHECK_EQ(map->FindRootMap()->NumberOfOwnDescriptors(),
8923 map->NumberOfOwnDescriptors());
8924
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00008925 maybe_elements_transition_map = map->ElementsTransitionMap();
8926 DCHECK(maybe_elements_transition_map == NULL ||
8927 (maybe_elements_transition_map->elements_kind() ==
8928 DICTIONARY_ELEMENTS &&
8929 kind == DICTIONARY_ELEMENTS));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00008930 DCHECK(!IsFastElementsKind(kind) ||
8931 IsMoreGeneralElementsKindTransition(map->elements_kind(), kind));
8932 DCHECK(kind != map->elements_kind());
8933 }
8934
Emily Bernierd0a1eb72015-03-24 16:35:39 -04008935 bool insert_transition = flag == INSERT_TRANSITION &&
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00008936 TransitionArray::CanHaveMoreTransitions(map) &&
8937 maybe_elements_transition_map == NULL;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00008938
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00008939 if (insert_transition) {
8940 Handle<Map> new_map = CopyForTransition(map, "CopyAsElementsKind");
Ben Murdochb8a8cc12014-11-26 15:28:44 +00008941 new_map->set_elements_kind(kind);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00008942
8943 Isolate* isolate = map->GetIsolate();
8944 Handle<Name> name = isolate->factory()->elements_transition_symbol();
8945 ConnectTransition(map, new_map, name, SPECIAL_TRANSITION);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00008946 return new_map;
8947 }
8948
Ben Murdochb8a8cc12014-11-26 15:28:44 +00008949 // Create a new free-floating map only if we are not allowed to store it.
Emily Bernierd0a1eb72015-03-24 16:35:39 -04008950 Handle<Map> new_map = Copy(map, "CopyAsElementsKind");
Ben Murdochb8a8cc12014-11-26 15:28:44 +00008951 new_map->set_elements_kind(kind);
Steve Block8defd9f2010-07-08 12:39:36 +01008952 return new_map;
Steve Blocka7e24c12009-10-30 11:49:00 +00008953}
8954
Ben Murdochb8a8cc12014-11-26 15:28:44 +00008955
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00008956Handle<Map> Map::AsLanguageMode(Handle<Map> initial_map,
8957 LanguageMode language_mode, FunctionKind kind) {
8958 DCHECK_EQ(JS_FUNCTION_TYPE, initial_map->instance_type());
8959 // Initial map for sloppy mode function is stored in the function
Ben Murdochda12d292016-06-02 14:46:10 +01008960 // constructor. Initial maps for strict mode are cached as special transitions
8961 // using |strict_function_transition_symbol| as a key.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00008962 if (language_mode == SLOPPY) return initial_map;
8963 Isolate* isolate = initial_map->GetIsolate();
8964 Factory* factory = isolate->factory();
8965 Handle<Symbol> transition_symbol;
8966
8967 int map_index = Context::FunctionMapIndex(language_mode, kind);
8968 Handle<Map> function_map(
8969 Map::cast(isolate->native_context()->get(map_index)));
8970
8971 STATIC_ASSERT(LANGUAGE_END == 3);
8972 switch (language_mode) {
8973 case STRICT:
8974 transition_symbol = factory->strict_function_transition_symbol();
8975 break;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00008976 default:
8977 UNREACHABLE();
8978 break;
8979 }
8980 Map* maybe_transition =
8981 TransitionArray::SearchSpecial(*initial_map, *transition_symbol);
8982 if (maybe_transition != NULL) {
8983 return handle(maybe_transition, isolate);
8984 }
8985 initial_map->NotifyLeafMapLayoutChange();
8986
8987 // Create new map taking descriptors from the |function_map| and all
8988 // the other details from the |initial_map|.
8989 Handle<Map> map =
8990 Map::CopyInitialMap(function_map, initial_map->instance_size(),
8991 initial_map->GetInObjectProperties(),
8992 initial_map->unused_property_fields());
8993 map->SetConstructor(initial_map->GetConstructor());
8994 map->set_prototype(initial_map->prototype());
8995
8996 if (TransitionArray::CanHaveMoreTransitions(initial_map)) {
8997 Map::ConnectTransition(initial_map, map, transition_symbol,
8998 SPECIAL_TRANSITION);
8999 }
9000 return map;
9001}
9002
9003
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00009004Handle<Map> Map::CopyForTransition(Handle<Map> map, const char* reason) {
9005 DCHECK(!map->is_prototype_map());
9006 Handle<Map> new_map = CopyDropDescriptors(map);
9007
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009008 if (map->owns_descriptors()) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00009009 // In case the map owned its own descriptors, share the descriptors and
9010 // transfer ownership to the new map.
Emily Bernierd0a1eb72015-03-24 16:35:39 -04009011 // The properties did not change, so reuse descriptors.
9012 new_map->InitializeDescriptors(map->instance_descriptors(),
9013 map->GetLayoutDescriptor());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00009014 } else {
9015 // In case the map did not own its own descriptors, a split is forced by
9016 // copying the map; creating a new descriptor array cell.
9017 Handle<DescriptorArray> descriptors(map->instance_descriptors());
9018 int number_of_own_descriptors = map->NumberOfOwnDescriptors();
9019 Handle<DescriptorArray> new_descriptors =
9020 DescriptorArray::CopyUpTo(descriptors, number_of_own_descriptors);
9021 Handle<LayoutDescriptor> new_layout_descriptor(map->GetLayoutDescriptor(),
9022 map->GetIsolate());
9023 new_map->InitializeDescriptors(*new_descriptors, *new_layout_descriptor);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009024 }
9025
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00009026#if TRACE_MAPS
9027 if (FLAG_trace_maps) {
9028 PrintF("[TraceMaps: CopyForTransition from= %p to= %p reason= %s ]\n",
9029 reinterpret_cast<void*>(*map), reinterpret_cast<void*>(*new_map),
9030 reason);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04009031 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00009032#endif
9033
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009034 return new_map;
Ben Murdoch3ef787d2012-04-12 10:51:47 +01009035}
Steve Blocka7e24c12009-10-30 11:49:00 +00009036
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009037
Emily Bernierd0a1eb72015-03-24 16:35:39 -04009038Handle<Map> Map::Copy(Handle<Map> map, const char* reason) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009039 Handle<DescriptorArray> descriptors(map->instance_descriptors());
9040 int number_of_own_descriptors = map->NumberOfOwnDescriptors();
9041 Handle<DescriptorArray> new_descriptors =
9042 DescriptorArray::CopyUpTo(descriptors, number_of_own_descriptors);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04009043 Handle<LayoutDescriptor> new_layout_descriptor(map->GetLayoutDescriptor(),
9044 map->GetIsolate());
9045 return CopyReplaceDescriptors(map, new_descriptors, new_layout_descriptor,
9046 OMIT_TRANSITION, MaybeHandle<Name>(), reason,
9047 SPECIAL_TRANSITION);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009048}
9049
9050
9051Handle<Map> Map::Create(Isolate* isolate, int inobject_properties) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -04009052 Handle<Map> copy =
9053 Copy(handle(isolate->object_function()->initial_map()), "MapCreate");
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009054
9055 // Check that we do not overflow the instance size when adding the extra
9056 // inobject properties. If the instance size overflows, we allocate as many
9057 // properties as we can as inobject properties.
9058 int max_extra_properties =
9059 (JSObject::kMaxInstanceSize - JSObject::kHeaderSize) >> kPointerSizeLog2;
9060
9061 if (inobject_properties > max_extra_properties) {
9062 inobject_properties = max_extra_properties;
9063 }
9064
9065 int new_instance_size =
9066 JSObject::kHeaderSize + kPointerSize * inobject_properties;
9067
9068 // Adjust the map with the extra inobject properties.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00009069 copy->SetInObjectProperties(inobject_properties);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009070 copy->set_unused_property_fields(inobject_properties);
9071 copy->set_instance_size(new_instance_size);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00009072 copy->set_visitor_id(Heap::GetStaticVisitorIdForMap(*copy));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009073 return copy;
9074}
9075
9076
Emily Bernierd0a1eb72015-03-24 16:35:39 -04009077Handle<Map> Map::CopyForPreventExtensions(Handle<Map> map,
9078 PropertyAttributes attrs_to_add,
9079 Handle<Symbol> transition_marker,
9080 const char* reason) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009081 int num_descriptors = map->NumberOfOwnDescriptors();
9082 Isolate* isolate = map->GetIsolate();
9083 Handle<DescriptorArray> new_desc = DescriptorArray::CopyUpToAddAttributes(
Emily Bernierd0a1eb72015-03-24 16:35:39 -04009084 handle(map->instance_descriptors(), isolate), num_descriptors,
9085 attrs_to_add);
9086 Handle<LayoutDescriptor> new_layout_descriptor(map->GetLayoutDescriptor(),
9087 isolate);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009088 Handle<Map> new_map = CopyReplaceDescriptors(
Emily Bernierd0a1eb72015-03-24 16:35:39 -04009089 map, new_desc, new_layout_descriptor, INSERT_TRANSITION,
9090 transition_marker, reason, SPECIAL_TRANSITION);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009091 new_map->set_is_extensible(false);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00009092 if (!IsFixedTypedArrayElementsKind(map->elements_kind())) {
Ben Murdoch097c5b22016-05-18 11:27:45 +01009093 ElementsKind new_kind = IsStringWrapperElementsKind(map->elements_kind())
9094 ? SLOW_STRING_WRAPPER_ELEMENTS
9095 : DICTIONARY_ELEMENTS;
9096 new_map->set_elements_kind(new_kind);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00009097 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009098 return new_map;
9099}
9100
Ben Murdoch097c5b22016-05-18 11:27:45 +01009101FieldType* DescriptorArray::GetFieldType(int descriptor_number) {
9102 DCHECK(GetDetails(descriptor_number).location() == kField);
9103 Object* value = GetValue(descriptor_number);
9104 if (value->IsWeakCell()) {
9105 if (WeakCell::cast(value)->cleared()) return FieldType::None();
9106 value = WeakCell::cast(value)->value();
9107 }
9108 return FieldType::cast(value);
9109}
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009110
Ben Murdoch097c5b22016-05-18 11:27:45 +01009111namespace {
9112
9113bool CanHoldValue(DescriptorArray* descriptors, int descriptor, Object* value) {
9114 PropertyDetails details = descriptors->GetDetails(descriptor);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009115 switch (details.type()) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00009116 case DATA:
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009117 return value->FitsRepresentation(details.representation()) &&
Ben Murdoch097c5b22016-05-18 11:27:45 +01009118 descriptors->GetFieldType(descriptor)->NowContains(value);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009119
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00009120 case DATA_CONSTANT:
Ben Murdoch097c5b22016-05-18 11:27:45 +01009121 DCHECK(descriptors->GetConstant(descriptor) != value ||
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009122 value->FitsRepresentation(details.representation()));
Ben Murdoch097c5b22016-05-18 11:27:45 +01009123 return descriptors->GetConstant(descriptor) == value;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009124
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00009125 case ACCESSOR:
9126 case ACCESSOR_CONSTANT:
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009127 return false;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009128 }
9129
9130 UNREACHABLE();
9131 return false;
9132}
9133
Ben Murdoch097c5b22016-05-18 11:27:45 +01009134Handle<Map> UpdateDescriptorForValue(Handle<Map> map, int descriptor,
9135 Handle<Object> value) {
9136 if (CanHoldValue(map->instance_descriptors(), descriptor, *value)) return map;
9137
9138 Isolate* isolate = map->GetIsolate();
9139 PropertyAttributes attributes =
9140 map->instance_descriptors()->GetDetails(descriptor).attributes();
9141 Representation representation = value->OptimalRepresentation();
9142 Handle<FieldType> type = value->OptimalType(isolate, representation);
9143
9144 return Map::ReconfigureProperty(map, descriptor, kData, attributes,
9145 representation, type, FORCE_FIELD);
9146}
9147
9148} // namespace
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009149
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00009150// static
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009151Handle<Map> Map::PrepareForDataProperty(Handle<Map> map, int descriptor,
9152 Handle<Object> value) {
9153 // Dictionaries can store any property value.
Ben Murdoch097c5b22016-05-18 11:27:45 +01009154 DCHECK(!map->is_dictionary_map());
9155 // Update to the newest map before storing the property.
9156 return UpdateDescriptorForValue(Update(map), descriptor, value);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009157}
9158
9159
9160Handle<Map> Map::TransitionToDataProperty(Handle<Map> map, Handle<Name> name,
9161 Handle<Object> value,
9162 PropertyAttributes attributes,
9163 StoreFromKeyed store_mode) {
Ben Murdochc5610432016-08-08 18:44:38 +01009164 RuntimeCallTimerScope stats_scope(
9165 *map, map->is_prototype_map()
9166 ? &RuntimeCallStats::PrototypeMap_TransitionToDataProperty
9167 : &RuntimeCallStats::Map_TransitionToDataProperty);
9168
Ben Murdoch097c5b22016-05-18 11:27:45 +01009169 DCHECK(name->IsUniqueName());
9170 DCHECK(!map->is_dictionary_map());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009171
9172 // Migrate to the newest map before storing the property.
9173 map = Update(map);
9174
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00009175 Map* maybe_transition =
9176 TransitionArray::SearchTransition(*map, kData, *name, attributes);
9177 if (maybe_transition != NULL) {
9178 Handle<Map> transition(maybe_transition);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009179 int descriptor = transition->LastAdded();
9180
Emily Bernierd0a1eb72015-03-24 16:35:39 -04009181 DCHECK_EQ(attributes, transition->instance_descriptors()
9182 ->GetDetails(descriptor)
9183 .attributes());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009184
Ben Murdoch097c5b22016-05-18 11:27:45 +01009185 return UpdateDescriptorForValue(transition, descriptor, value);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009186 }
9187
9188 TransitionFlag flag = INSERT_TRANSITION;
9189 MaybeHandle<Map> maybe_map;
9190 if (value->IsJSFunction()) {
9191 maybe_map = Map::CopyWithConstant(map, name, value, attributes, flag);
9192 } else if (!map->TooManyFastProperties(store_mode)) {
9193 Isolate* isolate = name->GetIsolate();
9194 Representation representation = value->OptimalRepresentation();
Ben Murdoch097c5b22016-05-18 11:27:45 +01009195 Handle<FieldType> type = value->OptimalType(isolate, representation);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009196 maybe_map =
9197 Map::CopyWithField(map, name, type, attributes, representation, flag);
9198 }
9199
9200 Handle<Map> result;
9201 if (!maybe_map.ToHandle(&result)) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -04009202#if TRACE_MAPS
9203 if (FLAG_trace_maps) {
9204 Vector<char> name_buffer = Vector<char>::New(100);
9205 name->NameShortPrint(name_buffer);
9206 Vector<char> buffer = Vector<char>::New(128);
9207 SNPrintF(buffer, "TooManyFastProperties %s", name_buffer.start());
9208 return Map::Normalize(map, CLEAR_INOBJECT_PROPERTIES, buffer.start());
9209 }
9210#endif
9211 return Map::Normalize(map, CLEAR_INOBJECT_PROPERTIES,
9212 "TooManyFastProperties");
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009213 }
9214
9215 return result;
9216}
9217
9218
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00009219Handle<Map> Map::ReconfigureExistingProperty(Handle<Map> map, int descriptor,
9220 PropertyKind kind,
9221 PropertyAttributes attributes) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009222 // Dictionaries have to be reconfigured in-place.
9223 DCHECK(!map->is_dictionary_map());
9224
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00009225 if (!map->GetBackPointer()->IsMap()) {
9226 // There is no benefit from reconstructing transition tree for maps without
9227 // back pointers.
9228 return CopyGeneralizeAllRepresentations(
Ben Murdochc5610432016-08-08 18:44:38 +01009229 map, map->elements_kind(), descriptor, FORCE_FIELD, kind, attributes,
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00009230 "GenAll_AttributesMismatchProtoMap");
9231 }
9232
9233 if (FLAG_trace_generalization) {
9234 map->PrintReconfiguration(stdout, descriptor, kind, attributes);
9235 }
9236
9237 Isolate* isolate = map->GetIsolate();
9238 Handle<Map> new_map = ReconfigureProperty(
9239 map, descriptor, kind, attributes, Representation::None(),
Ben Murdoch097c5b22016-05-18 11:27:45 +01009240 FieldType::None(isolate), FORCE_FIELD);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00009241 return new_map;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009242}
9243
Ben Murdochc5610432016-08-08 18:44:38 +01009244Handle<Map> Map::TransitionToAccessorProperty(Isolate* isolate, Handle<Map> map,
Ben Murdochda12d292016-06-02 14:46:10 +01009245 Handle<Name> name, int descriptor,
Ben Murdochc5610432016-08-08 18:44:38 +01009246 Handle<Object> getter,
9247 Handle<Object> setter,
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009248 PropertyAttributes attributes) {
Ben Murdochc5610432016-08-08 18:44:38 +01009249 RuntimeCallTimerScope stats_scope(
9250 isolate,
9251 map->is_prototype_map()
9252 ? &RuntimeCallStats::PrototypeMap_TransitionToAccessorProperty
9253 : &RuntimeCallStats::Map_TransitionToAccessorProperty);
9254
9255 // At least one of the accessors needs to be a new value.
9256 DCHECK(!getter->IsNull() || !setter->IsNull());
Ben Murdoch097c5b22016-05-18 11:27:45 +01009257 DCHECK(name->IsUniqueName());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009258
9259 // Dictionary maps can always have additional data properties.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00009260 if (map->is_dictionary_map()) return map;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009261
9262 // Migrate to the newest map before transitioning to the new property.
9263 map = Update(map);
9264
9265 PropertyNormalizationMode mode = map->is_prototype_map()
9266 ? KEEP_INOBJECT_PROPERTIES
9267 : CLEAR_INOBJECT_PROPERTIES;
9268
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00009269 Map* maybe_transition =
9270 TransitionArray::SearchTransition(*map, kAccessor, *name, attributes);
9271 if (maybe_transition != NULL) {
9272 Handle<Map> transition(maybe_transition, isolate);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009273 DescriptorArray* descriptors = transition->instance_descriptors();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009274 int descriptor = transition->LastAdded();
Emily Bernierd0a1eb72015-03-24 16:35:39 -04009275 DCHECK(descriptors->GetKey(descriptor)->Equals(*name));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009276
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00009277 DCHECK_EQ(kAccessor, descriptors->GetDetails(descriptor).kind());
Emily Bernierd0a1eb72015-03-24 16:35:39 -04009278 DCHECK_EQ(attributes, descriptors->GetDetails(descriptor).attributes());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009279
9280 Handle<Object> maybe_pair(descriptors->GetValue(descriptor), isolate);
9281 if (!maybe_pair->IsAccessorPair()) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -04009282 return Map::Normalize(map, mode, "TransitionToAccessorFromNonPair");
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009283 }
9284
9285 Handle<AccessorPair> pair = Handle<AccessorPair>::cast(maybe_pair);
Ben Murdochc5610432016-08-08 18:44:38 +01009286 if (!pair->Equals(*getter, *setter)) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -04009287 return Map::Normalize(map, mode, "TransitionToDifferentAccessor");
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009288 }
9289
9290 return transition;
9291 }
9292
9293 Handle<AccessorPair> pair;
9294 DescriptorArray* old_descriptors = map->instance_descriptors();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009295 if (descriptor != DescriptorArray::kNotFound) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -04009296 if (descriptor != map->LastAdded()) {
9297 return Map::Normalize(map, mode, "AccessorsOverwritingNonLast");
9298 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009299 PropertyDetails old_details = old_descriptors->GetDetails(descriptor);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00009300 if (old_details.type() != ACCESSOR_CONSTANT) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -04009301 return Map::Normalize(map, mode, "AccessorsOverwritingNonAccessors");
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009302 }
9303
9304 if (old_details.attributes() != attributes) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -04009305 return Map::Normalize(map, mode, "AccessorsWithAttributes");
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009306 }
9307
9308 Handle<Object> maybe_pair(old_descriptors->GetValue(descriptor), isolate);
9309 if (!maybe_pair->IsAccessorPair()) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -04009310 return Map::Normalize(map, mode, "AccessorsOverwritingNonPair");
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009311 }
9312
Ben Murdochc5610432016-08-08 18:44:38 +01009313 Handle<AccessorPair> current_pair = Handle<AccessorPair>::cast(maybe_pair);
9314 if (current_pair->Equals(*getter, *setter)) return map;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009315
Ben Murdochc5610432016-08-08 18:44:38 +01009316 bool overwriting_accessor = false;
9317 if (!getter->IsNull() && !current_pair->get(ACCESSOR_GETTER)->IsNull() &&
9318 current_pair->get(ACCESSOR_GETTER) != *getter) {
9319 overwriting_accessor = true;
9320 }
9321 if (!setter->IsNull() && !current_pair->get(ACCESSOR_SETTER)->IsNull() &&
9322 current_pair->get(ACCESSOR_SETTER) != *setter) {
9323 overwriting_accessor = true;
9324 }
9325 if (overwriting_accessor) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -04009326 return Map::Normalize(map, mode, "AccessorsOverwritingAccessors");
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009327 }
9328
9329 pair = AccessorPair::Copy(Handle<AccessorPair>::cast(maybe_pair));
9330 } else if (map->NumberOfOwnDescriptors() >= kMaxNumberOfDescriptors ||
9331 map->TooManyFastProperties(CERTAINLY_NOT_STORE_FROM_KEYED)) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -04009332 return Map::Normalize(map, CLEAR_INOBJECT_PROPERTIES, "TooManyAccessors");
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009333 } else {
9334 pair = isolate->factory()->NewAccessorPair();
9335 }
9336
Ben Murdochc5610432016-08-08 18:44:38 +01009337 pair->SetComponents(*getter, *setter);
9338
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009339 TransitionFlag flag = INSERT_TRANSITION;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00009340 AccessorConstantDescriptor new_desc(name, pair, attributes);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009341 return Map::CopyInsertDescriptor(map, &new_desc, flag);
9342}
9343
9344
9345Handle<Map> Map::CopyAddDescriptor(Handle<Map> map,
9346 Descriptor* descriptor,
9347 TransitionFlag flag) {
9348 Handle<DescriptorArray> descriptors(map->instance_descriptors());
9349
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00009350 // Share descriptors only if map owns descriptors and it not an initial map.
9351 if (flag == INSERT_TRANSITION && map->owns_descriptors() &&
9352 !map->GetBackPointer()->IsUndefined() &&
9353 TransitionArray::CanHaveMoreTransitions(map)) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009354 return ShareDescriptor(map, descriptors, descriptor);
9355 }
9356
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00009357 int nof = map->NumberOfOwnDescriptors();
9358 Handle<DescriptorArray> new_descriptors =
9359 DescriptorArray::CopyUpTo(descriptors, nof, 1);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009360 new_descriptors->Append(descriptor);
9361
Emily Bernierd0a1eb72015-03-24 16:35:39 -04009362 Handle<LayoutDescriptor> new_layout_descriptor =
9363 FLAG_unbox_double_fields
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00009364 ? LayoutDescriptor::New(map, new_descriptors, nof + 1)
Emily Bernierd0a1eb72015-03-24 16:35:39 -04009365 : handle(LayoutDescriptor::FastPointerLayout(), map->GetIsolate());
9366
9367 return CopyReplaceDescriptors(map, new_descriptors, new_layout_descriptor,
9368 flag, descriptor->GetKey(), "CopyAddDescriptor",
9369 SIMPLE_PROPERTY_TRANSITION);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009370}
9371
9372
9373Handle<Map> Map::CopyInsertDescriptor(Handle<Map> map,
9374 Descriptor* descriptor,
9375 TransitionFlag flag) {
9376 Handle<DescriptorArray> old_descriptors(map->instance_descriptors());
9377
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009378 // We replace the key if it is already present.
Ben Murdoch097c5b22016-05-18 11:27:45 +01009379 int index = old_descriptors->SearchWithCache(map->GetIsolate(),
9380 *descriptor->GetKey(), *map);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009381 if (index != DescriptorArray::kNotFound) {
9382 return CopyReplaceDescriptor(map, old_descriptors, descriptor, index, flag);
9383 }
9384 return CopyAddDescriptor(map, descriptor, flag);
9385}
9386
9387
9388Handle<DescriptorArray> DescriptorArray::CopyUpTo(
9389 Handle<DescriptorArray> desc,
9390 int enumeration_index,
9391 int slack) {
9392 return DescriptorArray::CopyUpToAddAttributes(
9393 desc, enumeration_index, NONE, slack);
9394}
9395
9396
9397Handle<DescriptorArray> DescriptorArray::CopyUpToAddAttributes(
9398 Handle<DescriptorArray> desc,
9399 int enumeration_index,
9400 PropertyAttributes attributes,
9401 int slack) {
9402 if (enumeration_index + slack == 0) {
9403 return desc->GetIsolate()->factory()->empty_descriptor_array();
9404 }
9405
9406 int size = enumeration_index;
9407
9408 Handle<DescriptorArray> descriptors =
9409 DescriptorArray::Allocate(desc->GetIsolate(), size, slack);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009410
9411 if (attributes != NONE) {
9412 for (int i = 0; i < size; ++i) {
9413 Object* value = desc->GetValue(i);
9414 Name* key = desc->GetKey(i);
9415 PropertyDetails details = desc->GetDetails(i);
9416 // Bulk attribute changes never affect private properties.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00009417 if (!key->IsPrivate()) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009418 int mask = DONT_DELETE | DONT_ENUM;
9419 // READ_ONLY is an invalid attribute for JS setters/getters.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00009420 if (details.type() != ACCESSOR_CONSTANT || !value->IsAccessorPair()) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009421 mask |= READ_ONLY;
9422 }
9423 details = details.CopyAddAttributes(
9424 static_cast<PropertyAttributes>(attributes & mask));
9425 }
9426 Descriptor inner_desc(
9427 handle(key), handle(value, desc->GetIsolate()), details);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00009428 descriptors->SetDescriptor(i, &inner_desc);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009429 }
9430 } else {
9431 for (int i = 0; i < size; ++i) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00009432 descriptors->CopyFrom(i, *desc);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009433 }
9434 }
9435
9436 if (desc->number_of_descriptors() != enumeration_index) descriptors->Sort();
9437
9438 return descriptors;
9439}
9440
9441
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00009442bool DescriptorArray::IsEqualUpTo(DescriptorArray* desc, int nof_descriptors) {
9443 for (int i = 0; i < nof_descriptors; i++) {
9444 if (GetKey(i) != desc->GetKey(i) || GetValue(i) != desc->GetValue(i)) {
9445 return false;
9446 }
9447 PropertyDetails details = GetDetails(i);
9448 PropertyDetails other_details = desc->GetDetails(i);
9449 if (details.type() != other_details.type() ||
9450 !details.representation().Equals(other_details.representation())) {
9451 return false;
9452 }
9453 }
9454 return true;
9455}
9456
9457
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009458Handle<Map> Map::CopyReplaceDescriptor(Handle<Map> map,
9459 Handle<DescriptorArray> descriptors,
9460 Descriptor* descriptor,
9461 int insertion_index,
9462 TransitionFlag flag) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009463 Handle<Name> key = descriptor->GetKey();
9464 DCHECK(*key == descriptors->GetKey(insertion_index));
9465
9466 Handle<DescriptorArray> new_descriptors = DescriptorArray::CopyUpTo(
9467 descriptors, map->NumberOfOwnDescriptors());
9468
9469 new_descriptors->Replace(insertion_index, descriptor);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04009470 Handle<LayoutDescriptor> new_layout_descriptor = LayoutDescriptor::New(
9471 map, new_descriptors, new_descriptors->number_of_descriptors());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009472
9473 SimpleTransitionFlag simple_flag =
9474 (insertion_index == descriptors->number_of_descriptors() - 1)
Emily Bernierd0a1eb72015-03-24 16:35:39 -04009475 ? SIMPLE_PROPERTY_TRANSITION
9476 : PROPERTY_TRANSITION;
9477 return CopyReplaceDescriptors(map, new_descriptors, new_layout_descriptor,
9478 flag, key, "CopyReplaceDescriptor",
9479 simple_flag);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009480}
9481
9482
9483void Map::UpdateCodeCache(Handle<Map> map,
9484 Handle<Name> name,
9485 Handle<Code> code) {
9486 Isolate* isolate = map->GetIsolate();
9487 HandleScope scope(isolate);
9488 // Allocate the code cache if not present.
Ben Murdochc5610432016-08-08 18:44:38 +01009489 if (!map->has_code_cache()) {
9490 Handle<Object> result =
9491 CodeCacheHashTable::New(isolate, CodeCacheHashTable::kInitialSize);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009492 map->set_code_cache(*result);
Steve Block6ded16b2010-05-10 14:33:55 +01009493 }
Steve Blocka7e24c12009-10-30 11:49:00 +00009494
Steve Block6ded16b2010-05-10 14:33:55 +01009495 // Update the code cache.
Ben Murdochc5610432016-08-08 18:44:38 +01009496 Handle<CodeCacheHashTable> cache(CodeCacheHashTable::cast(map->code_cache()),
9497 isolate);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009498 Handle<Object> new_cache = CodeCacheHashTable::Put(cache, name, code);
Ben Murdochc5610432016-08-08 18:44:38 +01009499 map->set_code_cache(*new_cache);
Steve Block6ded16b2010-05-10 14:33:55 +01009500}
9501
Ben Murdochc5610432016-08-08 18:44:38 +01009502Code* Map::LookupInCodeCache(Name* name, Code::Flags flags) {
9503 if (!has_code_cache()) return nullptr;
9504 return CodeCacheHashTable::cast(code_cache())->Lookup(name, flags);
Steve Block6ded16b2010-05-10 14:33:55 +01009505}
9506
9507
9508// The key in the code cache hash table consists of the property name and the
9509// code object. The actual match is on the name and the code flags. If a key
9510// is created using the flags and not a code object it can only be used for
9511// lookup not to create a new entry.
9512class CodeCacheHashTableKey : public HashTableKey {
9513 public:
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009514 CodeCacheHashTableKey(Handle<Name> name, Code::Flags flags)
Ben Murdochc5610432016-08-08 18:44:38 +01009515 : name_(name), flags_(flags), code_() {
9516 DCHECK(name_->IsUniqueName());
9517 }
Steve Block6ded16b2010-05-10 14:33:55 +01009518
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009519 CodeCacheHashTableKey(Handle<Name> name, Handle<Code> code)
Ben Murdochc5610432016-08-08 18:44:38 +01009520 : name_(name), flags_(code->flags()), code_(code) {
9521 DCHECK(name_->IsUniqueName());
9522 }
Steve Block6ded16b2010-05-10 14:33:55 +01009523
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00009524 bool IsMatch(Object* other) override {
Ben Murdochc5610432016-08-08 18:44:38 +01009525 DCHECK(other->IsFixedArray());
Steve Block6ded16b2010-05-10 14:33:55 +01009526 FixedArray* pair = FixedArray::cast(other);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009527 Name* name = Name::cast(pair->get(0));
Steve Block6ded16b2010-05-10 14:33:55 +01009528 Code::Flags flags = Code::cast(pair->get(1))->flags();
Ben Murdochc5610432016-08-08 18:44:38 +01009529 if (flags != flags_) return false;
9530 DCHECK(name->IsUniqueName());
9531 return *name_ == name;
Steve Block6ded16b2010-05-10 14:33:55 +01009532 }
9533
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009534 static uint32_t NameFlagsHashHelper(Name* name, Code::Flags flags) {
Steve Block6ded16b2010-05-10 14:33:55 +01009535 return name->Hash() ^ flags;
9536 }
9537
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00009538 uint32_t Hash() override { return NameFlagsHashHelper(*name_, flags_); }
Steve Block6ded16b2010-05-10 14:33:55 +01009539
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00009540 uint32_t HashForObject(Object* obj) override {
Steve Block6ded16b2010-05-10 14:33:55 +01009541 FixedArray* pair = FixedArray::cast(obj);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009542 Name* name = Name::cast(pair->get(0));
Steve Block6ded16b2010-05-10 14:33:55 +01009543 Code* code = Code::cast(pair->get(1));
9544 return NameFlagsHashHelper(name, code->flags());
9545 }
9546
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00009547 MUST_USE_RESULT Handle<Object> AsHandle(Isolate* isolate) override {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009548 Handle<Code> code = code_.ToHandleChecked();
9549 Handle<FixedArray> pair = isolate->factory()->NewFixedArray(2);
9550 pair->set(0, *name_);
9551 pair->set(1, *code);
Steve Block6ded16b2010-05-10 14:33:55 +01009552 return pair;
9553 }
9554
9555 private:
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009556 Handle<Name> name_;
Steve Block6ded16b2010-05-10 14:33:55 +01009557 Code::Flags flags_;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00009558 // TODO(jkummerow): We should be able to get by without this.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009559 MaybeHandle<Code> code_;
Steve Block6ded16b2010-05-10 14:33:55 +01009560};
9561
9562
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009563Handle<CodeCacheHashTable> CodeCacheHashTable::Put(
9564 Handle<CodeCacheHashTable> cache, Handle<Name> name, Handle<Code> code) {
Steve Block6ded16b2010-05-10 14:33:55 +01009565 CodeCacheHashTableKey key(name, code);
Steve Block6ded16b2010-05-10 14:33:55 +01009566
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009567 Handle<CodeCacheHashTable> new_cache = EnsureCapacity(cache, 1, &key);
Steve Block6ded16b2010-05-10 14:33:55 +01009568
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009569 int entry = new_cache->FindInsertionEntry(key.Hash());
9570 Handle<Object> k = key.AsHandle(cache->GetIsolate());
Steve Block6ded16b2010-05-10 14:33:55 +01009571
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009572 new_cache->set(EntryToIndex(entry), *k);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009573 new_cache->ElementAdded();
9574 return new_cache;
Steve Block6ded16b2010-05-10 14:33:55 +01009575}
9576
Ben Murdochc5610432016-08-08 18:44:38 +01009577Code* CodeCacheHashTable::Lookup(Name* name, Code::Flags flags) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009578 DisallowHeapAllocation no_alloc;
9579 CodeCacheHashTableKey key(handle(name), flags);
Steve Block6ded16b2010-05-10 14:33:55 +01009580 int entry = FindEntry(&key);
Ben Murdochc5610432016-08-08 18:44:38 +01009581 if (entry == kNotFound) return nullptr;
9582 return Code::cast(FixedArray::cast(get(EntryToIndex(entry)))->get(1));
Steve Block6ded16b2010-05-10 14:33:55 +01009583}
9584
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009585void FixedArray::Shrink(int new_length) {
9586 DCHECK(0 <= new_length && new_length <= length());
9587 if (new_length < length()) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00009588 GetHeap()->RightTrimFixedArray<Heap::CONCURRENT_TO_SWEEPER>(
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009589 this, length() - new_length);
9590 }
9591}
9592
9593
Steve Blocka7e24c12009-10-30 11:49:00 +00009594void FixedArray::CopyTo(int pos, FixedArray* dest, int dest_pos, int len) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009595 DisallowHeapAllocation no_gc;
Leon Clarke4515c472010-02-03 11:58:03 +00009596 WriteBarrierMode mode = dest->GetWriteBarrierMode(no_gc);
Steve Blocka7e24c12009-10-30 11:49:00 +00009597 for (int index = 0; index < len; index++) {
9598 dest->set(dest_pos+index, get(pos+index), mode);
9599 }
9600}
9601
9602
9603#ifdef DEBUG
9604bool FixedArray::IsEqualTo(FixedArray* other) {
9605 if (length() != other->length()) return false;
9606 for (int i = 0 ; i < length(); ++i) {
9607 if (get(i) != other->get(i)) return false;
9608 }
9609 return true;
9610}
9611#endif
9612
9613
Emily Bernierd0a1eb72015-03-24 16:35:39 -04009614// static
9615void WeakFixedArray::Set(Handle<WeakFixedArray> array, int index,
9616 Handle<HeapObject> value) {
9617 DCHECK(array->IsEmptySlot(index)); // Don't overwrite anything.
9618 Handle<WeakCell> cell =
9619 value->IsMap() ? Map::WeakCellForMap(Handle<Map>::cast(value))
9620 : array->GetIsolate()->factory()->NewWeakCell(value);
9621 Handle<FixedArray>::cast(array)->set(index + kFirstIndex, *cell);
9622 if (FLAG_trace_weak_arrays) {
9623 PrintF("[WeakFixedArray: storing at index %d ]\n", index);
9624 }
9625 array->set_last_used_index(index);
9626}
9627
9628
9629// static
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00009630Handle<WeakFixedArray> WeakFixedArray::Add(Handle<Object> maybe_array,
9631 Handle<HeapObject> value,
9632 int* assigned_index) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -04009633 Handle<WeakFixedArray> array =
9634 (maybe_array.is_null() || !maybe_array->IsWeakFixedArray())
9635 ? Allocate(value->GetIsolate(), 1, Handle<WeakFixedArray>::null())
9636 : Handle<WeakFixedArray>::cast(maybe_array);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04009637 // Try to store the new entry if there's room. Optimize for consecutive
9638 // accesses.
9639 int first_index = array->last_used_index();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00009640 int length = array->Length();
9641 if (length > 0) {
9642 for (int i = first_index;;) {
9643 if (array->IsEmptySlot((i))) {
9644 WeakFixedArray::Set(array, i, value);
9645 if (assigned_index != NULL) *assigned_index = i;
9646 return array;
9647 }
9648 if (FLAG_trace_weak_arrays) {
9649 PrintF("[WeakFixedArray: searching for free slot]\n");
9650 }
9651 i = (i + 1) % length;
9652 if (i == first_index) break;
Emily Bernierd0a1eb72015-03-24 16:35:39 -04009653 }
Emily Bernierd0a1eb72015-03-24 16:35:39 -04009654 }
9655
9656 // No usable slot found, grow the array.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00009657 int new_length = length == 0 ? 1 : length + (length >> 1) + 4;
Emily Bernierd0a1eb72015-03-24 16:35:39 -04009658 Handle<WeakFixedArray> new_array =
9659 Allocate(array->GetIsolate(), new_length, array);
9660 if (FLAG_trace_weak_arrays) {
9661 PrintF("[WeakFixedArray: growing to size %d ]\n", new_length);
9662 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00009663 WeakFixedArray::Set(new_array, length, value);
9664 if (assigned_index != NULL) *assigned_index = length;
Emily Bernierd0a1eb72015-03-24 16:35:39 -04009665 return new_array;
9666}
9667
9668
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00009669template <class CompactionCallback>
9670void WeakFixedArray::Compact() {
9671 FixedArray* array = FixedArray::cast(this);
9672 int new_length = kFirstIndex;
9673 for (int i = kFirstIndex; i < array->length(); i++) {
9674 Object* element = array->get(i);
9675 if (element->IsSmi()) continue;
9676 if (WeakCell::cast(element)->cleared()) continue;
9677 Object* value = WeakCell::cast(element)->value();
9678 CompactionCallback::Callback(value, i - kFirstIndex,
9679 new_length - kFirstIndex);
9680 array->set(new_length++, element);
9681 }
9682 array->Shrink(new_length);
9683 set_last_used_index(0);
9684}
9685
9686
9687void WeakFixedArray::Iterator::Reset(Object* maybe_array) {
9688 if (maybe_array->IsWeakFixedArray()) {
9689 list_ = WeakFixedArray::cast(maybe_array);
9690 index_ = 0;
9691#ifdef DEBUG
9692 last_used_index_ = list_->last_used_index();
9693#endif // DEBUG
9694 }
9695}
9696
9697
9698void JSObject::PrototypeRegistryCompactionCallback::Callback(Object* value,
9699 int old_index,
9700 int new_index) {
9701 DCHECK(value->IsMap() && Map::cast(value)->is_prototype_map());
9702 Map* map = Map::cast(value);
9703 DCHECK(map->prototype_info()->IsPrototypeInfo());
9704 PrototypeInfo* proto_info = PrototypeInfo::cast(map->prototype_info());
9705 DCHECK_EQ(old_index, proto_info->registry_slot());
9706 proto_info->set_registry_slot(new_index);
9707}
9708
9709
9710template void WeakFixedArray::Compact<WeakFixedArray::NullCallback>();
9711template void
9712WeakFixedArray::Compact<JSObject::PrototypeRegistryCompactionCallback>();
9713
9714
9715bool WeakFixedArray::Remove(Handle<HeapObject> value) {
9716 if (Length() == 0) return false;
Emily Bernierd0a1eb72015-03-24 16:35:39 -04009717 // Optimize for the most recently added element to be removed again.
9718 int first_index = last_used_index();
9719 for (int i = first_index;;) {
9720 if (Get(i) == *value) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00009721 Clear(i);
9722 // Users of WeakFixedArray should make sure that there are no duplicates.
9723 return true;
Emily Bernierd0a1eb72015-03-24 16:35:39 -04009724 }
9725 i = (i + 1) % Length();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00009726 if (i == first_index) return false;
Emily Bernierd0a1eb72015-03-24 16:35:39 -04009727 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00009728 UNREACHABLE();
Emily Bernierd0a1eb72015-03-24 16:35:39 -04009729}
9730
9731
9732// static
9733Handle<WeakFixedArray> WeakFixedArray::Allocate(
9734 Isolate* isolate, int size, Handle<WeakFixedArray> initialize_from) {
9735 DCHECK(0 <= size);
9736 Handle<FixedArray> result =
9737 isolate->factory()->NewUninitializedFixedArray(size + kFirstIndex);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00009738 int index = 0;
9739 if (!initialize_from.is_null()) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -04009740 DCHECK(initialize_from->Length() <= size);
9741 Handle<FixedArray> raw_source = Handle<FixedArray>::cast(initialize_from);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00009742 // Copy the entries without compacting, since the PrototypeInfo relies on
9743 // the index of the entries not to change.
9744 while (index < raw_source->length()) {
9745 result->set(index, raw_source->get(index));
9746 index++;
Emily Bernierd0a1eb72015-03-24 16:35:39 -04009747 }
9748 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00009749 while (index < result->length()) {
9750 result->set(index, Smi::FromInt(0));
9751 index++;
9752 }
9753 return Handle<WeakFixedArray>::cast(result);
9754}
9755
9756
9757Handle<ArrayList> ArrayList::Add(Handle<ArrayList> array, Handle<Object> obj,
9758 AddMode mode) {
9759 int length = array->Length();
9760 array = EnsureSpace(array, length + 1);
9761 if (mode == kReloadLengthAfterAllocation) {
9762 DCHECK(array->Length() <= length);
9763 length = array->Length();
9764 }
9765 array->Set(length, *obj);
9766 array->SetLength(length + 1);
9767 return array;
9768}
9769
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00009770Handle<ArrayList> ArrayList::Add(Handle<ArrayList> array, Handle<Object> obj1,
9771 Handle<Object> obj2, AddMode mode) {
9772 int length = array->Length();
9773 array = EnsureSpace(array, length + 2);
9774 if (mode == kReloadLengthAfterAllocation) {
9775 length = array->Length();
9776 }
9777 array->Set(length, *obj1);
9778 array->Set(length + 1, *obj2);
9779 array->SetLength(length + 2);
9780 return array;
9781}
9782
9783
9784bool ArrayList::IsFull() {
9785 int capacity = length();
9786 return kFirstIndex + Length() == capacity;
9787}
9788
9789
9790Handle<ArrayList> ArrayList::EnsureSpace(Handle<ArrayList> array, int length) {
9791 int capacity = array->length();
9792 bool empty = (capacity == 0);
9793 if (capacity < kFirstIndex + length) {
9794 Isolate* isolate = array->GetIsolate();
9795 int new_capacity = kFirstIndex + length;
9796 new_capacity = new_capacity + Max(new_capacity / 2, 2);
9797 int grow_by = new_capacity - capacity;
9798 array = Handle<ArrayList>::cast(
9799 isolate->factory()->CopyFixedArrayAndGrow(array, grow_by));
9800 if (empty) array->SetLength(0);
9801 }
9802 return array;
Emily Bernierd0a1eb72015-03-24 16:35:39 -04009803}
9804
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009805Handle<DescriptorArray> DescriptorArray::Allocate(Isolate* isolate,
9806 int number_of_descriptors,
Ben Murdoch097c5b22016-05-18 11:27:45 +01009807 int slack,
9808 PretenureFlag pretenure) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009809 DCHECK(0 <= number_of_descriptors);
9810 Factory* factory = isolate->factory();
Steve Blocka7e24c12009-10-30 11:49:00 +00009811 // Do not use DescriptorArray::cast on incomplete object.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009812 int size = number_of_descriptors + slack;
9813 if (size == 0) return factory->empty_descriptor_array();
9814 // Allocate the array of keys.
Ben Murdoch097c5b22016-05-18 11:27:45 +01009815 Handle<FixedArray> result =
9816 factory->NewFixedArray(LengthFor(size), pretenure);
Steve Blocka7e24c12009-10-30 11:49:00 +00009817
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009818 result->set(kDescriptorLengthIndex, Smi::FromInt(number_of_descriptors));
9819 result->set(kEnumCacheIndex, Smi::FromInt(0));
9820 return Handle<DescriptorArray>::cast(result);
9821}
9822
9823
9824void DescriptorArray::ClearEnumCache() {
9825 set(kEnumCacheIndex, Smi::FromInt(0));
9826}
9827
9828
9829void DescriptorArray::Replace(int index, Descriptor* descriptor) {
9830 descriptor->SetSortedKeyIndex(GetSortedKeyIndex(index));
9831 Set(index, descriptor);
Steve Blocka7e24c12009-10-30 11:49:00 +00009832}
9833
9834
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00009835// static
9836void DescriptorArray::SetEnumCache(Handle<DescriptorArray> descriptors,
9837 Isolate* isolate,
9838 Handle<FixedArray> new_cache,
9839 Handle<FixedArray> new_index_cache) {
9840 DCHECK(!descriptors->IsEmpty());
9841 FixedArray* bridge_storage;
9842 bool needs_new_enum_cache = !descriptors->HasEnumCache();
9843 if (needs_new_enum_cache) {
9844 bridge_storage = *isolate->factory()->NewFixedArray(
9845 DescriptorArray::kEnumCacheBridgeLength);
9846 } else {
9847 bridge_storage = FixedArray::cast(descriptors->get(kEnumCacheIndex));
9848 }
9849 bridge_storage->set(kEnumCacheBridgeCacheIndex, *new_cache);
9850 bridge_storage->set(kEnumCacheBridgeIndicesCacheIndex,
9851 new_index_cache.is_null() ? Object::cast(Smi::FromInt(0))
9852 : *new_index_cache);
9853 if (needs_new_enum_cache) {
9854 descriptors->set(kEnumCacheIndex, bridge_storage);
9855 }
Steve Blocka7e24c12009-10-30 11:49:00 +00009856}
9857
9858
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00009859void DescriptorArray::CopyFrom(int index, DescriptorArray* src) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009860 Object* value = src->GetValue(index);
9861 PropertyDetails details = src->GetDetails(index);
9862 Descriptor desc(handle(src->GetKey(index)),
9863 handle(value, src->GetIsolate()),
9864 details);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00009865 SetDescriptor(index, &desc);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01009866}
9867
9868
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009869void DescriptorArray::Sort() {
Steve Blocka7e24c12009-10-30 11:49:00 +00009870 // In-place heap sort.
9871 int len = number_of_descriptors();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009872 // Reset sorting since the descriptor array might contain invalid pointers.
9873 for (int i = 0; i < len; ++i) SetSortedKey(i, i);
Steve Blocka7e24c12009-10-30 11:49:00 +00009874 // Bottom-up max-heap construction.
Steve Block6ded16b2010-05-10 14:33:55 +01009875 // Index of the last node with children
9876 const int max_parent_index = (len / 2) - 1;
9877 for (int i = max_parent_index; i >= 0; --i) {
9878 int parent_index = i;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009879 const uint32_t parent_hash = GetSortedKey(i)->Hash();
Steve Block6ded16b2010-05-10 14:33:55 +01009880 while (parent_index <= max_parent_index) {
9881 int child_index = 2 * parent_index + 1;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009882 uint32_t child_hash = GetSortedKey(child_index)->Hash();
Steve Block6ded16b2010-05-10 14:33:55 +01009883 if (child_index + 1 < len) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009884 uint32_t right_child_hash = GetSortedKey(child_index + 1)->Hash();
Steve Block6ded16b2010-05-10 14:33:55 +01009885 if (right_child_hash > child_hash) {
9886 child_index++;
9887 child_hash = right_child_hash;
9888 }
Steve Blocka7e24c12009-10-30 11:49:00 +00009889 }
Steve Block6ded16b2010-05-10 14:33:55 +01009890 if (child_hash <= parent_hash) break;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009891 SwapSortedKeys(parent_index, child_index);
Steve Block6ded16b2010-05-10 14:33:55 +01009892 // Now element at child_index could be < its children.
9893 parent_index = child_index; // parent_hash remains correct.
Steve Blocka7e24c12009-10-30 11:49:00 +00009894 }
9895 }
9896
9897 // Extract elements and create sorted array.
9898 for (int i = len - 1; i > 0; --i) {
9899 // Put max element at the back of the array.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009900 SwapSortedKeys(0, i);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01009901 // Shift down the new top element.
Steve Blocka7e24c12009-10-30 11:49:00 +00009902 int parent_index = 0;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009903 const uint32_t parent_hash = GetSortedKey(parent_index)->Hash();
Steve Block6ded16b2010-05-10 14:33:55 +01009904 const int max_parent_index = (i / 2) - 1;
9905 while (parent_index <= max_parent_index) {
9906 int child_index = parent_index * 2 + 1;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009907 uint32_t child_hash = GetSortedKey(child_index)->Hash();
Steve Block6ded16b2010-05-10 14:33:55 +01009908 if (child_index + 1 < i) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009909 uint32_t right_child_hash = GetSortedKey(child_index + 1)->Hash();
Steve Block6ded16b2010-05-10 14:33:55 +01009910 if (right_child_hash > child_hash) {
9911 child_index++;
9912 child_hash = right_child_hash;
9913 }
Steve Blocka7e24c12009-10-30 11:49:00 +00009914 }
Steve Block6ded16b2010-05-10 14:33:55 +01009915 if (child_hash <= parent_hash) break;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009916 SwapSortedKeys(parent_index, child_index);
Steve Block6ded16b2010-05-10 14:33:55 +01009917 parent_index = child_index;
Steve Blocka7e24c12009-10-30 11:49:00 +00009918 }
9919 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009920 DCHECK(IsSortedNoDuplicates());
Kristian Monsen0d5e1162010-09-30 15:31:59 +01009921}
Steve Blocka7e24c12009-10-30 11:49:00 +00009922
Kristian Monsen0d5e1162010-09-30 15:31:59 +01009923
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009924Handle<AccessorPair> AccessorPair::Copy(Handle<AccessorPair> pair) {
9925 Handle<AccessorPair> copy = pair->GetIsolate()->factory()->NewAccessorPair();
9926 copy->set_getter(pair->getter());
9927 copy->set_setter(pair->setter());
Ben Murdoch3ef787d2012-04-12 10:51:47 +01009928 return copy;
9929}
9930
Ben Murdoch097c5b22016-05-18 11:27:45 +01009931Handle<Object> AccessorPair::GetComponent(Handle<AccessorPair> accessor_pair,
9932 AccessorComponent component) {
9933 Object* accessor = accessor_pair->get(component);
9934 if (accessor->IsFunctionTemplateInfo()) {
9935 return ApiNatives::InstantiateFunction(
9936 handle(FunctionTemplateInfo::cast(accessor)))
9937 .ToHandleChecked();
9938 }
9939 Isolate* isolate = accessor_pair->GetIsolate();
Ben Murdochc5610432016-08-08 18:44:38 +01009940 if (accessor->IsNull()) {
Ben Murdoch097c5b22016-05-18 11:27:45 +01009941 return isolate->factory()->undefined_value();
9942 }
9943 return handle(accessor, isolate);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01009944}
9945
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009946Handle<DeoptimizationInputData> DeoptimizationInputData::New(
9947 Isolate* isolate, int deopt_entry_count, PretenureFlag pretenure) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009948 return Handle<DeoptimizationInputData>::cast(
9949 isolate->factory()->NewFixedArray(LengthFor(deopt_entry_count),
9950 pretenure));
Ben Murdochb0fe1622011-05-05 13:52:32 +01009951}
9952
9953
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009954Handle<DeoptimizationOutputData> DeoptimizationOutputData::New(
9955 Isolate* isolate,
9956 int number_of_deopt_points,
9957 PretenureFlag pretenure) {
9958 Handle<FixedArray> result;
9959 if (number_of_deopt_points == 0) {
9960 result = isolate->factory()->empty_fixed_array();
9961 } else {
9962 result = isolate->factory()->NewFixedArray(
9963 LengthOfFixedArray(number_of_deopt_points), pretenure);
9964 }
9965 return Handle<DeoptimizationOutputData>::cast(result);
Ben Murdochb0fe1622011-05-05 13:52:32 +01009966}
9967
9968
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00009969// static
9970Handle<LiteralsArray> LiteralsArray::New(Isolate* isolate,
9971 Handle<TypeFeedbackVector> vector,
9972 int number_of_literals,
9973 PretenureFlag pretenure) {
9974 Handle<FixedArray> literals = isolate->factory()->NewFixedArray(
9975 number_of_literals + kFirstLiteralIndex, pretenure);
9976 Handle<LiteralsArray> casted_literals = Handle<LiteralsArray>::cast(literals);
9977 casted_literals->set_feedback_vector(*vector);
9978 return casted_literals;
9979}
9980
Ben Murdoch097c5b22016-05-18 11:27:45 +01009981int HandlerTable::LookupRange(int pc_offset, int* data_out,
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00009982 CatchPrediction* prediction_out) {
Ben Murdoch097c5b22016-05-18 11:27:45 +01009983 int innermost_handler = -1;
9984#ifdef DEBUG
9985 // Assuming that ranges are well nested, we don't need to track the innermost
9986 // offsets. This is just to verify that the table is actually well nested.
9987 int innermost_start = std::numeric_limits<int>::min();
9988 int innermost_end = std::numeric_limits<int>::max();
9989#endif
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00009990 for (int i = 0; i < length(); i += kRangeEntrySize) {
9991 int start_offset = Smi::cast(get(i + kRangeStartIndex))->value();
9992 int end_offset = Smi::cast(get(i + kRangeEndIndex))->value();
9993 int handler_field = Smi::cast(get(i + kRangeHandlerIndex))->value();
9994 int handler_offset = HandlerOffsetField::decode(handler_field);
9995 CatchPrediction prediction = HandlerPredictionField::decode(handler_field);
Ben Murdoch097c5b22016-05-18 11:27:45 +01009996 int handler_data = Smi::cast(get(i + kRangeDataIndex))->value();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00009997 if (pc_offset > start_offset && pc_offset <= end_offset) {
Ben Murdoch097c5b22016-05-18 11:27:45 +01009998 DCHECK_GE(start_offset, innermost_start);
9999 DCHECK_LT(end_offset, innermost_end);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000010000 innermost_handler = handler_offset;
Ben Murdoch097c5b22016-05-18 11:27:45 +010010001#ifdef DEBUG
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000010002 innermost_start = start_offset;
Ben Murdoch097c5b22016-05-18 11:27:45 +010010003 innermost_end = end_offset;
10004#endif
10005 if (data_out) *data_out = handler_data;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000010006 if (prediction_out) *prediction_out = prediction;
10007 }
10008 }
10009 return innermost_handler;
10010}
10011
10012
10013// TODO(turbofan): Make sure table is sorted and use binary search.
10014int HandlerTable::LookupReturn(int pc_offset, CatchPrediction* prediction_out) {
10015 for (int i = 0; i < length(); i += kReturnEntrySize) {
10016 int return_offset = Smi::cast(get(i + kReturnOffsetIndex))->value();
10017 int handler_field = Smi::cast(get(i + kReturnHandlerIndex))->value();
10018 if (pc_offset == return_offset) {
10019 if (prediction_out) {
10020 *prediction_out = HandlerPredictionField::decode(handler_field);
10021 }
10022 return HandlerOffsetField::decode(handler_field);
10023 }
10024 }
10025 return -1;
10026}
10027
10028
Steve Blocka7e24c12009-10-30 11:49:00 +000010029#ifdef DEBUG
10030bool DescriptorArray::IsEqualTo(DescriptorArray* other) {
10031 if (IsEmpty()) return other->IsEmpty();
10032 if (other->IsEmpty()) return false;
10033 if (length() != other->length()) return false;
10034 for (int i = 0; i < length(); ++i) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010035 if (get(i) != other->get(i)) return false;
Steve Blocka7e24c12009-10-30 11:49:00 +000010036 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010037 return true;
Steve Blocka7e24c12009-10-30 11:49:00 +000010038}
10039#endif
10040
10041
Steve Blocka7e24c12009-10-30 11:49:00 +000010042bool String::LooksValid() {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010043 if (!GetIsolate()->heap()->Contains(this)) return false;
Steve Blocka7e24c12009-10-30 11:49:00 +000010044 return true;
10045}
10046
10047
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000010048// static
10049MaybeHandle<String> Name::ToFunctionName(Handle<Name> name) {
10050 if (name->IsString()) return Handle<String>::cast(name);
10051 // ES6 section 9.2.11 SetFunctionName, step 4.
10052 Isolate* const isolate = name->GetIsolate();
10053 Handle<Object> description(Handle<Symbol>::cast(name)->name(), isolate);
10054 if (description->IsUndefined()) return isolate->factory()->empty_string();
10055 IncrementalStringBuilder builder(isolate);
10056 builder.AppendCharacter('[');
10057 builder.AppendString(Handle<String>::cast(description));
10058 builder.AppendCharacter(']');
10059 return builder.Finish();
10060}
10061
10062
10063namespace {
10064
10065bool AreDigits(const uint8_t* s, int from, int to) {
10066 for (int i = from; i < to; i++) {
10067 if (s[i] < '0' || s[i] > '9') return false;
10068 }
10069
10070 return true;
10071}
10072
10073
10074int ParseDecimalInteger(const uint8_t* s, int from, int to) {
10075 DCHECK(to - from < 10); // Overflow is not possible.
10076 DCHECK(from < to);
10077 int d = s[from] - '0';
10078
10079 for (int i = from + 1; i < to; i++) {
10080 d = 10 * d + (s[i] - '0');
10081 }
10082
10083 return d;
10084}
10085
10086} // namespace
10087
10088
10089// static
10090Handle<Object> String::ToNumber(Handle<String> subject) {
10091 Isolate* const isolate = subject->GetIsolate();
10092
10093 // Flatten {subject} string first.
10094 subject = String::Flatten(subject);
10095
10096 // Fast array index case.
10097 uint32_t index;
10098 if (subject->AsArrayIndex(&index)) {
10099 return isolate->factory()->NewNumberFromUint(index);
10100 }
10101
10102 // Fast case: short integer or some sorts of junk values.
10103 if (subject->IsSeqOneByteString()) {
10104 int len = subject->length();
10105 if (len == 0) return handle(Smi::FromInt(0), isolate);
10106
10107 DisallowHeapAllocation no_gc;
10108 uint8_t const* data = Handle<SeqOneByteString>::cast(subject)->GetChars();
10109 bool minus = (data[0] == '-');
10110 int start_pos = (minus ? 1 : 0);
10111
10112 if (start_pos == len) {
10113 return isolate->factory()->nan_value();
10114 } else if (data[start_pos] > '9') {
10115 // Fast check for a junk value. A valid string may start from a
10116 // whitespace, a sign ('+' or '-'), the decimal point, a decimal digit
10117 // or the 'I' character ('Infinity'). All of that have codes not greater
10118 // than '9' except 'I' and &nbsp;.
10119 if (data[start_pos] != 'I' && data[start_pos] != 0xa0) {
10120 return isolate->factory()->nan_value();
10121 }
10122 } else if (len - start_pos < 10 && AreDigits(data, start_pos, len)) {
10123 // The maximal/minimal smi has 10 digits. If the string has less digits
10124 // we know it will fit into the smi-data type.
10125 int d = ParseDecimalInteger(data, start_pos, len);
10126 if (minus) {
10127 if (d == 0) return isolate->factory()->minus_zero_value();
10128 d = -d;
10129 } else if (!subject->HasHashCode() && len <= String::kMaxArrayIndexSize &&
10130 (len == 1 || data[0] != '0')) {
10131 // String hash is not calculated yet but all the data are present.
10132 // Update the hash field to speed up sequential convertions.
10133 uint32_t hash = StringHasher::MakeArrayIndexHash(d, len);
10134#ifdef DEBUG
10135 subject->Hash(); // Force hash calculation.
10136 DCHECK_EQ(static_cast<int>(subject->hash_field()),
10137 static_cast<int>(hash));
10138#endif
10139 subject->set_hash_field(hash);
10140 }
10141 return handle(Smi::FromInt(d), isolate);
10142 }
10143 }
10144
10145 // Slower case.
10146 int flags = ALLOW_HEX | ALLOW_OCTAL | ALLOW_BINARY;
10147 return isolate->factory()->NewNumber(
10148 StringToDouble(isolate->unicode_cache(), subject, flags));
10149}
10150
10151
Ben Murdoch69a99ed2011-11-30 16:03:39 +000010152String::FlatContent String::GetFlatContent() {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010153 DCHECK(!AllowHeapAllocation::IsAllowed());
Steve Blocka7e24c12009-10-30 11:49:00 +000010154 int length = this->length();
Ben Murdoch69a99ed2011-11-30 16:03:39 +000010155 StringShape shape(this);
Steve Blocka7e24c12009-10-30 11:49:00 +000010156 String* string = this;
Steve Blocka7e24c12009-10-30 11:49:00 +000010157 int offset = 0;
Ben Murdoch69a99ed2011-11-30 16:03:39 +000010158 if (shape.representation_tag() == kConsStringTag) {
Steve Blocka7e24c12009-10-30 11:49:00 +000010159 ConsString* cons = ConsString::cast(string);
Ben Murdoch69a99ed2011-11-30 16:03:39 +000010160 if (cons->second()->length() != 0) {
10161 return FlatContent();
10162 }
Steve Blocka7e24c12009-10-30 11:49:00 +000010163 string = cons->first();
Ben Murdoch69a99ed2011-11-30 16:03:39 +000010164 shape = StringShape(string);
Steve Blocka7e24c12009-10-30 11:49:00 +000010165 }
Ben Murdoch69a99ed2011-11-30 16:03:39 +000010166 if (shape.representation_tag() == kSlicedStringTag) {
10167 SlicedString* slice = SlicedString::cast(string);
10168 offset = slice->offset();
10169 string = slice->parent();
10170 shape = StringShape(string);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010171 DCHECK(shape.representation_tag() != kConsStringTag &&
Ben Murdoch69a99ed2011-11-30 16:03:39 +000010172 shape.representation_tag() != kSlicedStringTag);
Steve Blocka7e24c12009-10-30 11:49:00 +000010173 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010174 if (shape.encoding_tag() == kOneByteStringTag) {
10175 const uint8_t* start;
Ben Murdoch69a99ed2011-11-30 16:03:39 +000010176 if (shape.representation_tag() == kSeqStringTag) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010177 start = SeqOneByteString::cast(string)->GetChars();
Ben Murdoch69a99ed2011-11-30 16:03:39 +000010178 } else {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010179 start = ExternalOneByteString::cast(string)->GetChars();
Ben Murdoch69a99ed2011-11-30 16:03:39 +000010180 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010181 return FlatContent(start + offset, length);
Ben Murdoch69a99ed2011-11-30 16:03:39 +000010182 } else {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010183 DCHECK(shape.encoding_tag() == kTwoByteStringTag);
Ben Murdoch69a99ed2011-11-30 16:03:39 +000010184 const uc16* start;
10185 if (shape.representation_tag() == kSeqStringTag) {
10186 start = SeqTwoByteString::cast(string)->GetChars();
10187 } else {
Ben Murdoch3ef787d2012-04-12 10:51:47 +010010188 start = ExternalTwoByteString::cast(string)->GetChars();
Ben Murdoch69a99ed2011-11-30 16:03:39 +000010189 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010190 return FlatContent(start + offset, length);
Ben Murdoch69a99ed2011-11-30 16:03:39 +000010191 }
Steve Blocka7e24c12009-10-30 11:49:00 +000010192}
10193
10194
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000010195base::SmartArrayPointer<char> String::ToCString(AllowNullsFlag allow_nulls,
10196 RobustnessFlag robust_flag,
10197 int offset, int length,
10198 int* length_return) {
Steve Blocka7e24c12009-10-30 11:49:00 +000010199 if (robust_flag == ROBUST_STRING_TRAVERSAL && !LooksValid()) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000010200 return base::SmartArrayPointer<char>(NULL);
Steve Blocka7e24c12009-10-30 11:49:00 +000010201 }
Steve Blocka7e24c12009-10-30 11:49:00 +000010202 // Negative length means the to the end of the string.
10203 if (length < 0) length = kMaxInt - offset;
10204
10205 // Compute the size of the UTF-8 string. Start at the specified offset.
Emily Bernierd0a1eb72015-03-24 16:35:39 -040010206 StringCharacterStream stream(this, offset);
Steve Blocka7e24c12009-10-30 11:49:00 +000010207 int character_position = offset;
10208 int utf8_bytes = 0;
Ben Murdoch3ef787d2012-04-12 10:51:47 +010010209 int last = unibrow::Utf16::kNoPreviousCharacter;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010210 while (stream.HasMore() && character_position++ < offset + length) {
10211 uint16_t character = stream.GetNext();
Ben Murdoch3ef787d2012-04-12 10:51:47 +010010212 utf8_bytes += unibrow::Utf8::Length(character, last);
10213 last = character;
Steve Blocka7e24c12009-10-30 11:49:00 +000010214 }
10215
10216 if (length_return) {
10217 *length_return = utf8_bytes;
10218 }
10219
10220 char* result = NewArray<char>(utf8_bytes + 1);
10221
10222 // Convert the UTF-16 string to a UTF-8 buffer. Start at the specified offset.
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010223 stream.Reset(this, offset);
Steve Blocka7e24c12009-10-30 11:49:00 +000010224 character_position = offset;
10225 int utf8_byte_position = 0;
Ben Murdoch3ef787d2012-04-12 10:51:47 +010010226 last = unibrow::Utf16::kNoPreviousCharacter;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010227 while (stream.HasMore() && character_position++ < offset + length) {
10228 uint16_t character = stream.GetNext();
Ben Murdoch3ef787d2012-04-12 10:51:47 +010010229 if (allow_nulls == DISALLOW_NULLS && character == 0) {
10230 character = ' ';
Steve Blocka7e24c12009-10-30 11:49:00 +000010231 }
Ben Murdoch3ef787d2012-04-12 10:51:47 +010010232 utf8_byte_position +=
10233 unibrow::Utf8::Encode(result + utf8_byte_position, character, last);
10234 last = character;
Steve Blocka7e24c12009-10-30 11:49:00 +000010235 }
10236 result[utf8_byte_position] = 0;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000010237 return base::SmartArrayPointer<char>(result);
Steve Blocka7e24c12009-10-30 11:49:00 +000010238}
10239
10240
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000010241base::SmartArrayPointer<char> String::ToCString(AllowNullsFlag allow_nulls,
10242 RobustnessFlag robust_flag,
10243 int* length_return) {
Steve Blocka7e24c12009-10-30 11:49:00 +000010244 return ToCString(allow_nulls, robust_flag, 0, -1, length_return);
10245}
10246
10247
Steve Blocka7e24c12009-10-30 11:49:00 +000010248const uc16* String::GetTwoByteData(unsigned start) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010249 DCHECK(!IsOneByteRepresentationUnderneath());
Steve Blocka7e24c12009-10-30 11:49:00 +000010250 switch (StringShape(this).representation_tag()) {
10251 case kSeqStringTag:
10252 return SeqTwoByteString::cast(this)->SeqTwoByteStringGetData(start);
10253 case kExternalStringTag:
10254 return ExternalTwoByteString::cast(this)->
10255 ExternalTwoByteStringGetData(start);
Ben Murdoch69a99ed2011-11-30 16:03:39 +000010256 case kSlicedStringTag: {
10257 SlicedString* slice = SlicedString::cast(this);
10258 return slice->parent()->GetTwoByteData(start + slice->offset());
10259 }
Steve Blocka7e24c12009-10-30 11:49:00 +000010260 case kConsStringTag:
10261 UNREACHABLE();
10262 return NULL;
10263 }
10264 UNREACHABLE();
10265 return NULL;
10266}
10267
10268
Steve Blocka7e24c12009-10-30 11:49:00 +000010269const uc16* SeqTwoByteString::SeqTwoByteStringGetData(unsigned start) {
10270 return reinterpret_cast<uc16*>(
10271 reinterpret_cast<char*>(this) - kHeapObjectTag + kHeaderSize) + start;
10272}
10273
10274
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010275void Relocatable::PostGarbageCollectionProcessing(Isolate* isolate) {
Steve Block44f0eee2011-05-26 01:26:41 +010010276 Relocatable* current = isolate->relocatable_top();
Steve Blocka7e24c12009-10-30 11:49:00 +000010277 while (current != NULL) {
10278 current->PostGarbageCollection();
10279 current = current->prev_;
10280 }
10281}
10282
10283
10284// Reserve space for statics needing saving and restoring.
10285int Relocatable::ArchiveSpacePerThread() {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010286 return sizeof(Relocatable*); // NOLINT
Steve Blocka7e24c12009-10-30 11:49:00 +000010287}
10288
10289
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010290// Archive statics that are thread-local.
Ben Murdoch257744e2011-11-30 15:57:28 +000010291char* Relocatable::ArchiveState(Isolate* isolate, char* to) {
Steve Block44f0eee2011-05-26 01:26:41 +010010292 *reinterpret_cast<Relocatable**>(to) = isolate->relocatable_top();
10293 isolate->set_relocatable_top(NULL);
Steve Blocka7e24c12009-10-30 11:49:00 +000010294 return to + ArchiveSpacePerThread();
10295}
10296
10297
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010298// Restore statics that are thread-local.
Ben Murdoch257744e2011-11-30 15:57:28 +000010299char* Relocatable::RestoreState(Isolate* isolate, char* from) {
Steve Block44f0eee2011-05-26 01:26:41 +010010300 isolate->set_relocatable_top(*reinterpret_cast<Relocatable**>(from));
Steve Blocka7e24c12009-10-30 11:49:00 +000010301 return from + ArchiveSpacePerThread();
10302}
10303
10304
10305char* Relocatable::Iterate(ObjectVisitor* v, char* thread_storage) {
10306 Relocatable* top = *reinterpret_cast<Relocatable**>(thread_storage);
10307 Iterate(v, top);
10308 return thread_storage + ArchiveSpacePerThread();
10309}
10310
10311
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010312void Relocatable::Iterate(Isolate* isolate, ObjectVisitor* v) {
Steve Block44f0eee2011-05-26 01:26:41 +010010313 Iterate(v, isolate->relocatable_top());
Steve Blocka7e24c12009-10-30 11:49:00 +000010314}
10315
10316
10317void Relocatable::Iterate(ObjectVisitor* v, Relocatable* top) {
10318 Relocatable* current = top;
10319 while (current != NULL) {
10320 current->IterateInstance(v);
10321 current = current->prev_;
10322 }
10323}
10324
10325
Steve Block44f0eee2011-05-26 01:26:41 +010010326FlatStringReader::FlatStringReader(Isolate* isolate, Handle<String> str)
10327 : Relocatable(isolate),
10328 str_(str.location()),
Steve Blocka7e24c12009-10-30 11:49:00 +000010329 length_(str->length()) {
10330 PostGarbageCollection();
10331}
10332
10333
Steve Block44f0eee2011-05-26 01:26:41 +010010334FlatStringReader::FlatStringReader(Isolate* isolate, Vector<const char> input)
10335 : Relocatable(isolate),
10336 str_(0),
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010337 is_one_byte_(true),
Steve Blocka7e24c12009-10-30 11:49:00 +000010338 length_(input.length()),
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010339 start_(input.start()) {}
Steve Blocka7e24c12009-10-30 11:49:00 +000010340
10341
10342void FlatStringReader::PostGarbageCollection() {
10343 if (str_ == NULL) return;
10344 Handle<String> str(str_);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010345 DCHECK(str->IsFlat());
10346 DisallowHeapAllocation no_gc;
10347 // This does not actually prevent the vector from being relocated later.
Ben Murdoch69a99ed2011-11-30 16:03:39 +000010348 String::FlatContent content = str->GetFlatContent();
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010349 DCHECK(content.IsFlat());
10350 is_one_byte_ = content.IsOneByte();
10351 if (is_one_byte_) {
10352 start_ = content.ToOneByteVector().start();
Steve Blocka7e24c12009-10-30 11:49:00 +000010353 } else {
Ben Murdoch69a99ed2011-11-30 16:03:39 +000010354 start_ = content.ToUC16Vector().start();
Steve Blocka7e24c12009-10-30 11:49:00 +000010355 }
10356}
10357
10358
Emily Bernierd0a1eb72015-03-24 16:35:39 -040010359void ConsStringIterator::Initialize(ConsString* cons_string, int offset) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010360 DCHECK(cons_string != NULL);
10361 root_ = cons_string;
10362 consumed_ = offset;
10363 // Force stack blown condition to trigger restart.
10364 depth_ = 1;
10365 maximum_depth_ = kStackSize + depth_;
10366 DCHECK(StackBlown());
Steve Blocka7e24c12009-10-30 11:49:00 +000010367}
10368
10369
Emily Bernierd0a1eb72015-03-24 16:35:39 -040010370String* ConsStringIterator::Continue(int* offset_out) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010371 DCHECK(depth_ != 0);
10372 DCHECK_EQ(0, *offset_out);
10373 bool blew_stack = StackBlown();
10374 String* string = NULL;
10375 // Get the next leaf if there is one.
10376 if (!blew_stack) string = NextLeaf(&blew_stack);
10377 // Restart search from root.
10378 if (blew_stack) {
10379 DCHECK(string == NULL);
10380 string = Search(offset_out);
Steve Blocka7e24c12009-10-30 11:49:00 +000010381 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010382 // Ensure future calls return null immediately.
10383 if (string == NULL) Reset(NULL);
10384 return string;
Steve Blocka7e24c12009-10-30 11:49:00 +000010385}
10386
10387
Emily Bernierd0a1eb72015-03-24 16:35:39 -040010388String* ConsStringIterator::Search(int* offset_out) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010389 ConsString* cons_string = root_;
10390 // Reset the stack, pushing the root string.
10391 depth_ = 1;
10392 maximum_depth_ = 1;
10393 frames_[0] = cons_string;
10394 const int consumed = consumed_;
10395 int offset = 0;
Steve Blocka7e24c12009-10-30 11:49:00 +000010396 while (true) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010397 // Loop until the string is found which contains the target offset.
10398 String* string = cons_string->first();
10399 int length = string->length();
10400 int32_t type;
10401 if (consumed < offset + length) {
10402 // Target offset is in the left branch.
10403 // Keep going if we're still in a ConString.
10404 type = string->map()->instance_type();
10405 if ((type & kStringRepresentationMask) == kConsStringTag) {
10406 cons_string = ConsString::cast(string);
10407 PushLeft(cons_string);
Steve Blocka7e24c12009-10-30 11:49:00 +000010408 continue;
Steve Blocka7e24c12009-10-30 11:49:00 +000010409 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010410 // Tell the stack we're done descending.
10411 AdjustMaximumDepth();
Steve Blocka7e24c12009-10-30 11:49:00 +000010412 } else {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010413 // Descend right.
10414 // Update progress through the string.
10415 offset += length;
10416 // Keep going if we're still in a ConString.
10417 string = cons_string->second();
10418 type = string->map()->instance_type();
10419 if ((type & kStringRepresentationMask) == kConsStringTag) {
10420 cons_string = ConsString::cast(string);
10421 PushRight(cons_string);
10422 continue;
Steve Blocka7e24c12009-10-30 11:49:00 +000010423 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010424 // Need this to be updated for the current string.
10425 length = string->length();
10426 // Account for the possibility of an empty right leaf.
10427 // This happens only if we have asked for an offset outside the string.
10428 if (length == 0) {
10429 // Reset so future operations will return null immediately.
10430 Reset(NULL);
10431 return NULL;
10432 }
10433 // Tell the stack we're done descending.
10434 AdjustMaximumDepth();
10435 // Pop stack so next iteration is in correct place.
10436 Pop();
10437 }
10438 DCHECK(length != 0);
10439 // Adjust return values and exit.
10440 consumed_ = offset + length;
10441 *offset_out = consumed - offset;
10442 return string;
10443 }
10444 UNREACHABLE();
10445 return NULL;
10446}
10447
10448
Emily Bernierd0a1eb72015-03-24 16:35:39 -040010449String* ConsStringIterator::NextLeaf(bool* blew_stack) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010450 while (true) {
10451 // Tree traversal complete.
10452 if (depth_ == 0) {
10453 *blew_stack = false;
10454 return NULL;
10455 }
10456 // We've lost track of higher nodes.
10457 if (StackBlown()) {
10458 *blew_stack = true;
10459 return NULL;
10460 }
10461 // Go right.
10462 ConsString* cons_string = frames_[OffsetForDepth(depth_ - 1)];
10463 String* string = cons_string->second();
10464 int32_t type = string->map()->instance_type();
10465 if ((type & kStringRepresentationMask) != kConsStringTag) {
10466 // Pop stack so next iteration is in correct place.
10467 Pop();
10468 int length = string->length();
10469 // Could be a flattened ConsString.
10470 if (length == 0) continue;
10471 consumed_ += length;
10472 return string;
10473 }
10474 cons_string = ConsString::cast(string);
10475 PushRight(cons_string);
10476 // Need to traverse all the way left.
10477 while (true) {
10478 // Continue left.
10479 string = cons_string->first();
10480 type = string->map()->instance_type();
10481 if ((type & kStringRepresentationMask) != kConsStringTag) {
10482 AdjustMaximumDepth();
10483 int length = string->length();
10484 DCHECK(length != 0);
10485 consumed_ += length;
10486 return string;
10487 }
10488 cons_string = ConsString::cast(string);
10489 PushLeft(cons_string);
Steve Blocka7e24c12009-10-30 11:49:00 +000010490 }
10491 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010492 UNREACHABLE();
10493 return NULL;
Steve Blocka7e24c12009-10-30 11:49:00 +000010494}
10495
10496
Steve Blocka7e24c12009-10-30 11:49:00 +000010497uint16_t ConsString::ConsStringGet(int index) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010498 DCHECK(index >= 0 && index < this->length());
Steve Blocka7e24c12009-10-30 11:49:00 +000010499
10500 // Check for a flattened cons string
10501 if (second()->length() == 0) {
10502 String* left = first();
10503 return left->Get(index);
10504 }
10505
10506 String* string = String::cast(this);
10507
10508 while (true) {
10509 if (StringShape(string).IsCons()) {
10510 ConsString* cons_string = ConsString::cast(string);
10511 String* left = cons_string->first();
10512 if (left->length() > index) {
10513 string = left;
10514 } else {
10515 index -= left->length();
10516 string = cons_string->second();
10517 }
10518 } else {
10519 return string->Get(index);
10520 }
10521 }
10522
10523 UNREACHABLE();
10524 return 0;
10525}
10526
10527
Ben Murdoch69a99ed2011-11-30 16:03:39 +000010528uint16_t SlicedString::SlicedStringGet(int index) {
10529 return parent()->Get(offset() + index);
10530}
10531
10532
Steve Blocka7e24c12009-10-30 11:49:00 +000010533template <typename sinkchar>
10534void String::WriteToFlat(String* src,
10535 sinkchar* sink,
10536 int f,
10537 int t) {
10538 String* source = src;
10539 int from = f;
10540 int to = t;
10541 while (true) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010542 DCHECK(0 <= from && from <= to && to <= source->length());
Steve Blocka7e24c12009-10-30 11:49:00 +000010543 switch (StringShape(source).full_representation_tag()) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010544 case kOneByteStringTag | kExternalStringTag: {
10545 CopyChars(sink, ExternalOneByteString::cast(source)->GetChars() + from,
Steve Blocka7e24c12009-10-30 11:49:00 +000010546 to - from);
10547 return;
10548 }
10549 case kTwoByteStringTag | kExternalStringTag: {
10550 const uc16* data =
Ben Murdoch3ef787d2012-04-12 10:51:47 +010010551 ExternalTwoByteString::cast(source)->GetChars();
Steve Blocka7e24c12009-10-30 11:49:00 +000010552 CopyChars(sink,
10553 data + from,
10554 to - from);
10555 return;
10556 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010557 case kOneByteStringTag | kSeqStringTag: {
Steve Blocka7e24c12009-10-30 11:49:00 +000010558 CopyChars(sink,
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010559 SeqOneByteString::cast(source)->GetChars() + from,
Steve Blocka7e24c12009-10-30 11:49:00 +000010560 to - from);
10561 return;
10562 }
10563 case kTwoByteStringTag | kSeqStringTag: {
10564 CopyChars(sink,
10565 SeqTwoByteString::cast(source)->GetChars() + from,
10566 to - from);
10567 return;
10568 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010569 case kOneByteStringTag | kConsStringTag:
Steve Blocka7e24c12009-10-30 11:49:00 +000010570 case kTwoByteStringTag | kConsStringTag: {
10571 ConsString* cons_string = ConsString::cast(source);
10572 String* first = cons_string->first();
10573 int boundary = first->length();
10574 if (to - boundary >= boundary - from) {
10575 // Right hand side is longer. Recurse over left.
10576 if (from < boundary) {
10577 WriteToFlat(first, sink, from, boundary);
Ben Murdochda12d292016-06-02 14:46:10 +010010578 if (from == 0 && cons_string->second() == first) {
10579 CopyChars(sink + boundary, sink, boundary);
10580 return;
10581 }
Steve Blocka7e24c12009-10-30 11:49:00 +000010582 sink += boundary - from;
10583 from = 0;
10584 } else {
10585 from -= boundary;
10586 }
10587 to -= boundary;
10588 source = cons_string->second();
10589 } else {
10590 // Left hand side is longer. Recurse over right.
10591 if (to > boundary) {
10592 String* second = cons_string->second();
Ben Murdoch3ef787d2012-04-12 10:51:47 +010010593 // When repeatedly appending to a string, we get a cons string that
10594 // is unbalanced to the left, a list, essentially. We inline the
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010595 // common case of sequential one-byte right child.
Ben Murdoch3ef787d2012-04-12 10:51:47 +010010596 if (to - boundary == 1) {
10597 sink[boundary - from] = static_cast<sinkchar>(second->Get(0));
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010598 } else if (second->IsSeqOneByteString()) {
Ben Murdoch3ef787d2012-04-12 10:51:47 +010010599 CopyChars(sink + boundary - from,
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010600 SeqOneByteString::cast(second)->GetChars(),
Steve Blocka7e24c12009-10-30 11:49:00 +000010601 to - boundary);
Ben Murdoch3ef787d2012-04-12 10:51:47 +010010602 } else {
10603 WriteToFlat(second,
10604 sink + boundary - from,
10605 0,
10606 to - boundary);
10607 }
Steve Blocka7e24c12009-10-30 11:49:00 +000010608 to = boundary;
10609 }
10610 source = first;
10611 }
10612 break;
10613 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010614 case kOneByteStringTag | kSlicedStringTag:
Ben Murdoch69a99ed2011-11-30 16:03:39 +000010615 case kTwoByteStringTag | kSlicedStringTag: {
10616 SlicedString* slice = SlicedString::cast(source);
10617 unsigned offset = slice->offset();
10618 WriteToFlat(slice->parent(), sink, from + offset, to + offset);
10619 return;
10620 }
Steve Blocka7e24c12009-10-30 11:49:00 +000010621 }
10622 }
10623}
10624
10625
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010626
10627template <typename SourceChar>
10628static void CalculateLineEndsImpl(Isolate* isolate,
10629 List<int>* line_ends,
10630 Vector<const SourceChar> src,
10631 bool include_ending_line) {
10632 const int src_len = src.length();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000010633 UnicodeCache* cache = isolate->unicode_cache();
10634 for (int i = 0; i < src_len - 1; i++) {
10635 SourceChar current = src[i];
10636 SourceChar next = src[i + 1];
10637 if (cache->IsLineTerminatorSequence(current, next)) line_ends->Add(i);
10638 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010639
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000010640 if (src_len > 0 && cache->IsLineTerminatorSequence(src[src_len - 1], 0)) {
10641 line_ends->Add(src_len - 1);
10642 }
10643 if (include_ending_line) {
10644 // Include one character beyond the end of script. The rewriter uses that
10645 // position for the implicit return statement.
10646 line_ends->Add(src_len);
Steve Blocka7e24c12009-10-30 11:49:00 +000010647 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010648}
10649
10650
10651Handle<FixedArray> String::CalculateLineEnds(Handle<String> src,
10652 bool include_ending_line) {
10653 src = Flatten(src);
10654 // Rough estimate of line count based on a roughly estimated average
10655 // length of (unpacked) code.
10656 int line_count_estimate = src->length() >> 4;
10657 List<int> line_ends(line_count_estimate);
10658 Isolate* isolate = src->GetIsolate();
10659 { DisallowHeapAllocation no_allocation; // ensure vectors stay valid.
10660 // Dispatch on type of strings.
10661 String::FlatContent content = src->GetFlatContent();
10662 DCHECK(content.IsFlat());
10663 if (content.IsOneByte()) {
10664 CalculateLineEndsImpl(isolate,
10665 &line_ends,
10666 content.ToOneByteVector(),
10667 include_ending_line);
10668 } else {
10669 CalculateLineEndsImpl(isolate,
10670 &line_ends,
10671 content.ToUC16Vector(),
10672 include_ending_line);
10673 }
10674 }
10675 int line_count = line_ends.length();
10676 Handle<FixedArray> array = isolate->factory()->NewFixedArray(line_count);
10677 for (int i = 0; i < line_count; i++) {
10678 array->set(i, Smi::FromInt(line_ends[i]));
10679 }
10680 return array;
Steve Blocka7e24c12009-10-30 11:49:00 +000010681}
10682
10683
10684// Compares the contents of two strings by reading and comparing
10685// int-sized blocks of characters.
10686template <typename Char>
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010687static inline bool CompareRawStringContents(const Char* const a,
10688 const Char* const b,
10689 int length) {
10690 return CompareChars(a, b, length) == 0;
10691}
10692
10693
10694template<typename Chars1, typename Chars2>
10695class RawStringComparator : public AllStatic {
10696 public:
10697 static inline bool compare(const Chars1* a, const Chars2* b, int len) {
10698 DCHECK(sizeof(Chars1) != sizeof(Chars2));
10699 for (int i = 0; i < len; i++) {
10700 if (a[i] != b[i]) {
Steve Blocka7e24c12009-10-30 11:49:00 +000010701 return false;
10702 }
10703 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010704 return true;
Steve Blocka7e24c12009-10-30 11:49:00 +000010705 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010706};
Steve Blocka7e24c12009-10-30 11:49:00 +000010707
10708
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010709template<>
10710class RawStringComparator<uint16_t, uint16_t> {
10711 public:
10712 static inline bool compare(const uint16_t* a, const uint16_t* b, int len) {
10713 return CompareRawStringContents(a, b, len);
Steve Blocka7e24c12009-10-30 11:49:00 +000010714 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010715};
10716
10717
10718template<>
10719class RawStringComparator<uint8_t, uint8_t> {
10720 public:
10721 static inline bool compare(const uint8_t* a, const uint8_t* b, int len) {
10722 return CompareRawStringContents(a, b, len);
10723 }
10724};
10725
10726
10727class StringComparator {
10728 class State {
10729 public:
Emily Bernierd0a1eb72015-03-24 16:35:39 -040010730 State() : is_one_byte_(true), length_(0), buffer8_(NULL) {}
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010731
Emily Bernierd0a1eb72015-03-24 16:35:39 -040010732 void Init(String* string) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010733 ConsString* cons_string = String::VisitFlat(this, string);
Emily Bernierd0a1eb72015-03-24 16:35:39 -040010734 iter_.Reset(cons_string);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010735 if (cons_string != NULL) {
10736 int offset;
Emily Bernierd0a1eb72015-03-24 16:35:39 -040010737 string = iter_.Next(&offset);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010738 String::VisitFlat(this, string, offset);
10739 }
10740 }
10741
10742 inline void VisitOneByteString(const uint8_t* chars, int length) {
10743 is_one_byte_ = true;
10744 buffer8_ = chars;
10745 length_ = length;
10746 }
10747
10748 inline void VisitTwoByteString(const uint16_t* chars, int length) {
10749 is_one_byte_ = false;
10750 buffer16_ = chars;
10751 length_ = length;
10752 }
10753
10754 void Advance(int consumed) {
10755 DCHECK(consumed <= length_);
10756 // Still in buffer.
10757 if (length_ != consumed) {
10758 if (is_one_byte_) {
10759 buffer8_ += consumed;
10760 } else {
10761 buffer16_ += consumed;
10762 }
10763 length_ -= consumed;
10764 return;
10765 }
10766 // Advance state.
10767 int offset;
Emily Bernierd0a1eb72015-03-24 16:35:39 -040010768 String* next = iter_.Next(&offset);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010769 DCHECK_EQ(0, offset);
10770 DCHECK(next != NULL);
10771 String::VisitFlat(this, next);
10772 }
10773
Emily Bernierd0a1eb72015-03-24 16:35:39 -040010774 ConsStringIterator iter_;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010775 bool is_one_byte_;
10776 int length_;
10777 union {
10778 const uint8_t* buffer8_;
10779 const uint16_t* buffer16_;
10780 };
10781
10782 private:
Emily Bernierd0a1eb72015-03-24 16:35:39 -040010783 DISALLOW_COPY_AND_ASSIGN(State);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010784 };
10785
10786 public:
Emily Bernierd0a1eb72015-03-24 16:35:39 -040010787 inline StringComparator() {}
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010788
10789 template<typename Chars1, typename Chars2>
10790 static inline bool Equals(State* state_1, State* state_2, int to_check) {
10791 const Chars1* a = reinterpret_cast<const Chars1*>(state_1->buffer8_);
10792 const Chars2* b = reinterpret_cast<const Chars2*>(state_2->buffer8_);
10793 return RawStringComparator<Chars1, Chars2>::compare(a, b, to_check);
10794 }
10795
10796 bool Equals(String* string_1, String* string_2) {
10797 int length = string_1->length();
10798 state_1_.Init(string_1);
10799 state_2_.Init(string_2);
10800 while (true) {
10801 int to_check = Min(state_1_.length_, state_2_.length_);
10802 DCHECK(to_check > 0 && to_check <= length);
10803 bool is_equal;
10804 if (state_1_.is_one_byte_) {
10805 if (state_2_.is_one_byte_) {
10806 is_equal = Equals<uint8_t, uint8_t>(&state_1_, &state_2_, to_check);
10807 } else {
10808 is_equal = Equals<uint8_t, uint16_t>(&state_1_, &state_2_, to_check);
10809 }
10810 } else {
10811 if (state_2_.is_one_byte_) {
10812 is_equal = Equals<uint16_t, uint8_t>(&state_1_, &state_2_, to_check);
10813 } else {
10814 is_equal = Equals<uint16_t, uint16_t>(&state_1_, &state_2_, to_check);
10815 }
10816 }
10817 // Looping done.
10818 if (!is_equal) return false;
10819 length -= to_check;
10820 // Exit condition. Strings are equal.
10821 if (length == 0) return true;
10822 state_1_.Advance(to_check);
10823 state_2_.Advance(to_check);
10824 }
10825 }
10826
10827 private:
10828 State state_1_;
10829 State state_2_;
Emily Bernierd0a1eb72015-03-24 16:35:39 -040010830
10831 DISALLOW_COPY_AND_ASSIGN(StringComparator);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010832};
Steve Blocka7e24c12009-10-30 11:49:00 +000010833
10834
Steve Blocka7e24c12009-10-30 11:49:00 +000010835bool String::SlowEquals(String* other) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010836 DisallowHeapAllocation no_gc;
Steve Blocka7e24c12009-10-30 11:49:00 +000010837 // Fast check: negative check with lengths.
10838 int len = length();
10839 if (len != other->length()) return false;
10840 if (len == 0) return true;
10841
10842 // Fast check: if hash code is computed for both strings
10843 // a fast negative check can be performed.
10844 if (HasHashCode() && other->HasHashCode()) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010845#ifdef ENABLE_SLOW_DCHECKS
Ben Murdochc7cc0282012-03-05 14:35:55 +000010846 if (FLAG_enable_slow_asserts) {
10847 if (Hash() != other->Hash()) {
10848 bool found_difference = false;
10849 for (int i = 0; i < len; i++) {
10850 if (Get(i) != other->Get(i)) {
10851 found_difference = true;
10852 break;
10853 }
10854 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010855 DCHECK(found_difference);
Ben Murdochc7cc0282012-03-05 14:35:55 +000010856 }
10857 }
10858#endif
Steve Blocka7e24c12009-10-30 11:49:00 +000010859 if (Hash() != other->Hash()) return false;
10860 }
10861
Leon Clarkef7060e22010-06-03 12:02:55 +010010862 // We know the strings are both non-empty. Compare the first chars
10863 // before we try to flatten the strings.
10864 if (this->Get(0) != other->Get(0)) return false;
10865
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010866 if (IsSeqOneByteString() && other->IsSeqOneByteString()) {
10867 const uint8_t* str1 = SeqOneByteString::cast(this)->GetChars();
10868 const uint8_t* str2 = SeqOneByteString::cast(other)->GetChars();
10869 return CompareRawStringContents(str1, str2, len);
Steve Blocka7e24c12009-10-30 11:49:00 +000010870 }
10871
Emily Bernierd0a1eb72015-03-24 16:35:39 -040010872 StringComparator comparator;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010873 return comparator.Equals(this, other);
10874}
10875
10876
10877bool String::SlowEquals(Handle<String> one, Handle<String> two) {
10878 // Fast check: negative check with lengths.
10879 int one_length = one->length();
10880 if (one_length != two->length()) return false;
10881 if (one_length == 0) return true;
10882
10883 // Fast check: if hash code is computed for both strings
10884 // a fast negative check can be performed.
10885 if (one->HasHashCode() && two->HasHashCode()) {
10886#ifdef ENABLE_SLOW_DCHECKS
10887 if (FLAG_enable_slow_asserts) {
10888 if (one->Hash() != two->Hash()) {
10889 bool found_difference = false;
10890 for (int i = 0; i < one_length; i++) {
10891 if (one->Get(i) != two->Get(i)) {
10892 found_difference = true;
10893 break;
10894 }
Steve Blocka7e24c12009-10-30 11:49:00 +000010895 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010896 DCHECK(found_difference);
Steve Blocka7e24c12009-10-30 11:49:00 +000010897 }
10898 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010899#endif
10900 if (one->Hash() != two->Hash()) return false;
10901 }
10902
10903 // We know the strings are both non-empty. Compare the first chars
10904 // before we try to flatten the strings.
10905 if (one->Get(0) != two->Get(0)) return false;
10906
10907 one = String::Flatten(one);
10908 two = String::Flatten(two);
10909
10910 DisallowHeapAllocation no_gc;
10911 String::FlatContent flat1 = one->GetFlatContent();
10912 String::FlatContent flat2 = two->GetFlatContent();
10913
10914 if (flat1.IsOneByte() && flat2.IsOneByte()) {
10915 return CompareRawStringContents(flat1.ToOneByteVector().start(),
10916 flat2.ToOneByteVector().start(),
10917 one_length);
Steve Blocka7e24c12009-10-30 11:49:00 +000010918 } else {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010919 for (int i = 0; i < one_length; i++) {
10920 if (flat1.Get(i) != flat2.Get(i)) return false;
10921 }
10922 return true;
Steve Blocka7e24c12009-10-30 11:49:00 +000010923 }
10924}
10925
10926
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000010927// static
10928ComparisonResult String::Compare(Handle<String> x, Handle<String> y) {
10929 // A few fast case tests before we flatten.
10930 if (x.is_identical_to(y)) {
10931 return ComparisonResult::kEqual;
10932 } else if (y->length() == 0) {
10933 return x->length() == 0 ? ComparisonResult::kEqual
10934 : ComparisonResult::kGreaterThan;
10935 } else if (x->length() == 0) {
10936 return ComparisonResult::kLessThan;
Steve Blocka7e24c12009-10-30 11:49:00 +000010937 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000010938
10939 int const d = x->Get(0) - y->Get(0);
10940 if (d < 0) {
10941 return ComparisonResult::kLessThan;
10942 } else if (d > 0) {
10943 return ComparisonResult::kGreaterThan;
10944 }
10945
10946 // Slow case.
10947 x = String::Flatten(x);
10948 y = String::Flatten(y);
10949
10950 DisallowHeapAllocation no_gc;
10951 ComparisonResult result = ComparisonResult::kEqual;
10952 int prefix_length = x->length();
10953 if (y->length() < prefix_length) {
10954 prefix_length = y->length();
10955 result = ComparisonResult::kGreaterThan;
10956 } else if (y->length() > prefix_length) {
10957 result = ComparisonResult::kLessThan;
10958 }
10959 int r;
10960 String::FlatContent x_content = x->GetFlatContent();
10961 String::FlatContent y_content = y->GetFlatContent();
10962 if (x_content.IsOneByte()) {
10963 Vector<const uint8_t> x_chars = x_content.ToOneByteVector();
10964 if (y_content.IsOneByte()) {
10965 Vector<const uint8_t> y_chars = y_content.ToOneByteVector();
10966 r = CompareChars(x_chars.start(), y_chars.start(), prefix_length);
10967 } else {
10968 Vector<const uc16> y_chars = y_content.ToUC16Vector();
10969 r = CompareChars(x_chars.start(), y_chars.start(), prefix_length);
10970 }
10971 } else {
10972 Vector<const uc16> x_chars = x_content.ToUC16Vector();
10973 if (y_content.IsOneByte()) {
10974 Vector<const uint8_t> y_chars = y_content.ToOneByteVector();
10975 r = CompareChars(x_chars.start(), y_chars.start(), prefix_length);
10976 } else {
10977 Vector<const uc16> y_chars = y_content.ToUC16Vector();
10978 r = CompareChars(x_chars.start(), y_chars.start(), prefix_length);
10979 }
10980 }
10981 if (r < 0) {
10982 result = ComparisonResult::kLessThan;
10983 } else if (r > 0) {
10984 result = ComparisonResult::kGreaterThan;
10985 }
10986 return result;
Steve Blocka7e24c12009-10-30 11:49:00 +000010987}
10988
10989
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010990bool String::IsUtf8EqualTo(Vector<const char> str, bool allow_prefix_match) {
Steve Blocka7e24c12009-10-30 11:49:00 +000010991 int slen = length();
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010992 // Can't check exact length equality, but we can check bounds.
10993 int str_len = str.length();
10994 if (!allow_prefix_match &&
10995 (str_len < slen ||
10996 str_len > slen*static_cast<int>(unibrow::Utf8::kMaxEncodedSize))) {
10997 return false;
10998 }
Steve Blocka7e24c12009-10-30 11:49:00 +000010999 int i;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000011000 size_t remaining_in_str = static_cast<size_t>(str_len);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011001 const uint8_t* utf8_data = reinterpret_cast<const uint8_t*>(str.start());
11002 for (i = 0; i < slen && remaining_in_str > 0; i++) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000011003 size_t cursor = 0;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011004 uint32_t r = unibrow::Utf8::ValueOf(utf8_data, remaining_in_str, &cursor);
11005 DCHECK(cursor > 0 && cursor <= remaining_in_str);
Ben Murdoch3ef787d2012-04-12 10:51:47 +010011006 if (r > unibrow::Utf16::kMaxNonSurrogateCharCode) {
11007 if (i > slen - 1) return false;
11008 if (Get(i++) != unibrow::Utf16::LeadSurrogate(r)) return false;
11009 if (Get(i) != unibrow::Utf16::TrailSurrogate(r)) return false;
11010 } else {
11011 if (Get(i) != r) return false;
11012 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011013 utf8_data += cursor;
11014 remaining_in_str -= cursor;
Steve Blocka7e24c12009-10-30 11:49:00 +000011015 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011016 return (allow_prefix_match || i == slen) && remaining_in_str == 0;
Steve Blocka7e24c12009-10-30 11:49:00 +000011017}
11018
11019
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011020bool String::IsOneByteEqualTo(Vector<const uint8_t> str) {
Steve Block9fac8402011-05-12 15:51:54 +010011021 int slen = length();
11022 if (str.length() != slen) return false;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011023 DisallowHeapAllocation no_gc;
Ben Murdoch69a99ed2011-11-30 16:03:39 +000011024 FlatContent content = GetFlatContent();
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011025 if (content.IsOneByte()) {
11026 return CompareChars(content.ToOneByteVector().start(),
Ben Murdoch69a99ed2011-11-30 16:03:39 +000011027 str.start(), slen) == 0;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000011028 }
11029 for (int i = 0; i < slen; i++) {
11030 if (Get(i) != static_cast<uint16_t>(str[i])) return false;
Steve Block9fac8402011-05-12 15:51:54 +010011031 }
11032 return true;
11033}
11034
11035
11036bool String::IsTwoByteEqualTo(Vector<const uc16> str) {
11037 int slen = length();
11038 if (str.length() != slen) return false;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011039 DisallowHeapAllocation no_gc;
Ben Murdoch69a99ed2011-11-30 16:03:39 +000011040 FlatContent content = GetFlatContent();
11041 if (content.IsTwoByte()) {
11042 return CompareChars(content.ToUC16Vector().start(), str.start(), slen) == 0;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000011043 }
Steve Block9fac8402011-05-12 15:51:54 +010011044 for (int i = 0; i < slen; i++) {
11045 if (Get(i) != str[i]) return false;
11046 }
11047 return true;
11048}
11049
11050
Steve Blocka7e24c12009-10-30 11:49:00 +000011051uint32_t String::ComputeAndSetHash() {
11052 // Should only be called if hash code has not yet been computed.
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011053 DCHECK(!HasHashCode());
Steve Blocka7e24c12009-10-30 11:49:00 +000011054
11055 // Store the hash code in the object.
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011056 uint32_t field = IteratingStringHasher::Hash(this, GetHeap()->HashSeed());
Steve Blockd0582a62009-12-15 09:54:21 +000011057 set_hash_field(field);
Steve Blocka7e24c12009-10-30 11:49:00 +000011058
11059 // Check the hash code is there.
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011060 DCHECK(HasHashCode());
Steve Blocka7e24c12009-10-30 11:49:00 +000011061 uint32_t result = field >> kHashShift;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011062 DCHECK(result != 0); // Ensure that the hash value of 0 is never computed.
Steve Blocka7e24c12009-10-30 11:49:00 +000011063 return result;
11064}
11065
11066
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011067bool String::ComputeArrayIndex(uint32_t* index) {
11068 int length = this->length();
Steve Blocka7e24c12009-10-30 11:49:00 +000011069 if (length == 0 || length > kMaxArrayIndexSize) return false;
Emily Bernierd0a1eb72015-03-24 16:35:39 -040011070 StringCharacterStream stream(this);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011071 return StringToArrayIndex(&stream, index);
Steve Blocka7e24c12009-10-30 11:49:00 +000011072}
11073
11074
11075bool String::SlowAsArrayIndex(uint32_t* index) {
11076 if (length() <= kMaxCachedArrayIndexLength) {
11077 Hash(); // force computation of hash code
Steve Blockd0582a62009-12-15 09:54:21 +000011078 uint32_t field = hash_field();
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +010011079 if ((field & kIsNotArrayIndexMask) != 0) return false;
Steve Blockd0582a62009-12-15 09:54:21 +000011080 // Isolate the array index form the full hash field.
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011081 *index = ArrayIndexValueBits::decode(field);
Steve Blocka7e24c12009-10-30 11:49:00 +000011082 return true;
11083 } else {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011084 return ComputeArrayIndex(index);
Steve Blocka7e24c12009-10-30 11:49:00 +000011085 }
11086}
11087
11088
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011089Handle<String> SeqString::Truncate(Handle<SeqString> string, int new_length) {
11090 int new_size, old_size;
11091 int old_length = string->length();
11092 if (old_length <= new_length) return string;
11093
11094 if (string->IsSeqOneByteString()) {
11095 old_size = SeqOneByteString::SizeFor(old_length);
11096 new_size = SeqOneByteString::SizeFor(new_length);
11097 } else {
11098 DCHECK(string->IsSeqTwoByteString());
11099 old_size = SeqTwoByteString::SizeFor(old_length);
11100 new_size = SeqTwoByteString::SizeFor(new_length);
11101 }
11102
11103 int delta = old_size - new_size;
11104
11105 Address start_of_string = string->address();
11106 DCHECK_OBJECT_ALIGNED(start_of_string);
11107 DCHECK_OBJECT_ALIGNED(start_of_string + new_size);
11108
11109 Heap* heap = string->GetHeap();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000011110 // Sizes are pointer size aligned, so that we can use filler objects
11111 // that are a multiple of pointer size.
Ben Murdochda12d292016-06-02 14:46:10 +010011112 heap->CreateFillerObjectAt(start_of_string + new_size, delta,
11113 ClearRecordedSlots::kNo);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000011114 heap->AdjustLiveBytes(*string, -delta, Heap::CONCURRENT_TO_SWEEPER);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011115
11116 // We are storing the new length using release store after creating a filler
11117 // for the left-over space to avoid races with the sweeper thread.
11118 string->synchronized_set_length(new_length);
11119
11120 if (new_length == 0) return heap->isolate()->factory()->empty_string();
11121 return string;
11122}
11123
11124
Iain Merrick9ac36c92010-09-13 15:29:50 +010011125uint32_t StringHasher::MakeArrayIndexHash(uint32_t value, int length) {
Kristian Monsen80d68ea2010-09-08 11:05:35 +010011126 // For array indexes mix the length into the hash as an array index could
11127 // be zero.
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011128 DCHECK(length > 0);
11129 DCHECK(length <= String::kMaxArrayIndexSize);
11130 DCHECK(TenToThe(String::kMaxCachedArrayIndexLength) <
Kristian Monsen80d68ea2010-09-08 11:05:35 +010011131 (1 << String::kArrayIndexValueBits));
Iain Merrick9ac36c92010-09-13 15:29:50 +010011132
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011133 value <<= String::ArrayIndexValueBits::kShift;
11134 value |= length << String::ArrayIndexLengthBits::kShift;
Iain Merrick9ac36c92010-09-13 15:29:50 +010011135
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011136 DCHECK((value & String::kIsNotArrayIndexMask) == 0);
11137 DCHECK((length > String::kMaxCachedArrayIndexLength) ||
Iain Merrick9ac36c92010-09-13 15:29:50 +010011138 (value & String::kContainsCachedArrayIndexMask) == 0);
Kristian Monsen80d68ea2010-09-08 11:05:35 +010011139 return value;
Steve Blocka7e24c12009-10-30 11:49:00 +000011140}
11141
11142
11143uint32_t StringHasher::GetHashField() {
Steve Blockd0582a62009-12-15 09:54:21 +000011144 if (length_ <= String::kMaxHashCalcLength) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011145 if (is_array_index_) {
11146 return MakeArrayIndexHash(array_index_, length_);
Steve Blocka7e24c12009-10-30 11:49:00 +000011147 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011148 return (GetHashCore(raw_running_hash_) << String::kHashShift) |
11149 String::kIsNotArrayIndexMask;
Steve Blocka7e24c12009-10-30 11:49:00 +000011150 } else {
Kristian Monsen80d68ea2010-09-08 11:05:35 +010011151 return (length_ << String::kHashShift) | String::kIsNotArrayIndexMask;
Steve Blocka7e24c12009-10-30 11:49:00 +000011152 }
11153}
11154
11155
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011156uint32_t StringHasher::ComputeUtf8Hash(Vector<const char> chars,
11157 uint32_t seed,
11158 int* utf16_length_out) {
11159 int vector_length = chars.length();
11160 // Handle some edge cases
11161 if (vector_length <= 1) {
11162 DCHECK(vector_length == 0 ||
11163 static_cast<uint8_t>(chars.start()[0]) <=
11164 unibrow::Utf8::kMaxOneByteChar);
11165 *utf16_length_out = vector_length;
11166 return HashSequentialString(chars.start(), vector_length, seed);
Steve Blocka7e24c12009-10-30 11:49:00 +000011167 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011168 // Start with a fake length which won't affect computation.
11169 // It will be updated later.
11170 StringHasher hasher(String::kMaxArrayIndexSize, seed);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000011171 size_t remaining = static_cast<size_t>(vector_length);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011172 const uint8_t* stream = reinterpret_cast<const uint8_t*>(chars.start());
11173 int utf16_length = 0;
11174 bool is_index = true;
11175 DCHECK(hasher.is_array_index_);
11176 while (remaining > 0) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000011177 size_t consumed = 0;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011178 uint32_t c = unibrow::Utf8::ValueOf(stream, remaining, &consumed);
11179 DCHECK(consumed > 0 && consumed <= remaining);
11180 stream += consumed;
11181 remaining -= consumed;
11182 bool is_two_characters = c > unibrow::Utf16::kMaxNonSurrogateCharCode;
11183 utf16_length += is_two_characters ? 2 : 1;
11184 // No need to keep hashing. But we do need to calculate utf16_length.
11185 if (utf16_length > String::kMaxHashCalcLength) continue;
11186 if (is_two_characters) {
11187 uint16_t c1 = unibrow::Utf16::LeadSurrogate(c);
11188 uint16_t c2 = unibrow::Utf16::TrailSurrogate(c);
11189 hasher.AddCharacter(c1);
11190 hasher.AddCharacter(c2);
11191 if (is_index) is_index = hasher.UpdateIndex(c1);
11192 if (is_index) is_index = hasher.UpdateIndex(c2);
11193 } else {
11194 hasher.AddCharacter(c);
11195 if (is_index) is_index = hasher.UpdateIndex(c);
11196 }
Steve Blocka7e24c12009-10-30 11:49:00 +000011197 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011198 *utf16_length_out = static_cast<int>(utf16_length);
11199 // Must set length here so that hash computation is correct.
11200 hasher.length_ = utf16_length;
Steve Blocka7e24c12009-10-30 11:49:00 +000011201 return hasher.GetHashField();
11202}
11203
11204
Emily Bernierd0a1eb72015-03-24 16:35:39 -040011205void IteratingStringHasher::VisitConsString(ConsString* cons_string) {
11206 // Run small ConsStrings through ConsStringIterator.
11207 if (cons_string->length() < 64) {
11208 ConsStringIterator iter(cons_string);
11209 int offset;
11210 String* string;
11211 while (nullptr != (string = iter.Next(&offset))) {
11212 DCHECK_EQ(0, offset);
11213 String::VisitFlat(this, string, 0);
11214 }
11215 return;
11216 }
11217 // Slow case.
11218 const int max_length = String::kMaxHashCalcLength;
11219 int length = std::min(cons_string->length(), max_length);
11220 if (cons_string->HasOnlyOneByteChars()) {
11221 uint8_t* buffer = new uint8_t[length];
11222 String::WriteToFlat(cons_string, buffer, 0, length);
11223 AddCharacters(buffer, length);
11224 delete[] buffer;
11225 } else {
11226 uint16_t* buffer = new uint16_t[length];
11227 String::WriteToFlat(cons_string, buffer, 0, length);
11228 AddCharacters(buffer, length);
11229 delete[] buffer;
11230 }
11231}
11232
11233
Steve Blocka7e24c12009-10-30 11:49:00 +000011234void String::PrintOn(FILE* file) {
11235 int length = this->length();
11236 for (int i = 0; i < length; i++) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011237 PrintF(file, "%c", Get(i));
Steve Blocka7e24c12009-10-30 11:49:00 +000011238 }
11239}
11240
11241
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000011242int Map::Hash() {
11243 // For performance reasons we only hash the 3 most variable fields of a map:
Emily Bernierd0a1eb72015-03-24 16:35:39 -040011244 // constructor, prototype and bit_field2. For predictability reasons we
11245 // use objects' offsets in respective pages for hashing instead of raw
11246 // addresses.
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000011247
11248 // Shift away the tag.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000011249 int hash = ObjectAddressForHashing(GetConstructor()) >> 2;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000011250
11251 // XOR-ing the prototype and constructor directly yields too many zero bits
11252 // when the two pointers are close (which is fairly common).
Emily Bernierd0a1eb72015-03-24 16:35:39 -040011253 // To avoid this we shift the prototype bits relatively to the constructor.
11254 hash ^= ObjectAddressForHashing(prototype()) << (32 - kPageSizeBits);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000011255
11256 return hash ^ (hash >> 16) ^ bit_field2();
11257}
11258
11259
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000011260namespace {
11261
11262bool CheckEquivalent(Map* first, Map* second) {
11263 return first->GetConstructor() == second->GetConstructor() &&
11264 first->prototype() == second->prototype() &&
11265 first->instance_type() == second->instance_type() &&
11266 first->bit_field() == second->bit_field() &&
11267 first->is_extensible() == second->is_extensible() &&
Ben Murdoch097c5b22016-05-18 11:27:45 +010011268 first->new_target_is_base() == second->new_target_is_base() &&
11269 first->has_hidden_prototype() == second->has_hidden_prototype();
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011270}
11271
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000011272} // namespace
11273
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011274
11275bool Map::EquivalentToForTransition(Map* other) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000011276 if (!CheckEquivalent(this, other)) return false;
11277 if (instance_type() == JS_FUNCTION_TYPE) {
11278 // JSFunctions require more checks to ensure that sloppy function is
11279 // not equvalent to strict function.
11280 int nof = Min(NumberOfOwnDescriptors(), other->NumberOfOwnDescriptors());
11281 return instance_descriptors()->IsEqualUpTo(other->instance_descriptors(),
11282 nof);
11283 }
11284 return true;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011285}
11286
11287
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000011288bool Map::EquivalentToForNormalization(Map* other,
11289 PropertyNormalizationMode mode) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000011290 int properties =
11291 mode == CLEAR_INOBJECT_PROPERTIES ? 0 : other->GetInObjectProperties();
11292 return CheckEquivalent(this, other) && bit_field2() == other->bit_field2() &&
11293 GetInObjectProperties() == properties;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011294}
11295
11296
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000011297bool JSFunction::Inlines(SharedFunctionInfo* candidate) {
11298 DisallowHeapAllocation no_gc;
11299 if (shared() == candidate) return true;
11300 if (code()->kind() != Code::OPTIMIZED_FUNCTION) return false;
11301 DeoptimizationInputData* const data =
11302 DeoptimizationInputData::cast(code()->deoptimization_data());
11303 if (data->length() == 0) return false;
11304 FixedArray* const literals = data->LiteralArray();
11305 int const inlined_count = data->InlinedFunctionCount()->value();
11306 for (int i = 0; i < inlined_count; ++i) {
11307 if (SharedFunctionInfo::cast(literals->get(i)) == candidate) {
11308 return true;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011309 }
11310 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000011311 return false;
Steve Block791712a2010-08-27 10:21:07 +010011312}
11313
Ben Murdochc5610432016-08-08 18:44:38 +010011314void JSFunction::MarkForBaseline() {
11315 Isolate* isolate = GetIsolate();
11316 set_code_no_write_barrier(
11317 isolate->builtins()->builtin(Builtins::kCompileBaseline));
11318 // No write barrier required, since the builtin is part of the root set.
11319}
Steve Block791712a2010-08-27 10:21:07 +010011320
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011321void JSFunction::MarkForOptimization() {
Emily Bernierd0a1eb72015-03-24 16:35:39 -040011322 Isolate* isolate = GetIsolate();
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011323 DCHECK(!IsOptimized());
11324 DCHECK(shared()->allows_lazy_compilation() ||
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000011325 !shared()->optimization_disabled());
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011326 set_code_no_write_barrier(
Emily Bernierd0a1eb72015-03-24 16:35:39 -040011327 isolate->builtins()->builtin(Builtins::kCompileOptimized));
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011328 // No write barrier required, since the builtin is part of the root set.
Ben Murdochb0fe1622011-05-05 13:52:32 +010011329}
11330
11331
Emily Bernierd0a1eb72015-03-24 16:35:39 -040011332void JSFunction::AttemptConcurrentOptimization() {
11333 Isolate* isolate = GetIsolate();
11334 if (!isolate->concurrent_recompilation_enabled() ||
11335 isolate->bootstrapper()->IsActive()) {
11336 MarkForOptimization();
11337 return;
11338 }
Emily Bernierd0a1eb72015-03-24 16:35:39 -040011339 DCHECK(!IsInOptimizationQueue());
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011340 DCHECK(!IsOptimized());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000011341 DCHECK(shared()->allows_lazy_compilation() ||
11342 !shared()->optimization_disabled());
Emily Bernierd0a1eb72015-03-24 16:35:39 -040011343 DCHECK(isolate->concurrent_recompilation_enabled());
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011344 if (FLAG_trace_concurrent_recompilation) {
11345 PrintF(" ** Marking ");
11346 ShortPrint();
11347 PrintF(" for concurrent recompilation.\n");
Ben Murdoch3ef787d2012-04-12 10:51:47 +010011348 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011349 set_code_no_write_barrier(
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000011350 isolate->builtins()->builtin(Builtins::kCompileOptimizedConcurrent));
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011351 // No write barrier required, since the builtin is part of the root set.
Ben Murdoch3ef787d2012-04-12 10:51:47 +010011352}
11353
11354
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000011355void SharedFunctionInfo::AddSharedCodeToOptimizedCodeMap(
11356 Handle<SharedFunctionInfo> shared, Handle<Code> code) {
11357 Isolate* isolate = shared->GetIsolate();
11358 if (isolate->serializer_enabled()) return;
11359 DCHECK(code->kind() == Code::OPTIMIZED_FUNCTION);
11360 // Empty code maps are unsupported.
11361 if (!shared->OptimizedCodeMapIsCleared()) {
11362 Handle<WeakCell> cell = isolate->factory()->NewWeakCell(code);
11363 // A collection may have occured and cleared the optimized code map in the
11364 // allocation above.
11365 if (!shared->OptimizedCodeMapIsCleared()) {
11366 shared->optimized_code_map()->set(kSharedCodeIndex, *cell);
11367 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011368 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011369}
11370
Ben Murdochda12d292016-06-02 14:46:10 +010011371// static
11372void SharedFunctionInfo::AddToOptimizedCodeMap(
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000011373 Handle<SharedFunctionInfo> shared, Handle<Context> native_context,
Ben Murdochda12d292016-06-02 14:46:10 +010011374 MaybeHandle<Code> code, Handle<LiteralsArray> literals,
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011375 BailoutId osr_ast_id) {
11376 Isolate* isolate = shared->GetIsolate();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000011377 if (isolate->serializer_enabled()) return;
Ben Murdochda12d292016-06-02 14:46:10 +010011378 DCHECK(code.is_null() ||
11379 code.ToHandleChecked()->kind() == Code::OPTIMIZED_FUNCTION);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011380 DCHECK(native_context->IsNativeContext());
11381 STATIC_ASSERT(kEntryLength == 4);
11382 Handle<FixedArray> new_code_map;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000011383 int entry;
11384
11385 if (shared->OptimizedCodeMapIsCleared()) {
11386 new_code_map = isolate->factory()->NewFixedArray(kInitialLength, TENURED);
11387 new_code_map->set(kSharedCodeIndex, *isolate->factory()->empty_weak_cell(),
11388 SKIP_WRITE_BARRIER);
11389 entry = kEntriesStart;
Ben Murdoch3ef787d2012-04-12 10:51:47 +010011390 } else {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000011391 Handle<FixedArray> old_code_map(shared->optimized_code_map(), isolate);
11392 entry = shared->SearchOptimizedCodeMapEntry(*native_context, osr_ast_id);
11393 if (entry > kSharedCodeIndex) {
Ben Murdochda12d292016-06-02 14:46:10 +010011394 // Just set the code and literals of the entry.
11395 if (!code.is_null()) {
11396 Handle<WeakCell> code_cell =
11397 isolate->factory()->NewWeakCell(code.ToHandleChecked());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000011398 old_code_map->set(entry + kCachedCodeOffset, *code_cell);
11399 }
11400 Handle<WeakCell> literals_cell =
11401 isolate->factory()->NewWeakCell(literals);
11402 old_code_map->set(entry + kLiteralsOffset, *literals_cell);
11403 return;
11404 }
11405
11406 // Can we reuse an entry?
11407 DCHECK(entry < kEntriesStart);
11408 int length = old_code_map->length();
11409 for (int i = kEntriesStart; i < length; i += kEntryLength) {
11410 if (WeakCell::cast(old_code_map->get(i + kContextOffset))->cleared()) {
11411 new_code_map = old_code_map;
11412 entry = i;
11413 break;
11414 }
11415 }
11416
11417 if (entry < kEntriesStart) {
11418 // Copy old optimized code map and append one new entry.
11419 new_code_map = isolate->factory()->CopyFixedArrayAndGrow(
11420 old_code_map, kEntryLength, TENURED);
11421 // TODO(mstarzinger): Temporary workaround. The allocation above might
11422 // have flushed the optimized code map and the copy we created is full of
11423 // holes. For now we just give up on adding the entry and pretend it got
11424 // flushed.
11425 if (shared->OptimizedCodeMapIsCleared()) return;
11426 entry = old_code_map->length();
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011427 }
Ben Murdoch3ef787d2012-04-12 10:51:47 +010011428 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000011429
Ben Murdochda12d292016-06-02 14:46:10 +010011430 Handle<WeakCell> code_cell =
11431 code.is_null() ? isolate->factory()->empty_weak_cell()
11432 : isolate->factory()->NewWeakCell(code.ToHandleChecked());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000011433 Handle<WeakCell> literals_cell = isolate->factory()->NewWeakCell(literals);
11434 WeakCell* context_cell = native_context->self_weak_cell();
11435
11436 new_code_map->set(entry + kContextOffset, context_cell);
11437 new_code_map->set(entry + kCachedCodeOffset, *code_cell);
11438 new_code_map->set(entry + kLiteralsOffset, *literals_cell);
11439 new_code_map->set(entry + kOsrAstIdOffset, Smi::FromInt(osr_ast_id.ToInt()));
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011440
11441#ifdef DEBUG
11442 for (int i = kEntriesStart; i < new_code_map->length(); i += kEntryLength) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000011443 WeakCell* cell = WeakCell::cast(new_code_map->get(i + kContextOffset));
11444 DCHECK(cell->cleared() || cell->value()->IsNativeContext());
11445 cell = WeakCell::cast(new_code_map->get(i + kCachedCodeOffset));
11446 DCHECK(cell->cleared() ||
11447 (cell->value()->IsCode() &&
11448 Code::cast(cell->value())->kind() == Code::OPTIMIZED_FUNCTION));
11449 cell = WeakCell::cast(new_code_map->get(i + kLiteralsOffset));
11450 DCHECK(cell->cleared() || cell->value()->IsFixedArray());
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011451 DCHECK(new_code_map->get(i + kOsrAstIdOffset)->IsSmi());
11452 }
11453#endif
Ben Murdoch3ef787d2012-04-12 10:51:47 +010011454
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000011455 FixedArray* old_code_map = shared->optimized_code_map();
11456 if (old_code_map != *new_code_map) {
11457 shared->set_optimized_code_map(*new_code_map);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011458 }
Ben Murdochb0fe1622011-05-05 13:52:32 +010011459}
11460
11461
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011462void SharedFunctionInfo::ClearOptimizedCodeMap() {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000011463 FixedArray* cleared_map = GetHeap()->cleared_optimized_code_map();
11464 set_optimized_code_map(cleared_map, SKIP_WRITE_BARRIER);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011465}
11466
11467
11468void SharedFunctionInfo::EvictFromOptimizedCodeMap(Code* optimized_code,
11469 const char* reason) {
11470 DisallowHeapAllocation no_gc;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000011471 if (OptimizedCodeMapIsCleared()) return;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011472
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000011473 Heap* heap = GetHeap();
11474 FixedArray* code_map = optimized_code_map();
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011475 int dst = kEntriesStart;
11476 int length = code_map->length();
11477 for (int src = kEntriesStart; src < length; src += kEntryLength) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000011478 DCHECK(WeakCell::cast(code_map->get(src))->cleared() ||
11479 WeakCell::cast(code_map->get(src))->value()->IsNativeContext());
11480 if (WeakCell::cast(code_map->get(src + kCachedCodeOffset))->value() ==
11481 optimized_code) {
11482 BailoutId osr(Smi::cast(code_map->get(src + kOsrAstIdOffset))->value());
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011483 if (FLAG_trace_opt) {
11484 PrintF("[evicting entry from optimizing code map (%s) for ", reason);
11485 ShortPrint();
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011486 if (osr.IsNone()) {
11487 PrintF("]\n");
11488 } else {
11489 PrintF(" (osr ast id %d)]\n", osr.ToInt());
11490 }
11491 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000011492 if (!osr.IsNone()) {
11493 // Evict the src entry by not copying it to the dst entry.
11494 continue;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011495 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000011496 // In case of non-OSR entry just clear the code in order to proceed
11497 // sharing literals.
11498 code_map->set(src + kCachedCodeOffset, heap->empty_weak_cell(),
11499 SKIP_WRITE_BARRIER);
11500 }
11501
11502 // Keep the src entry by copying it to the dst entry.
11503 if (dst != src) {
11504 code_map->set(dst + kContextOffset, code_map->get(src + kContextOffset));
11505 code_map->set(dst + kCachedCodeOffset,
11506 code_map->get(src + kCachedCodeOffset));
11507 code_map->set(dst + kLiteralsOffset,
11508 code_map->get(src + kLiteralsOffset));
11509 code_map->set(dst + kOsrAstIdOffset,
11510 code_map->get(src + kOsrAstIdOffset));
11511 }
11512 dst += kEntryLength;
11513 }
11514 if (WeakCell::cast(code_map->get(kSharedCodeIndex))->value() ==
11515 optimized_code) {
11516 // Evict context-independent code as well.
11517 code_map->set(kSharedCodeIndex, heap->empty_weak_cell(),
11518 SKIP_WRITE_BARRIER);
11519 if (FLAG_trace_opt) {
11520 PrintF("[evicting entry from optimizing code map (%s) for ", reason);
11521 ShortPrint();
11522 PrintF(" (context-independent code)]\n");
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011523 }
11524 }
11525 if (dst != length) {
11526 // Always trim even when array is cleared because of heap verifier.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000011527 heap->RightTrimFixedArray<Heap::CONCURRENT_TO_SWEEPER>(code_map,
11528 length - dst);
11529 if (code_map->length() == kEntriesStart &&
11530 WeakCell::cast(code_map->get(kSharedCodeIndex))->cleared()) {
11531 ClearOptimizedCodeMap();
11532 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011533 }
11534}
11535
11536
11537void SharedFunctionInfo::TrimOptimizedCodeMap(int shrink_by) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000011538 FixedArray* code_map = optimized_code_map();
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011539 DCHECK(shrink_by % kEntryLength == 0);
11540 DCHECK(shrink_by <= code_map->length() - kEntriesStart);
11541 // Always trim even when array is cleared because of heap verifier.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000011542 GetHeap()->RightTrimFixedArray<Heap::SEQUENTIAL_TO_SWEEPER>(code_map,
11543 shrink_by);
11544 if (code_map->length() == kEntriesStart &&
11545 WeakCell::cast(code_map->get(kSharedCodeIndex))->cleared()) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011546 ClearOptimizedCodeMap();
11547 }
11548}
11549
11550
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000011551static void GetMinInobjectSlack(Map* map, void* data) {
11552 int slack = map->unused_property_fields();
11553 if (*reinterpret_cast<int*>(data) > slack) {
11554 *reinterpret_cast<int*>(data) = slack;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011555 }
11556}
11557
11558
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000011559static void ShrinkInstanceSize(Map* map, void* data) {
11560 int slack = *reinterpret_cast<int*>(data);
11561 map->SetInObjectProperties(map->GetInObjectProperties() - slack);
11562 map->set_unused_property_fields(map->unused_property_fields() - slack);
11563 map->set_instance_size(map->instance_size() - slack * kPointerSize);
Ben Murdoch097c5b22016-05-18 11:27:45 +010011564 map->set_construction_counter(Map::kNoSlackTracking);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000011565
11566 // Visitor id might depend on the instance size, recalculate it.
11567 map->set_visitor_id(Heap::GetStaticVisitorIdForMap(map));
11568}
11569
Ben Murdoch097c5b22016-05-18 11:27:45 +010011570static void StopSlackTracking(Map* map, void* data) {
11571 map->set_construction_counter(Map::kNoSlackTracking);
11572}
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000011573
11574void Map::CompleteInobjectSlackTracking() {
11575 // Has to be an initial map.
11576 DCHECK(GetBackPointer()->IsUndefined());
11577
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000011578 int slack = unused_property_fields();
11579 TransitionArray::TraverseTransitionTree(this, &GetMinInobjectSlack, &slack);
11580 if (slack != 0) {
11581 // Resize the initial map and all maps in its transition tree.
11582 TransitionArray::TraverseTransitionTree(this, &ShrinkInstanceSize, &slack);
Ben Murdoch097c5b22016-05-18 11:27:45 +010011583 } else {
11584 TransitionArray::TraverseTransitionTree(this, &StopSlackTracking, nullptr);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000011585 }
11586}
11587
11588
11589static bool PrototypeBenefitsFromNormalization(Handle<JSObject> object) {
11590 DisallowHeapAllocation no_gc;
11591 if (!object->HasFastProperties()) return false;
11592 Map* map = object->map();
11593 if (map->is_prototype_map()) return false;
11594 DescriptorArray* descriptors = map->instance_descriptors();
11595 for (int i = 0; i < map->NumberOfOwnDescriptors(); i++) {
11596 PropertyDetails details = descriptors->GetDetails(i);
11597 if (details.location() == kDescriptor) continue;
11598 if (details.representation().IsHeapObject() ||
11599 details.representation().IsTagged()) {
11600 FieldIndex index = FieldIndex::ForDescriptor(map, i);
11601 if (object->RawFastPropertyAt(index)->IsJSFunction()) return true;
11602 }
11603 }
11604 return false;
11605}
11606
11607
11608// static
11609void JSObject::OptimizeAsPrototype(Handle<JSObject> object,
11610 PrototypeOptimizationMode mode) {
11611 if (object->IsJSGlobalObject()) return;
11612 if (mode == FAST_PROTOTYPE && PrototypeBenefitsFromNormalization(object)) {
11613 // First normalize to ensure all JSFunctions are DATA_CONSTANT.
11614 JSObject::NormalizeProperties(object, KEEP_INOBJECT_PROPERTIES, 0,
11615 "NormalizeAsPrototype");
11616 }
11617 Handle<Map> previous_map(object->map());
11618 if (!object->HasFastProperties()) {
11619 JSObject::MigrateSlowToFast(object, 0, "OptimizeAsPrototype");
11620 }
11621 if (!object->map()->is_prototype_map()) {
11622 if (object->map() == *previous_map) {
11623 Handle<Map> new_map = Map::Copy(handle(object->map()), "CopyAsPrototype");
11624 JSObject::MigrateToMap(object, new_map);
11625 }
11626 object->map()->set_is_prototype_map(true);
11627
11628 // Replace the pointer to the exact constructor with the Object function
11629 // from the same context if undetectable from JS. This is to avoid keeping
11630 // memory alive unnecessarily.
11631 Object* maybe_constructor = object->map()->GetConstructor();
11632 if (maybe_constructor->IsJSFunction()) {
11633 JSFunction* constructor = JSFunction::cast(maybe_constructor);
11634 Isolate* isolate = object->GetIsolate();
11635 if (!constructor->shared()->IsApiFunction() &&
11636 object->class_name() == isolate->heap()->Object_string()) {
11637 Context* context = constructor->context()->native_context();
11638 JSFunction* object_function = context->object_function();
11639 object->map()->SetConstructor(object_function);
11640 }
11641 }
11642 }
11643}
11644
11645
11646// static
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011647void JSObject::ReoptimizeIfPrototype(Handle<JSObject> object) {
11648 if (!object->map()->is_prototype_map()) return;
11649 OptimizeAsPrototype(object, FAST_PROTOTYPE);
11650}
11651
11652
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000011653// static
11654void JSObject::LazyRegisterPrototypeUser(Handle<Map> user, Isolate* isolate) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -040011655 DCHECK(FLAG_track_prototype_users);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000011656 // Contract: In line with InvalidatePrototypeChains()'s requirements,
11657 // leaf maps don't need to register as users, only prototypes do.
11658 DCHECK(user->is_prototype_map());
Emily Bernierd0a1eb72015-03-24 16:35:39 -040011659
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000011660 Handle<Map> current_user = user;
11661 Handle<PrototypeInfo> current_user_info =
11662 Map::GetOrCreatePrototypeInfo(user, isolate);
11663 for (PrototypeIterator iter(user); !iter.IsAtEnd(); iter.Advance()) {
11664 // Walk up the prototype chain as far as links haven't been registered yet.
11665 if (current_user_info->registry_slot() != PrototypeInfo::UNREGISTERED) {
11666 break;
11667 }
11668 Handle<Object> maybe_proto = PrototypeIterator::GetCurrent(iter);
11669 // Proxies on the prototype chain are not supported. They make it
11670 // impossible to make any assumptions about the prototype chain anyway.
11671 if (maybe_proto->IsJSProxy()) return;
11672 Handle<JSObject> proto = Handle<JSObject>::cast(maybe_proto);
11673 Handle<PrototypeInfo> proto_info =
11674 Map::GetOrCreatePrototypeInfo(proto, isolate);
11675 Handle<Object> maybe_registry(proto_info->prototype_users(), isolate);
11676 int slot = 0;
11677 Handle<WeakFixedArray> new_array =
11678 WeakFixedArray::Add(maybe_registry, current_user, &slot);
11679 current_user_info->set_registry_slot(slot);
11680 if (!maybe_registry.is_identical_to(new_array)) {
11681 proto_info->set_prototype_users(*new_array);
11682 }
11683 if (FLAG_trace_prototype_users) {
11684 PrintF("Registering %p as a user of prototype %p (map=%p).\n",
11685 reinterpret_cast<void*>(*current_user),
11686 reinterpret_cast<void*>(*proto),
11687 reinterpret_cast<void*>(proto->map()));
11688 }
Emily Bernierd0a1eb72015-03-24 16:35:39 -040011689
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000011690 current_user = handle(proto->map(), isolate);
11691 current_user_info = proto_info;
Emily Bernierd0a1eb72015-03-24 16:35:39 -040011692 }
11693}
11694
11695
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000011696// Can be called regardless of whether |user| was actually registered with
11697// |prototype|. Returns true when there was a registration.
11698// static
11699bool JSObject::UnregisterPrototypeUser(Handle<Map> user, Isolate* isolate) {
11700 DCHECK(user->is_prototype_map());
11701 // If it doesn't have a PrototypeInfo, it was never registered.
11702 if (!user->prototype_info()->IsPrototypeInfo()) return false;
11703 // If it had no prototype before, see if it had users that might expect
11704 // registration.
11705 if (!user->prototype()->IsJSObject()) {
11706 Object* users =
11707 PrototypeInfo::cast(user->prototype_info())->prototype_users();
11708 return users->IsWeakFixedArray();
11709 }
11710 Handle<JSObject> prototype(JSObject::cast(user->prototype()), isolate);
11711 Handle<PrototypeInfo> user_info =
11712 Map::GetOrCreatePrototypeInfo(user, isolate);
11713 int slot = user_info->registry_slot();
11714 if (slot == PrototypeInfo::UNREGISTERED) return false;
11715 DCHECK(prototype->map()->is_prototype_map());
11716 Object* maybe_proto_info = prototype->map()->prototype_info();
11717 // User knows its registry slot, prototype info and user registry must exist.
11718 DCHECK(maybe_proto_info->IsPrototypeInfo());
11719 Handle<PrototypeInfo> proto_info(PrototypeInfo::cast(maybe_proto_info),
11720 isolate);
11721 Object* maybe_registry = proto_info->prototype_users();
11722 DCHECK(maybe_registry->IsWeakFixedArray());
11723 DCHECK(WeakFixedArray::cast(maybe_registry)->Get(slot) == *user);
11724 WeakFixedArray::cast(maybe_registry)->Clear(slot);
11725 if (FLAG_trace_prototype_users) {
11726 PrintF("Unregistering %p as a user of prototype %p.\n",
11727 reinterpret_cast<void*>(*user), reinterpret_cast<void*>(*prototype));
11728 }
11729 return true;
Emily Bernierd0a1eb72015-03-24 16:35:39 -040011730}
11731
11732
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000011733static void InvalidatePrototypeChainsInternal(Map* map) {
11734 if (!map->is_prototype_map()) return;
11735 if (FLAG_trace_prototype_users) {
11736 PrintF("Invalidating prototype map %p 's cell\n",
11737 reinterpret_cast<void*>(map));
11738 }
11739 Object* maybe_proto_info = map->prototype_info();
11740 if (!maybe_proto_info->IsPrototypeInfo()) return;
11741 PrototypeInfo* proto_info = PrototypeInfo::cast(maybe_proto_info);
11742 Object* maybe_cell = proto_info->validity_cell();
11743 if (maybe_cell->IsCell()) {
11744 // Just set the value; the cell will be replaced lazily.
11745 Cell* cell = Cell::cast(maybe_cell);
11746 cell->set_value(Smi::FromInt(Map::kPrototypeChainInvalid));
11747 }
11748
11749 WeakFixedArray::Iterator iterator(proto_info->prototype_users());
11750 // For now, only maps register themselves as users.
11751 Map* user;
11752 while ((user = iterator.Next<Map>())) {
11753 // Walk the prototype chain (backwards, towards leaf objects) if necessary.
11754 InvalidatePrototypeChainsInternal(user);
11755 }
11756}
11757
11758
11759// static
11760void JSObject::InvalidatePrototypeChains(Map* map) {
11761 if (!FLAG_eliminate_prototype_chain_checks) return;
11762 DisallowHeapAllocation no_gc;
11763 InvalidatePrototypeChainsInternal(map);
11764}
11765
11766
11767// static
11768Handle<PrototypeInfo> Map::GetOrCreatePrototypeInfo(Handle<JSObject> prototype,
11769 Isolate* isolate) {
11770 Object* maybe_proto_info = prototype->map()->prototype_info();
11771 if (maybe_proto_info->IsPrototypeInfo()) {
11772 return handle(PrototypeInfo::cast(maybe_proto_info), isolate);
11773 }
11774 Handle<PrototypeInfo> proto_info = isolate->factory()->NewPrototypeInfo();
11775 prototype->map()->set_prototype_info(*proto_info);
11776 return proto_info;
11777}
11778
11779
11780// static
11781Handle<PrototypeInfo> Map::GetOrCreatePrototypeInfo(Handle<Map> prototype_map,
11782 Isolate* isolate) {
11783 Object* maybe_proto_info = prototype_map->prototype_info();
11784 if (maybe_proto_info->IsPrototypeInfo()) {
11785 return handle(PrototypeInfo::cast(maybe_proto_info), isolate);
11786 }
11787 Handle<PrototypeInfo> proto_info = isolate->factory()->NewPrototypeInfo();
11788 prototype_map->set_prototype_info(*proto_info);
11789 return proto_info;
11790}
11791
11792
11793// static
11794Handle<Cell> Map::GetOrCreatePrototypeChainValidityCell(Handle<Map> map,
11795 Isolate* isolate) {
11796 Handle<Object> maybe_prototype(map->prototype(), isolate);
11797 if (!maybe_prototype->IsJSObject()) return Handle<Cell>::null();
11798 Handle<JSObject> prototype = Handle<JSObject>::cast(maybe_prototype);
11799 // Ensure the prototype is registered with its own prototypes so its cell
11800 // will be invalidated when necessary.
11801 JSObject::LazyRegisterPrototypeUser(handle(prototype->map(), isolate),
11802 isolate);
11803 Handle<PrototypeInfo> proto_info =
11804 GetOrCreatePrototypeInfo(prototype, isolate);
11805 Object* maybe_cell = proto_info->validity_cell();
11806 // Return existing cell if it's still valid.
11807 if (maybe_cell->IsCell()) {
11808 Handle<Cell> cell(Cell::cast(maybe_cell), isolate);
11809 if (cell->value() == Smi::FromInt(Map::kPrototypeChainValid)) {
11810 return cell;
11811 }
11812 }
11813 // Otherwise create a new cell.
11814 Handle<Cell> cell = isolate->factory()->NewCell(
11815 handle(Smi::FromInt(Map::kPrototypeChainValid), isolate));
11816 proto_info->set_validity_cell(*cell);
11817 return cell;
11818}
11819
11820
11821// static
11822void Map::SetPrototype(Handle<Map> map, Handle<Object> prototype,
Emily Bernierd0a1eb72015-03-24 16:35:39 -040011823 PrototypeOptimizationMode proto_mode) {
Ben Murdochc5610432016-08-08 18:44:38 +010011824 RuntimeCallTimerScope stats_scope(*map, &RuntimeCallStats::Map_SetPrototype);
11825
Ben Murdoch097c5b22016-05-18 11:27:45 +010011826 bool is_hidden = false;
Emily Bernierd0a1eb72015-03-24 16:35:39 -040011827 if (prototype->IsJSObject()) {
11828 Handle<JSObject> prototype_jsobj = Handle<JSObject>::cast(prototype);
Emily Bernierd0a1eb72015-03-24 16:35:39 -040011829 JSObject::OptimizeAsPrototype(prototype_jsobj, proto_mode);
Ben Murdoch097c5b22016-05-18 11:27:45 +010011830
11831 Object* maybe_constructor = prototype_jsobj->map()->GetConstructor();
11832 if (maybe_constructor->IsJSFunction()) {
11833 JSFunction* constructor = JSFunction::cast(maybe_constructor);
11834 Object* data = constructor->shared()->function_data();
11835 is_hidden = (data->IsFunctionTemplateInfo() &&
11836 FunctionTemplateInfo::cast(data)->hidden_prototype()) ||
11837 prototype->IsJSGlobalObject();
11838 }
Emily Bernierd0a1eb72015-03-24 16:35:39 -040011839 }
Ben Murdoch097c5b22016-05-18 11:27:45 +010011840 map->set_has_hidden_prototype(is_hidden);
11841
Emily Bernierd0a1eb72015-03-24 16:35:39 -040011842 WriteBarrierMode wb_mode =
11843 prototype->IsNull() ? SKIP_WRITE_BARRIER : UPDATE_WRITE_BARRIER;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000011844 map->set_prototype(*prototype, wb_mode);
Emily Bernierd0a1eb72015-03-24 16:35:39 -040011845}
11846
11847
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011848Handle<Object> CacheInitialJSArrayMaps(
11849 Handle<Context> native_context, Handle<Map> initial_map) {
11850 // Replace all of the cached initial array maps in the native context with
11851 // the appropriate transitioned elements kind maps.
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011852 Handle<Map> current_map = initial_map;
11853 ElementsKind kind = current_map->elements_kind();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000011854 DCHECK_EQ(GetInitialFastElementsKind(), kind);
Ben Murdochda12d292016-06-02 14:46:10 +010011855 native_context->set(Context::ArrayMapIndex(kind), *current_map);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011856 for (int i = GetSequenceIndexFromFastElementsKind(kind) + 1;
11857 i < kFastElementsKindCount; ++i) {
11858 Handle<Map> new_map;
11859 ElementsKind next_kind = GetFastElementsKindFromSequenceIndex(i);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000011860 if (Map* maybe_elements_transition = current_map->ElementsTransitionMap()) {
11861 new_map = handle(maybe_elements_transition);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011862 } else {
11863 new_map = Map::CopyAsElementsKind(
11864 current_map, next_kind, INSERT_TRANSITION);
11865 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000011866 DCHECK_EQ(next_kind, new_map->elements_kind());
Ben Murdochda12d292016-06-02 14:46:10 +010011867 native_context->set(Context::ArrayMapIndex(next_kind), *new_map);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011868 current_map = new_map;
11869 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011870 return initial_map;
11871}
11872
11873
11874void JSFunction::SetInstancePrototype(Handle<JSFunction> function,
11875 Handle<Object> value) {
11876 Isolate* isolate = function->GetIsolate();
11877
11878 DCHECK(value->IsJSReceiver());
11879
11880 // Now some logic for the maps of the objects that are created by using this
11881 // function as a constructor.
11882 if (function->has_initial_map()) {
11883 // If the function has allocated the initial map replace it with a
11884 // copy containing the new prototype. Also complete any in-object
11885 // slack tracking that is in progress at this point because it is
11886 // still tracking the old copy.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000011887 function->CompleteInobjectSlackTrackingIfActive();
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011888
11889 Handle<Map> initial_map(function->initial_map(), isolate);
11890
11891 if (!initial_map->GetIsolate()->bootstrapper()->IsActive() &&
11892 initial_map->instance_type() == JS_OBJECT_TYPE) {
11893 // Put the value in the initial map field until an initial map is needed.
11894 // At that point, a new initial map is created and the prototype is put
11895 // into the initial map where it belongs.
11896 function->set_prototype_or_initial_map(*value);
11897 } else {
Emily Bernierd0a1eb72015-03-24 16:35:39 -040011898 Handle<Map> new_map = Map::Copy(initial_map, "SetInstancePrototype");
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011899 JSFunction::SetInitialMap(function, new_map, value);
11900
11901 // If the function is used as the global Array function, cache the
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000011902 // updated initial maps (and transitioned versions) in the native context.
11903 Handle<Context> native_context(function->context()->native_context(),
11904 isolate);
11905 Handle<Object> array_function(
11906 native_context->get(Context::ARRAY_FUNCTION_INDEX), isolate);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011907 if (array_function->IsJSFunction() &&
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000011908 *function == JSFunction::cast(*array_function)) {
11909 CacheInitialJSArrayMaps(native_context, new_map);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011910 }
11911 }
11912
11913 // Deoptimize all code that embeds the previous initial map.
11914 initial_map->dependent_code()->DeoptimizeDependentCodeGroup(
11915 isolate, DependentCode::kInitialMapChangedGroup);
Steve Blocka7e24c12009-10-30 11:49:00 +000011916 } else {
11917 // Put the value in the initial map field until an initial map is
11918 // needed. At that point, a new initial map is created and the
11919 // prototype is put into the initial map where it belongs.
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011920 function->set_prototype_or_initial_map(*value);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000011921 if (value->IsJSObject()) {
11922 // Optimize as prototype to detach it from its transition tree.
11923 JSObject::OptimizeAsPrototype(Handle<JSObject>::cast(value),
11924 FAST_PROTOTYPE);
11925 }
Steve Blocka7e24c12009-10-30 11:49:00 +000011926 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011927 isolate->heap()->ClearInstanceofCache();
Steve Blocka7e24c12009-10-30 11:49:00 +000011928}
11929
11930
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011931void JSFunction::SetPrototype(Handle<JSFunction> function,
11932 Handle<Object> value) {
Ben Murdoch097c5b22016-05-18 11:27:45 +010011933 DCHECK(function->IsConstructor() ||
11934 IsGeneratorFunction(function->shared()->kind()));
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011935 Handle<Object> construct_prototype = value;
Steve Blocka7e24c12009-10-30 11:49:00 +000011936
Ben Murdoch3ef787d2012-04-12 10:51:47 +010011937 // If the value is not a JSReceiver, store the value in the map's
Steve Blocka7e24c12009-10-30 11:49:00 +000011938 // constructor field so it can be accessed. Also, set the prototype
11939 // used for constructing objects to the original object prototype.
11940 // See ECMA-262 13.2.2.
Ben Murdoch3ef787d2012-04-12 10:51:47 +010011941 if (!value->IsJSReceiver()) {
Steve Blocka7e24c12009-10-30 11:49:00 +000011942 // Copy the map so this does not affect unrelated functions.
11943 // Remove map transitions because they point to maps with a
11944 // different prototype.
Emily Bernierd0a1eb72015-03-24 16:35:39 -040011945 Handle<Map> new_map = Map::Copy(handle(function->map()), "SetPrototype");
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011946
11947 JSObject::MigrateToMap(function, new_map);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000011948 new_map->SetConstructor(*value);
Ben Murdoch8b112d22011-06-08 16:22:53 +010011949 new_map->set_non_instance_prototype(true);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011950 Isolate* isolate = new_map->GetIsolate();
Ben Murdochc5610432016-08-08 18:44:38 +010011951
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011952 construct_prototype = handle(
Ben Murdochc5610432016-08-08 18:44:38 +010011953 IsGeneratorFunction(function->shared()->kind())
11954 ? function->context()
11955 ->native_context()
11956 ->initial_generator_prototype()
11957 : function->context()->native_context()->initial_object_prototype(),
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011958 isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +000011959 } else {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011960 function->map()->set_non_instance_prototype(false);
Steve Blocka7e24c12009-10-30 11:49:00 +000011961 }
11962
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011963 return SetInstancePrototype(function, construct_prototype);
Steve Blocka7e24c12009-10-30 11:49:00 +000011964}
11965
11966
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011967bool JSFunction::RemovePrototype() {
11968 Context* native_context = context()->native_context();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000011969 Map* no_prototype_map =
11970 is_strict(shared()->language_mode())
11971 ? native_context->strict_function_without_prototype_map()
11972 : native_context->sloppy_function_without_prototype_map();
Steve Block44f0eee2011-05-26 01:26:41 +010011973
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011974 if (map() == no_prototype_map) return true;
11975
11976#ifdef DEBUG
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000011977 if (map() != (is_strict(shared()->language_mode())
11978 ? native_context->strict_function_map()
11979 : native_context->sloppy_function_map())) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011980 return false;
Ben Murdoche0cee9b2011-05-25 10:26:03 +010011981 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011982#endif
Steve Block44f0eee2011-05-26 01:26:41 +010011983
11984 set_map(no_prototype_map);
Ben Murdoch3ef787d2012-04-12 10:51:47 +010011985 set_prototype_or_initial_map(no_prototype_map->GetHeap()->the_hole_value());
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011986 return true;
Steve Block6ded16b2010-05-10 14:33:55 +010011987}
11988
11989
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011990void JSFunction::SetInitialMap(Handle<JSFunction> function, Handle<Map> map,
11991 Handle<Object> prototype) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -040011992 if (map->prototype() != *prototype) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000011993 Map::SetPrototype(map, prototype, FAST_PROTOTYPE);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011994 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011995 function->set_prototype_or_initial_map(*map);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000011996 map->SetConstructor(*function);
Emily Bernierd0a1eb72015-03-24 16:35:39 -040011997#if TRACE_MAPS
11998 if (FLAG_trace_maps) {
11999 PrintF("[TraceMaps: InitialMap map= %p SFI= %d_%s ]\n",
12000 reinterpret_cast<void*>(*map), function->shared()->unique_id(),
12001 function->shared()->DebugName()->ToCString().get());
12002 }
12003#endif
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012004}
12005
12006
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000012007#ifdef DEBUG
12008namespace {
12009
12010bool CanSubclassHaveInobjectProperties(InstanceType instance_type) {
12011 switch (instance_type) {
Ben Murdochc5610432016-08-08 18:44:38 +010012012 case JS_API_OBJECT_TYPE:
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000012013 case JS_ARRAY_BUFFER_TYPE:
Ben Murdochc5610432016-08-08 18:44:38 +010012014 case JS_ARRAY_TYPE:
12015 case JS_CONTEXT_EXTENSION_OBJECT_TYPE:
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000012016 case JS_DATA_VIEW_TYPE:
Ben Murdochc5610432016-08-08 18:44:38 +010012017 case JS_DATE_TYPE:
12018 case JS_FUNCTION_TYPE:
12019 case JS_GENERATOR_OBJECT_TYPE:
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000012020 case JS_MAP_ITERATOR_TYPE:
Ben Murdochc5610432016-08-08 18:44:38 +010012021 case JS_MAP_TYPE:
12022 case JS_MESSAGE_OBJECT_TYPE:
12023 case JS_MODULE_TYPE:
12024 case JS_OBJECT_TYPE:
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000012025 case JS_PROMISE_TYPE:
12026 case JS_REGEXP_TYPE:
Ben Murdochc5610432016-08-08 18:44:38 +010012027 case JS_SET_ITERATOR_TYPE:
12028 case JS_SET_TYPE:
12029 case JS_SPECIAL_API_OBJECT_TYPE:
12030 case JS_TYPED_ARRAY_TYPE:
12031 case JS_VALUE_TYPE:
12032 case JS_WEAK_MAP_TYPE:
12033 case JS_WEAK_SET_TYPE:
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000012034 return true;
12035
Ben Murdochc5610432016-08-08 18:44:38 +010012036 case BYTECODE_ARRAY_TYPE:
12037 case BYTE_ARRAY_TYPE:
12038 case CELL_TYPE:
12039 case CODE_TYPE:
12040 case FILLER_TYPE:
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000012041 case FIXED_ARRAY_TYPE:
12042 case FIXED_DOUBLE_ARRAY_TYPE:
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000012043 case FOREIGN_TYPE:
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000012044 case FREE_SPACE_TYPE:
Ben Murdochc5610432016-08-08 18:44:38 +010012045 case HEAP_NUMBER_TYPE:
12046 case JS_BOUND_FUNCTION_TYPE:
12047 case JS_GLOBAL_OBJECT_TYPE:
12048 case JS_GLOBAL_PROXY_TYPE:
12049 case JS_PROXY_TYPE:
12050 case MAP_TYPE:
12051 case MUTABLE_HEAP_NUMBER_TYPE:
12052 case ODDBALL_TYPE:
12053 case PROPERTY_CELL_TYPE:
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000012054 case SHARED_FUNCTION_INFO_TYPE:
Ben Murdochc5610432016-08-08 18:44:38 +010012055 case SIMD128_VALUE_TYPE:
12056 case SYMBOL_TYPE:
12057 case WEAK_CELL_TYPE:
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000012058
12059#define TYPED_ARRAY_CASE(Type, type, TYPE, ctype, size) \
12060 case FIXED_##TYPE##_ARRAY_TYPE:
12061#undef TYPED_ARRAY_CASE
12062
12063#define MAKE_STRUCT_CASE(NAME, Name, name) case NAME##_TYPE:
12064 STRUCT_LIST(MAKE_STRUCT_CASE)
12065#undef MAKE_STRUCT_CASE
12066 // We must not end up here for these instance types at all.
12067 UNREACHABLE();
12068 // Fall through.
12069 default:
12070 return false;
12071 }
12072}
12073
12074} // namespace
12075#endif
12076
12077
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012078void JSFunction::EnsureHasInitialMap(Handle<JSFunction> function) {
Ben Murdochc5610432016-08-08 18:44:38 +010012079 DCHECK(function->IsConstructor() || function->shared()->is_resumable());
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012080 if (function->has_initial_map()) return;
12081 Isolate* isolate = function->GetIsolate();
12082
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000012083 // The constructor should be compiled for the optimization hints to be
12084 // available.
Ben Murdochda12d292016-06-02 14:46:10 +010012085 Compiler::Compile(function, Compiler::CLEAR_EXCEPTION);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000012086
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012087 // First create a new map with the size and number of in-object properties
12088 // suggested by the function.
12089 InstanceType instance_type;
Ben Murdochc5610432016-08-08 18:44:38 +010012090 if (function->shared()->is_resumable()) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012091 instance_type = JS_GENERATOR_OBJECT_TYPE;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012092 } else {
12093 instance_type = JS_OBJECT_TYPE;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012094 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000012095 int instance_size;
12096 int in_object_properties;
12097 function->CalculateInstanceSize(instance_type, 0, &instance_size,
12098 &in_object_properties);
12099
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012100 Handle<Map> map = isolate->factory()->NewMap(instance_type, instance_size);
12101
12102 // Fetch or allocate prototype.
12103 Handle<Object> prototype;
12104 if (function->has_instance_prototype()) {
12105 prototype = handle(function->instance_prototype(), isolate);
12106 } else {
12107 prototype = isolate->factory()->NewFunctionPrototype(function);
12108 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000012109 map->SetInObjectProperties(in_object_properties);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012110 map->set_unused_property_fields(in_object_properties);
12111 DCHECK(map->has_fast_object_elements());
12112
12113 // Finally link initial map and constructor function.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000012114 DCHECK(prototype->IsJSReceiver());
12115 JSFunction::SetInitialMap(function, map, prototype);
12116 map->StartInobjectSlackTracking();
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012117}
12118
12119
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000012120// static
12121MaybeHandle<Map> JSFunction::GetDerivedMap(Isolate* isolate,
12122 Handle<JSFunction> constructor,
12123 Handle<JSReceiver> new_target) {
12124 EnsureHasInitialMap(constructor);
12125
12126 Handle<Map> constructor_initial_map(constructor->initial_map(), isolate);
12127 if (*new_target == *constructor) return constructor_initial_map;
12128
12129 // Fast case, new.target is a subclass of constructor. The map is cacheable
12130 // (and may already have been cached). new.target.prototype is guaranteed to
12131 // be a JSReceiver.
12132 if (new_target->IsJSFunction()) {
12133 Handle<JSFunction> function = Handle<JSFunction>::cast(new_target);
12134
12135 // Check that |function|'s initial map still in sync with the |constructor|,
12136 // otherwise we must create a new initial map for |function|.
12137 if (function->has_initial_map() &&
12138 function->initial_map()->GetConstructor() == *constructor) {
12139 return handle(function->initial_map(), isolate);
12140 }
12141
12142 // Create a new map with the size and number of in-object properties
12143 // suggested by |function|.
12144
12145 // Link initial map and constructor function if the new.target is actually a
12146 // subclass constructor.
12147 if (IsSubclassConstructor(function->shared()->kind())) {
12148 Handle<Object> prototype(function->instance_prototype(), isolate);
12149 InstanceType instance_type = constructor_initial_map->instance_type();
12150 DCHECK(CanSubclassHaveInobjectProperties(instance_type));
12151 int internal_fields =
12152 JSObject::GetInternalFieldCount(*constructor_initial_map);
12153 int pre_allocated = constructor_initial_map->GetInObjectProperties() -
12154 constructor_initial_map->unused_property_fields();
12155 int instance_size;
12156 int in_object_properties;
12157 function->CalculateInstanceSizeForDerivedClass(
12158 instance_type, internal_fields, &instance_size,
12159 &in_object_properties);
12160
12161 int unused_property_fields = in_object_properties - pre_allocated;
12162 Handle<Map> map =
12163 Map::CopyInitialMap(constructor_initial_map, instance_size,
12164 in_object_properties, unused_property_fields);
12165 map->set_new_target_is_base(false);
12166
12167 JSFunction::SetInitialMap(function, map, prototype);
12168 map->SetConstructor(*constructor);
Ben Murdoch097c5b22016-05-18 11:27:45 +010012169 map->set_construction_counter(Map::kNoSlackTracking);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000012170 map->StartInobjectSlackTracking();
12171 return map;
12172 }
12173 }
12174
12175 // Slow path, new.target is either a proxy or can't cache the map.
12176 // new.target.prototype is not guaranteed to be a JSReceiver, and may need to
12177 // fall back to the intrinsicDefaultProto.
12178 Handle<Object> prototype;
12179 if (new_target->IsJSFunction()) {
12180 Handle<JSFunction> function = Handle<JSFunction>::cast(new_target);
12181 // Make sure the new.target.prototype is cached.
12182 EnsureHasInitialMap(function);
12183 prototype = handle(function->prototype(), isolate);
12184 } else {
12185 Handle<String> prototype_string = isolate->factory()->prototype_string();
12186 ASSIGN_RETURN_ON_EXCEPTION(
12187 isolate, prototype,
12188 JSReceiver::GetProperty(new_target, prototype_string), Map);
12189 // The above prototype lookup might change the constructor and its
12190 // prototype, hence we have to reload the initial map.
12191 EnsureHasInitialMap(constructor);
12192 constructor_initial_map = handle(constructor->initial_map(), isolate);
12193 }
12194
12195 // If prototype is not a JSReceiver, fetch the intrinsicDefaultProto from the
12196 // correct realm. Rather than directly fetching the .prototype, we fetch the
12197 // constructor that points to the .prototype. This relies on
12198 // constructor.prototype being FROZEN for those constructors.
12199 if (!prototype->IsJSReceiver()) {
12200 Handle<Context> context;
12201 ASSIGN_RETURN_ON_EXCEPTION(isolate, context,
12202 JSReceiver::GetFunctionRealm(new_target), Map);
12203 DCHECK(context->IsNativeContext());
12204 Handle<Object> maybe_index = JSReceiver::GetDataProperty(
12205 constructor, isolate->factory()->native_context_index_symbol());
12206 int index = maybe_index->IsSmi() ? Smi::cast(*maybe_index)->value()
12207 : Context::OBJECT_FUNCTION_INDEX;
12208 Handle<JSFunction> realm_constructor(JSFunction::cast(context->get(index)));
12209 prototype = handle(realm_constructor->prototype(), isolate);
12210 }
12211
12212 Handle<Map> map = Map::CopyInitialMap(constructor_initial_map);
12213 map->set_new_target_is_base(false);
12214 DCHECK(prototype->IsJSReceiver());
12215 if (map->prototype() != *prototype) {
12216 Map::SetPrototype(map, prototype, FAST_PROTOTYPE);
12217 }
12218 map->SetConstructor(*constructor);
12219 return map;
Steve Blocka7e24c12009-10-30 11:49:00 +000012220}
12221
12222
Ben Murdochb0fe1622011-05-05 13:52:32 +010012223void JSFunction::PrintName(FILE* out) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000012224 base::SmartArrayPointer<char> name = shared()->DebugName()->ToCString();
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012225 PrintF(out, "%s", name.get());
Ben Murdochb0fe1622011-05-05 13:52:32 +010012226}
12227
12228
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000012229Handle<String> JSFunction::GetName(Handle<JSFunction> function) {
12230 Isolate* isolate = function->GetIsolate();
12231 Handle<Object> name =
12232 JSReceiver::GetDataProperty(function, isolate->factory()->name_string());
12233 if (name->IsString()) return Handle<String>::cast(name);
12234 return handle(function->shared()->DebugName(), isolate);
12235}
12236
12237
12238Handle<String> JSFunction::GetDebugName(Handle<JSFunction> function) {
12239 Isolate* isolate = function->GetIsolate();
12240 Handle<Object> name = JSReceiver::GetDataProperty(
12241 function, isolate->factory()->display_name_string());
12242 if (name->IsString()) return Handle<String>::cast(name);
12243 return JSFunction::GetName(function);
12244}
12245
Ben Murdoch097c5b22016-05-18 11:27:45 +010012246void JSFunction::SetName(Handle<JSFunction> function, Handle<Name> name,
12247 Handle<String> prefix) {
12248 Isolate* isolate = function->GetIsolate();
12249 Handle<String> function_name = Name::ToFunctionName(name).ToHandleChecked();
12250 if (prefix->length() > 0) {
12251 IncrementalStringBuilder builder(isolate);
12252 builder.AppendString(prefix);
12253 builder.AppendCharacter(' ');
12254 builder.AppendString(function_name);
12255 function_name = builder.Finish().ToHandleChecked();
12256 }
12257 JSObject::DefinePropertyOrElementIgnoreAttributes(
12258 function, isolate->factory()->name_string(), function_name,
12259 static_cast<PropertyAttributes>(DONT_ENUM | READ_ONLY))
12260 .ToHandleChecked();
12261}
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000012262
12263namespace {
12264
12265char const kNativeCodeSource[] = "function () { [native code] }";
12266
12267
12268Handle<String> NativeCodeFunctionSourceString(
12269 Handle<SharedFunctionInfo> shared_info) {
12270 Isolate* const isolate = shared_info->GetIsolate();
12271 if (shared_info->name()->IsString()) {
12272 IncrementalStringBuilder builder(isolate);
12273 builder.AppendCString("function ");
12274 builder.AppendString(handle(String::cast(shared_info->name()), isolate));
12275 builder.AppendCString("() { [native code] }");
12276 return builder.Finish().ToHandleChecked();
12277 }
12278 return isolate->factory()->NewStringFromAsciiChecked(kNativeCodeSource);
12279}
12280
12281} // namespace
12282
12283
12284// static
12285Handle<String> JSBoundFunction::ToString(Handle<JSBoundFunction> function) {
12286 Isolate* const isolate = function->GetIsolate();
12287 return isolate->factory()->NewStringFromAsciiChecked(kNativeCodeSource);
12288}
12289
12290
12291// static
12292Handle<String> JSFunction::ToString(Handle<JSFunction> function) {
12293 Isolate* const isolate = function->GetIsolate();
12294 Handle<SharedFunctionInfo> shared_info(function->shared(), isolate);
12295
12296 // Check if {function} should hide its source code.
12297 if (!shared_info->script()->IsScript() ||
12298 Script::cast(shared_info->script())->hide_source()) {
12299 return NativeCodeFunctionSourceString(shared_info);
12300 }
12301
12302 // Check if we should print {function} as a class.
12303 Handle<Object> class_start_position = JSReceiver::GetDataProperty(
12304 function, isolate->factory()->class_start_position_symbol());
12305 if (class_start_position->IsSmi()) {
12306 Handle<Object> class_end_position = JSReceiver::GetDataProperty(
12307 function, isolate->factory()->class_end_position_symbol());
12308 Handle<String> script_source(
12309 String::cast(Script::cast(shared_info->script())->source()), isolate);
12310 return isolate->factory()->NewSubString(
12311 script_source, Handle<Smi>::cast(class_start_position)->value(),
12312 Handle<Smi>::cast(class_end_position)->value());
12313 }
12314
12315 // Check if we have source code for the {function}.
12316 if (!shared_info->HasSourceCode()) {
12317 return NativeCodeFunctionSourceString(shared_info);
12318 }
12319
12320 IncrementalStringBuilder builder(isolate);
12321 if (!shared_info->is_arrow()) {
12322 if (shared_info->is_concise_method()) {
Ben Murdochc5610432016-08-08 18:44:38 +010012323 if (shared_info->is_generator()) {
12324 builder.AppendCharacter('*');
12325 } else if (shared_info->is_async()) {
12326 builder.AppendCString("async ");
12327 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000012328 } else {
12329 if (shared_info->is_generator()) {
12330 builder.AppendCString("function* ");
Ben Murdochc5610432016-08-08 18:44:38 +010012331 } else if (shared_info->is_async()) {
12332 builder.AppendCString("async function ");
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000012333 } else {
12334 builder.AppendCString("function ");
12335 }
12336 }
12337 if (shared_info->name_should_print_as_anonymous()) {
12338 builder.AppendCString("anonymous");
Ben Murdoch097c5b22016-05-18 11:27:45 +010012339 } else if (!shared_info->is_anonymous_expression()) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000012340 builder.AppendString(handle(String::cast(shared_info->name()), isolate));
12341 }
12342 }
12343 builder.AppendString(Handle<String>::cast(shared_info->GetSourceCode()));
12344 return builder.Finish().ToHandleChecked();
12345}
12346
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000012347void Oddball::Initialize(Isolate* isolate, Handle<Oddball> oddball,
12348 const char* to_string, Handle<Object> to_number,
Ben Murdochda12d292016-06-02 14:46:10 +010012349 bool to_boolean, const char* type_of, byte kind) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012350 Handle<String> internalized_to_string =
12351 isolate->factory()->InternalizeUtf8String(to_string);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000012352 Handle<String> internalized_type_of =
12353 isolate->factory()->InternalizeUtf8String(type_of);
Ben Murdochc5610432016-08-08 18:44:38 +010012354 oddball->set_to_number_raw(to_number->Number());
Ben Murdochda12d292016-06-02 14:46:10 +010012355 oddball->set_to_boolean(isolate->heap()->ToBoolean(to_boolean));
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012356 oddball->set_to_number(*to_number);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000012357 oddball->set_to_string(*internalized_to_string);
12358 oddball->set_type_of(*internalized_type_of);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012359 oddball->set_kind(kind);
12360}
12361
Ben Murdochc5610432016-08-08 18:44:38 +010012362void Script::SetEvalOrigin(Handle<Script> script,
12363 Handle<SharedFunctionInfo> outer_info,
12364 int eval_position) {
12365 if (eval_position == RelocInfo::kNoPosition) {
12366 // If the position is missing, attempt to get the code offset from the
12367 // current activation. Do not translate the code offset into source
12368 // position, but store it as negative value for lazy translation.
12369 StackTraceFrameIterator it(script->GetIsolate());
12370 if (!it.done() && it.is_javascript()) {
12371 FrameSummary summary = FrameSummary::GetFirst(it.javascript_frame());
12372 script->set_eval_from_shared(summary.function()->shared());
12373 script->set_eval_from_position(-summary.code_offset());
12374 return;
12375 }
12376 eval_position = 0;
12377 }
12378 script->set_eval_from_shared(*outer_info);
12379 script->set_eval_from_position(eval_position);
12380}
12381
12382int Script::GetEvalPosition() {
12383 DisallowHeapAllocation no_gc;
12384 DCHECK(compilation_type() == Script::COMPILATION_TYPE_EVAL);
12385 int position = eval_from_position();
12386 if (position < 0) {
12387 // Due to laziness, the position may not have been translated from code
12388 // offset yet, which would be encoded as negative integer. In that case,
12389 // translate and set the position.
12390 if (eval_from_shared()->IsUndefined()) {
12391 position = 0;
12392 } else {
12393 SharedFunctionInfo* shared = SharedFunctionInfo::cast(eval_from_shared());
12394 position = shared->abstract_code()->SourcePosition(-position);
12395 }
12396 DCHECK(position >= 0);
12397 set_eval_from_position(position);
12398 }
12399 return position;
12400}
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012401
12402void Script::InitLineEnds(Handle<Script> script) {
12403 if (!script->line_ends()->IsUndefined()) return;
12404
12405 Isolate* isolate = script->GetIsolate();
12406
12407 if (!script->source()->IsString()) {
12408 DCHECK(script->source()->IsUndefined());
12409 Handle<FixedArray> empty = isolate->factory()->NewFixedArray(0);
12410 script->set_line_ends(*empty);
12411 DCHECK(script->line_ends()->IsFixedArray());
12412 return;
12413 }
12414
12415 Handle<String> src(String::cast(script->source()), isolate);
12416
12417 Handle<FixedArray> array = String::CalculateLineEnds(src, true);
12418
12419 if (*array != isolate->heap()->empty_fixed_array()) {
12420 array->set_map(isolate->heap()->fixed_cow_array_map());
12421 }
12422
12423 script->set_line_ends(*array);
12424 DCHECK(script->line_ends()->IsFixedArray());
12425}
12426
12427
12428int Script::GetColumnNumber(Handle<Script> script, int code_pos) {
12429 int line_number = GetLineNumber(script, code_pos);
12430 if (line_number == -1) return -1;
12431
12432 DisallowHeapAllocation no_allocation;
12433 FixedArray* line_ends_array = FixedArray::cast(script->line_ends());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000012434 line_number = line_number - script->line_offset();
12435 if (line_number == 0) return code_pos + script->column_offset();
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012436 int prev_line_end_pos =
12437 Smi::cast(line_ends_array->get(line_number - 1))->value();
12438 return code_pos - (prev_line_end_pos + 1);
12439}
12440
12441
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000012442int Script::GetLineNumberWithArray(int code_pos) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012443 DisallowHeapAllocation no_allocation;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000012444 DCHECK(line_ends()->IsFixedArray());
12445 FixedArray* line_ends_array = FixedArray::cast(line_ends());
12446 int line_ends_len = line_ends_array->length();
12447 if (line_ends_len == 0) return -1;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012448
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000012449 if ((Smi::cast(line_ends_array->get(0)))->value() >= code_pos) {
12450 return line_offset();
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012451 }
12452
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000012453 int left = 0;
12454 int right = line_ends_len;
12455 while (int half = (right - left) / 2) {
12456 if ((Smi::cast(line_ends_array->get(left + half)))->value() > code_pos) {
12457 right -= half;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012458 } else {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000012459 left += half;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012460 }
12461 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000012462 return right + line_offset();
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012463}
12464
12465
12466int Script::GetLineNumber(Handle<Script> script, int code_pos) {
12467 InitLineEnds(script);
12468 return script->GetLineNumberWithArray(code_pos);
12469}
12470
12471
12472int Script::GetLineNumber(int code_pos) {
12473 DisallowHeapAllocation no_allocation;
12474 if (!line_ends()->IsUndefined()) return GetLineNumberWithArray(code_pos);
12475
12476 // Slow mode: we do not have line_ends. We have to iterate through source.
12477 if (!source()->IsString()) return -1;
12478
12479 String* source_string = String::cast(source());
12480 int line = 0;
12481 int len = source_string->length();
12482 for (int pos = 0; pos < len; pos++) {
12483 if (pos == code_pos) break;
12484 if (source_string->Get(pos) == '\n') line++;
12485 }
12486 return line;
12487}
12488
12489
12490Handle<Object> Script::GetNameOrSourceURL(Handle<Script> script) {
12491 Isolate* isolate = script->GetIsolate();
12492 Handle<String> name_or_source_url_key =
12493 isolate->factory()->InternalizeOneByteString(
12494 STATIC_CHAR_VECTOR("nameOrSourceURL"));
12495 Handle<JSObject> script_wrapper = Script::GetWrapper(script);
Ben Murdochda12d292016-06-02 14:46:10 +010012496 Handle<Object> property =
12497 JSReceiver::GetProperty(script_wrapper, name_or_source_url_key)
12498 .ToHandleChecked();
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012499 DCHECK(property->IsJSFunction());
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012500 Handle<Object> result;
12501 // Do not check against pending exception, since this function may be called
12502 // when an exception has already been pending.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000012503 if (!Execution::TryCall(isolate, property, script_wrapper, 0, NULL)
12504 .ToHandle(&result)) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012505 return isolate->factory()->undefined_value();
12506 }
12507 return result;
12508}
12509
12510
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012511Handle<JSObject> Script::GetWrapper(Handle<Script> script) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012512 Isolate* isolate = script->GetIsolate();
Emily Bernierd0a1eb72015-03-24 16:35:39 -040012513 if (!script->wrapper()->IsUndefined()) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000012514 DCHECK(script->wrapper()->IsWeakCell());
Emily Bernierd0a1eb72015-03-24 16:35:39 -040012515 Handle<WeakCell> cell(WeakCell::cast(script->wrapper()));
12516 if (!cell->cleared()) {
12517 // Return a handle for the existing script wrapper from the cache.
12518 return handle(JSObject::cast(cell->value()));
12519 }
12520 // If we found an empty WeakCell, that means the script wrapper was
12521 // GCed. We are not notified directly of that, so we decrement here
12522 // so that we at least don't count double for any given script.
12523 isolate->counters()->script_wrappers()->Decrement();
12524 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012525 // Construct a new script wrapper.
12526 isolate->counters()->script_wrappers()->Increment();
12527 Handle<JSFunction> constructor = isolate->script_function();
12528 Handle<JSValue> result =
12529 Handle<JSValue>::cast(isolate->factory()->NewJSObject(constructor));
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012530 result->set_value(*script);
Emily Bernierd0a1eb72015-03-24 16:35:39 -040012531 Handle<WeakCell> cell = isolate->factory()->NewWeakCell(result);
12532 script->set_wrapper(*cell);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012533 return result;
Steve Blocka7e24c12009-10-30 11:49:00 +000012534}
12535
12536
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000012537MaybeHandle<SharedFunctionInfo> Script::FindSharedFunctionInfo(
12538 FunctionLiteral* fun) {
12539 WeakFixedArray::Iterator iterator(shared_function_infos());
12540 SharedFunctionInfo* shared;
12541 while ((shared = iterator.Next<SharedFunctionInfo>())) {
12542 if (fun->function_token_position() == shared->function_token_position() &&
Ben Murdochc5610432016-08-08 18:44:38 +010012543 fun->start_position() == shared->start_position() &&
12544 fun->end_position() == shared->end_position()) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000012545 return Handle<SharedFunctionInfo>(shared);
12546 }
12547 }
12548 return MaybeHandle<SharedFunctionInfo>();
12549}
12550
12551
12552Script::Iterator::Iterator(Isolate* isolate)
12553 : iterator_(isolate->heap()->script_list()) {}
12554
12555
12556Script* Script::Iterator::Next() { return iterator_.Next<Script>(); }
12557
12558
12559SharedFunctionInfo::Iterator::Iterator(Isolate* isolate)
12560 : script_iterator_(isolate),
12561 sfi_iterator_(isolate->heap()->noscript_shared_function_infos()) {}
12562
12563
12564bool SharedFunctionInfo::Iterator::NextScript() {
12565 Script* script = script_iterator_.Next();
12566 if (script == NULL) return false;
12567 sfi_iterator_.Reset(script->shared_function_infos());
12568 return true;
12569}
12570
12571
12572SharedFunctionInfo* SharedFunctionInfo::Iterator::Next() {
12573 do {
12574 SharedFunctionInfo* next = sfi_iterator_.Next<SharedFunctionInfo>();
12575 if (next != NULL) return next;
12576 } while (NextScript());
12577 return NULL;
12578}
12579
12580
12581void SharedFunctionInfo::SetScript(Handle<SharedFunctionInfo> shared,
12582 Handle<Object> script_object) {
12583 if (shared->script() == *script_object) return;
12584 Isolate* isolate = shared->GetIsolate();
12585
12586 // Add shared function info to new script's list. If a collection occurs,
12587 // the shared function info may be temporarily in two lists.
12588 // This is okay because the gc-time processing of these lists can tolerate
12589 // duplicates.
12590 Handle<Object> list;
12591 if (script_object->IsScript()) {
12592 Handle<Script> script = Handle<Script>::cast(script_object);
12593 list = handle(script->shared_function_infos(), isolate);
12594 } else {
12595 list = isolate->factory()->noscript_shared_function_infos();
12596 }
12597
12598#ifdef DEBUG
Ben Murdochda12d292016-06-02 14:46:10 +010012599 if (FLAG_enable_slow_asserts) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000012600 WeakFixedArray::Iterator iterator(*list);
12601 SharedFunctionInfo* next;
12602 while ((next = iterator.Next<SharedFunctionInfo>())) {
12603 DCHECK_NE(next, *shared);
12604 }
12605 }
12606#endif // DEBUG
12607 list = WeakFixedArray::Add(list, shared);
12608
12609 if (script_object->IsScript()) {
12610 Handle<Script> script = Handle<Script>::cast(script_object);
12611 script->set_shared_function_infos(*list);
12612 } else {
12613 isolate->heap()->SetRootNoScriptSharedFunctionInfos(*list);
12614 }
12615
12616 // Remove shared function info from old script's list.
12617 if (shared->script()->IsScript()) {
12618 Script* old_script = Script::cast(shared->script());
12619 if (old_script->shared_function_infos()->IsWeakFixedArray()) {
12620 WeakFixedArray* list =
12621 WeakFixedArray::cast(old_script->shared_function_infos());
12622 list->Remove(shared);
12623 }
12624 } else {
12625 // Remove shared function info from root array.
12626 Object* list = isolate->heap()->noscript_shared_function_infos();
12627 CHECK(WeakFixedArray::cast(list)->Remove(shared));
12628 }
12629
12630 // Finally set new script.
12631 shared->set_script(*script_object);
12632}
12633
12634
Ben Murdochf87a2032010-10-22 12:50:53 +010012635String* SharedFunctionInfo::DebugName() {
12636 Object* n = name();
12637 if (!n->IsString() || String::cast(n)->length() == 0) return inferred_name();
12638 return String::cast(n);
12639}
12640
Ben Murdochda12d292016-06-02 14:46:10 +010012641// The filter is a pattern that matches function names in this way:
12642// "*" all; the default
12643// "-" all but the top-level function
12644// "-name" all but the function "name"
12645// "" only the top-level function
12646// "name" only the function "name"
12647// "name*" only functions starting with "name"
12648// "~" none; the tilde is not an identifier
12649bool SharedFunctionInfo::PassesFilter(const char* raw_filter) {
12650 if (*raw_filter == '*') return true;
12651 String* name = DebugName();
12652 Vector<const char> filter = CStrVector(raw_filter);
12653 if (filter.length() == 0) return name->length() == 0;
12654 if (filter[0] == '-') {
12655 // Negative filter.
12656 if (filter.length() == 1) {
12657 return (name->length() != 0);
12658 } else if (name->IsUtf8EqualTo(filter.SubVector(1, filter.length()))) {
12659 return false;
12660 }
12661 if (filter[filter.length() - 1] == '*' &&
12662 name->IsUtf8EqualTo(filter.SubVector(1, filter.length() - 1), true)) {
12663 return false;
12664 }
12665 return true;
12666
12667 } else if (name->IsUtf8EqualTo(filter)) {
12668 return true;
12669 }
12670 if (filter[filter.length() - 1] == '*' &&
12671 name->IsUtf8EqualTo(filter.SubVector(0, filter.length() - 1), true)) {
12672 return true;
12673 }
12674 return false;
12675}
Ben Murdochf87a2032010-10-22 12:50:53 +010012676
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012677bool SharedFunctionInfo::HasSourceCode() const {
Steve Blocka7e24c12009-10-30 11:49:00 +000012678 return !script()->IsUndefined() &&
Iain Merrick75681382010-08-19 15:07:18 +010012679 !reinterpret_cast<Script*>(script())->source()->IsUndefined();
Steve Blocka7e24c12009-10-30 11:49:00 +000012680}
12681
12682
Ben Murdoch3ef787d2012-04-12 10:51:47 +010012683Handle<Object> SharedFunctionInfo::GetSourceCode() {
12684 if (!HasSourceCode()) return GetIsolate()->factory()->undefined_value();
12685 Handle<String> source(String::cast(Script::cast(script())->source()));
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012686 return GetIsolate()->factory()->NewSubString(
12687 source, start_position(), end_position());
12688}
12689
12690
12691bool SharedFunctionInfo::IsInlineable() {
12692 // Check that the function has a script associated with it.
12693 if (!script()->IsScript()) return false;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000012694 return !optimization_disabled();
Steve Blocka7e24c12009-10-30 11:49:00 +000012695}
12696
12697
Ben Murdochb0fe1622011-05-05 13:52:32 +010012698int SharedFunctionInfo::SourceSize() {
12699 return end_position() - start_position();
12700}
12701
Ben Murdochda12d292016-06-02 14:46:10 +010012702void JSFunction::CalculateInstanceSizeHelper(InstanceType instance_type,
12703 int requested_internal_fields,
12704 int requested_in_object_properties,
12705 int* instance_size,
12706 int* in_object_properties) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000012707 int header_size = JSObject::GetHeaderSize(instance_type);
12708 DCHECK_LE(requested_internal_fields,
12709 (JSObject::kMaxInstanceSize - header_size) >> kPointerSizeLog2);
12710 *instance_size =
12711 Min(header_size +
12712 ((requested_internal_fields + requested_in_object_properties)
12713 << kPointerSizeLog2),
12714 JSObject::kMaxInstanceSize);
12715 *in_object_properties = ((*instance_size - header_size) >> kPointerSizeLog2) -
12716 requested_internal_fields;
12717}
12718
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000012719
12720void JSFunction::CalculateInstanceSize(InstanceType instance_type,
12721 int requested_internal_fields,
12722 int* instance_size,
12723 int* in_object_properties) {
12724 CalculateInstanceSizeHelper(instance_type, requested_internal_fields,
12725 shared()->expected_nof_properties(),
12726 instance_size, in_object_properties);
Steve Blocka7e24c12009-10-30 11:49:00 +000012727}
12728
12729
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000012730void JSFunction::CalculateInstanceSizeForDerivedClass(
12731 InstanceType instance_type, int requested_internal_fields,
12732 int* instance_size, int* in_object_properties) {
12733 Isolate* isolate = GetIsolate();
12734 int expected_nof_properties = 0;
12735 for (PrototypeIterator iter(isolate, this,
12736 PrototypeIterator::START_AT_RECEIVER);
12737 !iter.IsAtEnd(); iter.Advance()) {
Ben Murdoch097c5b22016-05-18 11:27:45 +010012738 JSReceiver* current = iter.GetCurrent<JSReceiver>();
12739 if (!current->IsJSFunction()) break;
12740 JSFunction* func = JSFunction::cast(current);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000012741 SharedFunctionInfo* shared = func->shared();
12742 expected_nof_properties += shared->expected_nof_properties();
12743 if (!IsSubclassConstructor(shared->kind())) {
12744 break;
12745 }
12746 }
12747 CalculateInstanceSizeHelper(instance_type, requested_internal_fields,
12748 expected_nof_properties, instance_size,
12749 in_object_properties);
Steve Blocka7e24c12009-10-30 11:49:00 +000012750}
12751
12752
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012753// Output the source code without any allocation in the heap.
Emily Bernierd0a1eb72015-03-24 16:35:39 -040012754std::ostream& operator<<(std::ostream& os, const SourceCodeOf& v) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012755 const SharedFunctionInfo* s = v.value;
Steve Blocka7e24c12009-10-30 11:49:00 +000012756 // For some native functions there is no source.
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012757 if (!s->HasSourceCode()) return os << "<No Source>";
Steve Blocka7e24c12009-10-30 11:49:00 +000012758
Steve Blockd0582a62009-12-15 09:54:21 +000012759 // Get the source for the script which this function came from.
Steve Blocka7e24c12009-10-30 11:49:00 +000012760 // Don't use String::cast because we don't want more assertion errors while
12761 // we are already creating a stack dump.
12762 String* script_source =
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012763 reinterpret_cast<String*>(Script::cast(s->script())->source());
Steve Blocka7e24c12009-10-30 11:49:00 +000012764
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012765 if (!script_source->LooksValid()) return os << "<Invalid Source>";
Steve Blocka7e24c12009-10-30 11:49:00 +000012766
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012767 if (!s->is_toplevel()) {
12768 os << "function ";
12769 Object* name = s->name();
Steve Blocka7e24c12009-10-30 11:49:00 +000012770 if (name->IsString() && String::cast(name)->length() > 0) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012771 String::cast(name)->PrintUC16(os);
Steve Blocka7e24c12009-10-30 11:49:00 +000012772 }
12773 }
12774
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012775 int len = s->end_position() - s->start_position();
12776 if (len <= v.max_length || v.max_length < 0) {
12777 script_source->PrintUC16(os, s->start_position(), s->end_position());
12778 return os;
Ben Murdochb0fe1622011-05-05 13:52:32 +010012779 } else {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012780 script_source->PrintUC16(os, s->start_position(),
12781 s->start_position() + v.max_length);
12782 return os << "...\n";
Steve Blocka7e24c12009-10-30 11:49:00 +000012783 }
12784}
12785
12786
Ben Murdochb0fe1622011-05-05 13:52:32 +010012787static bool IsCodeEquivalent(Code* code, Code* recompiled) {
12788 if (code->instruction_size() != recompiled->instruction_size()) return false;
12789 ByteArray* code_relocation = code->relocation_info();
12790 ByteArray* recompiled_relocation = recompiled->relocation_info();
12791 int length = code_relocation->length();
12792 if (length != recompiled_relocation->length()) return false;
12793 int compare = memcmp(code_relocation->GetDataStartAddress(),
12794 recompiled_relocation->GetDataStartAddress(),
12795 length);
12796 return compare == 0;
12797}
12798
12799
12800void SharedFunctionInfo::EnableDeoptimizationSupport(Code* recompiled) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012801 DCHECK(!has_deoptimization_support());
12802 DisallowHeapAllocation no_allocation;
Ben Murdochb0fe1622011-05-05 13:52:32 +010012803 Code* code = this->code();
12804 if (IsCodeEquivalent(code, recompiled)) {
12805 // Copy the deoptimization data from the recompiled code.
12806 code->set_deoptimization_data(recompiled->deoptimization_data());
12807 code->set_has_deoptimization_support(true);
12808 } else {
12809 // TODO(3025757): In case the recompiled isn't equivalent to the
12810 // old code, we have to replace it. We should try to avoid this
12811 // altogether because it flushes valuable type feedback by
12812 // effectively resetting all IC state.
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012813 ReplaceCode(recompiled);
Ben Murdochb0fe1622011-05-05 13:52:32 +010012814 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012815 DCHECK(has_deoptimization_support());
Ben Murdochb0fe1622011-05-05 13:52:32 +010012816}
12817
12818
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012819void SharedFunctionInfo::DisableOptimization(BailoutReason reason) {
Ben Murdoch257744e2011-11-30 15:57:28 +000012820 // Disable optimization for the shared function info and mark the
12821 // code as non-optimizable. The marker on the shared function info
12822 // is there because we flush non-optimized code thereby loosing the
12823 // non-optimizable information for the code. When the code is
12824 // regenerated and set on the shared function info it is marked as
12825 // non-optimizable if optimization is disabled for the shared
12826 // function info.
Emily Bernierd0a1eb72015-03-24 16:35:39 -040012827 DCHECK(reason != kNoReason);
Ben Murdoch257744e2011-11-30 15:57:28 +000012828 set_optimization_disabled(true);
Emily Bernierd0a1eb72015-03-24 16:35:39 -040012829 set_disable_optimization_reason(reason);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000012830 // Code should be the lazy compilation stub or else unoptimized.
Ben Murdochda12d292016-06-02 14:46:10 +010012831 DCHECK(abstract_code()->kind() == AbstractCode::FUNCTION ||
12832 abstract_code()->kind() == AbstractCode::INTERPRETED_FUNCTION ||
12833 abstract_code()->kind() == AbstractCode::BUILTIN);
12834 PROFILE(GetIsolate(), CodeDisableOptEvent(abstract_code(), this));
Ben Murdoch257744e2011-11-30 15:57:28 +000012835 if (FLAG_trace_opt) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012836 PrintF("[disabled optimization for ");
12837 ShortPrint();
12838 PrintF(", reason: %s]\n", GetBailoutReason(reason));
Ben Murdoch257744e2011-11-30 15:57:28 +000012839 }
12840}
12841
Ben Murdochc5610432016-08-08 18:44:38 +010012842namespace {
12843
12844// Sets the expected number of properties based on estimate from parser.
12845void SetExpectedNofPropertiesFromEstimate(Handle<SharedFunctionInfo> shared,
12846 FunctionLiteral* literal) {
12847 int estimate = literal->expected_property_count();
12848
12849 // If no properties are added in the constructor, they are more likely
12850 // to be added later.
12851 if (estimate == 0) estimate = 2;
12852
12853 // TODO(yangguo): check whether those heuristics are still up-to-date.
12854 // We do not shrink objects that go into a snapshot (yet), so we adjust
12855 // the estimate conservatively.
12856 if (shared->GetIsolate()->serializer_enabled()) {
12857 estimate += 2;
12858 } else {
12859 // Inobject slack tracking will reclaim redundant inobject space later,
12860 // so we can afford to adjust the estimate generously.
12861 estimate += 8;
12862 }
12863
12864 shared->set_expected_nof_properties(estimate);
12865}
12866
12867} // namespace
Ben Murdoch257744e2011-11-30 15:57:28 +000012868
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000012869void SharedFunctionInfo::InitFromFunctionLiteral(
12870 Handle<SharedFunctionInfo> shared_info, FunctionLiteral* lit) {
12871 shared_info->set_length(lit->scope()->default_function_length());
12872 shared_info->set_internal_formal_parameter_count(lit->parameter_count());
12873 shared_info->set_function_token_position(lit->function_token_position());
12874 shared_info->set_start_position(lit->start_position());
12875 shared_info->set_end_position(lit->end_position());
Ben Murdoch097c5b22016-05-18 11:27:45 +010012876 shared_info->set_is_declaration(lit->is_declaration());
12877 shared_info->set_is_named_expression(lit->is_named_expression());
12878 shared_info->set_is_anonymous_expression(lit->is_anonymous_expression());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000012879 shared_info->set_inferred_name(*lit->inferred_name());
12880 shared_info->set_allows_lazy_compilation(lit->AllowsLazyCompilation());
12881 shared_info->set_allows_lazy_compilation_without_context(
12882 lit->AllowsLazyCompilationWithoutContext());
12883 shared_info->set_language_mode(lit->language_mode());
12884 shared_info->set_uses_arguments(lit->scope()->arguments() != NULL);
12885 shared_info->set_has_duplicate_parameters(lit->has_duplicate_parameters());
12886 shared_info->set_ast_node_count(lit->ast_node_count());
12887 shared_info->set_is_function(lit->is_function());
12888 if (lit->dont_optimize_reason() != kNoReason) {
12889 shared_info->DisableOptimization(lit->dont_optimize_reason());
12890 }
12891 shared_info->set_dont_crankshaft(lit->flags() &
12892 AstProperties::kDontCrankshaft);
Ben Murdochc5610432016-08-08 18:44:38 +010012893 shared_info->set_never_compiled(true);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000012894 shared_info->set_kind(lit->kind());
12895 if (!IsConstructable(lit->kind(), lit->language_mode())) {
12896 shared_info->set_construct_stub(
12897 *shared_info->GetIsolate()->builtins()->ConstructedNonConstructable());
12898 }
12899 shared_info->set_needs_home_object(lit->scope()->NeedsHomeObject());
12900 shared_info->set_asm_function(lit->scope()->asm_function());
Ben Murdochc5610432016-08-08 18:44:38 +010012901 SetExpectedNofPropertiesFromEstimate(shared_info, lit);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000012902}
12903
12904
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012905bool SharedFunctionInfo::VerifyBailoutId(BailoutId id) {
12906 DCHECK(!id.IsNone());
Ben Murdochb0fe1622011-05-05 13:52:32 +010012907 Code* unoptimized = code();
12908 DeoptimizationOutputData* data =
12909 DeoptimizationOutputData::cast(unoptimized->deoptimization_data());
12910 unsigned ignore = Deoptimizer::GetOutputInfo(data, id, this);
12911 USE(ignore);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012912 return true; // Return true if there was no DCHECK.
Ben Murdochb0fe1622011-05-05 13:52:32 +010012913}
12914
12915
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000012916void Map::StartInobjectSlackTracking() {
12917 DCHECK(!IsInobjectSlackTrackingInProgress());
Ben Murdoch3ef787d2012-04-12 10:51:47 +010012918
Kristian Monsen0d5e1162010-09-30 15:31:59 +010012919 // No tracking during the snapshot construction phase.
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012920 Isolate* isolate = GetIsolate();
12921 if (isolate->serializer_enabled()) return;
Kristian Monsen0d5e1162010-09-30 15:31:59 +010012922
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000012923 if (unused_property_fields() == 0) return;
Kristian Monsen0d5e1162010-09-30 15:31:59 +010012924
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000012925 set_construction_counter(Map::kSlackTrackingCounterStart);
Kristian Monsen0d5e1162010-09-30 15:31:59 +010012926}
12927
12928
Ben Murdoch8f9999f2012-04-23 10:39:17 +010012929void SharedFunctionInfo::ResetForNewContext(int new_ic_age) {
12930 code()->ClearInlineCaches();
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012931 // If we clear ICs, we need to clear the type feedback vector too, since
12932 // CallICs are synced with a feedback vector slot.
12933 ClearTypeFeedbackInfo();
Ben Murdoch8f9999f2012-04-23 10:39:17 +010012934 set_ic_age(new_ic_age);
12935 if (code()->kind() == Code::FUNCTION) {
12936 code()->set_profiler_ticks(0);
Ben Murdochc5610432016-08-08 18:44:38 +010012937 if (optimization_disabled() && opt_count() >= FLAG_max_opt_count) {
12938 // Re-enable optimizations if they were disabled due to opt_count limit.
12939 set_optimization_disabled(false);
12940 }
12941 set_opt_count(0);
12942 set_deopt_count(0);
12943 } else if (code()->is_interpreter_entry_trampoline()) {
12944 set_profiler_ticks(0);
12945 if (optimization_disabled() && opt_count() >= FLAG_max_opt_count) {
Ben Murdoch8f9999f2012-04-23 10:39:17 +010012946 // Re-enable optimizations if they were disabled due to opt_count limit.
12947 set_optimization_disabled(false);
Ben Murdoch8f9999f2012-04-23 10:39:17 +010012948 }
12949 set_opt_count(0);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012950 set_deopt_count(0);
Ben Murdoch8f9999f2012-04-23 10:39:17 +010012951 }
12952}
12953
12954
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000012955int SharedFunctionInfo::SearchOptimizedCodeMapEntry(Context* native_context,
12956 BailoutId osr_ast_id) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012957 DisallowHeapAllocation no_gc;
12958 DCHECK(native_context->IsNativeContext());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000012959 if (!OptimizedCodeMapIsCleared()) {
12960 FixedArray* optimized_code_map = this->optimized_code_map();
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012961 int length = optimized_code_map->length();
12962 Smi* osr_ast_id_smi = Smi::FromInt(osr_ast_id.ToInt());
12963 for (int i = kEntriesStart; i < length; i += kEntryLength) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000012964 if (WeakCell::cast(optimized_code_map->get(i + kContextOffset))
12965 ->value() == native_context &&
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012966 optimized_code_map->get(i + kOsrAstIdOffset) == osr_ast_id_smi) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000012967 return i;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012968 }
12969 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000012970 Object* shared_code =
12971 WeakCell::cast(optimized_code_map->get(kSharedCodeIndex))->value();
12972 if (shared_code->IsCode() && osr_ast_id.IsNone()) {
12973 return kSharedCodeIndex;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012974 }
12975 }
12976 return -1;
Ben Murdoch8f9999f2012-04-23 10:39:17 +010012977}
12978
12979
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000012980CodeAndLiterals SharedFunctionInfo::SearchOptimizedCodeMap(
12981 Context* native_context, BailoutId osr_ast_id) {
12982 CodeAndLiterals result = {nullptr, nullptr};
12983 int entry = SearchOptimizedCodeMapEntry(native_context, osr_ast_id);
12984 if (entry != kNotFound) {
12985 FixedArray* code_map = optimized_code_map();
12986 if (entry == kSharedCodeIndex) {
12987 // We know the weak cell isn't cleared because we made sure of it in
12988 // SearchOptimizedCodeMapEntry and performed no allocations since that
12989 // call.
12990 result = {
12991 Code::cast(WeakCell::cast(code_map->get(kSharedCodeIndex))->value()),
12992 nullptr};
12993 } else {
12994 DCHECK_LE(entry + kEntryLength, code_map->length());
12995 WeakCell* cell = WeakCell::cast(code_map->get(entry + kCachedCodeOffset));
12996 WeakCell* literals_cell =
12997 WeakCell::cast(code_map->get(entry + kLiteralsOffset));
12998
12999 result = {cell->cleared() ? nullptr : Code::cast(cell->value()),
13000 literals_cell->cleared()
13001 ? nullptr
13002 : LiteralsArray::cast(literals_cell->value())};
13003 }
13004 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000013005 return result;
13006}
13007
13008
Ben Murdoch3ef787d2012-04-12 10:51:47 +010013009#define DECLARE_TAG(ignore1, name, ignore2) name,
13010const char* const VisitorSynchronization::kTags[
13011 VisitorSynchronization::kNumberOfSyncTags] = {
13012 VISITOR_SYNCHRONIZATION_TAGS_LIST(DECLARE_TAG)
13013};
13014#undef DECLARE_TAG
13015
13016
13017#define DECLARE_TAG(ignore1, ignore2, name) name,
13018const char* const VisitorSynchronization::kTagNames[
13019 VisitorSynchronization::kNumberOfSyncTags] = {
13020 VISITOR_SYNCHRONIZATION_TAGS_LIST(DECLARE_TAG)
13021};
13022#undef DECLARE_TAG
13023
13024
Steve Blocka7e24c12009-10-30 11:49:00 +000013025void ObjectVisitor::VisitCodeTarget(RelocInfo* rinfo) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013026 DCHECK(RelocInfo::IsCodeTarget(rinfo->rmode()));
Steve Blocka7e24c12009-10-30 11:49:00 +000013027 Object* target = Code::GetCodeFromTargetAddress(rinfo->target_address());
13028 Object* old_target = target;
13029 VisitPointer(&target);
13030 CHECK_EQ(target, old_target); // VisitPointer doesn't change Code* *target.
13031}
13032
13033
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013034void ObjectVisitor::VisitCodeAgeSequence(RelocInfo* rinfo) {
13035 DCHECK(RelocInfo::IsCodeAgeSequence(rinfo->rmode()));
13036 Object* stub = rinfo->code_age_stub();
13037 if (stub) {
13038 VisitPointer(&stub);
13039 }
13040}
13041
13042
Steve Block791712a2010-08-27 10:21:07 +010013043void ObjectVisitor::VisitCodeEntry(Address entry_address) {
13044 Object* code = Code::GetObjectFromEntryAddress(entry_address);
13045 Object* old_code = code;
13046 VisitPointer(&code);
13047 if (code != old_code) {
13048 Memory::Address_at(entry_address) = reinterpret_cast<Code*>(code)->entry();
13049 }
13050}
13051
13052
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013053void ObjectVisitor::VisitCell(RelocInfo* rinfo) {
13054 DCHECK(rinfo->rmode() == RelocInfo::CELL);
Ben Murdochb0fe1622011-05-05 13:52:32 +010013055 Object* cell = rinfo->target_cell();
13056 Object* old_cell = cell;
13057 VisitPointer(&cell);
13058 if (cell != old_cell) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013059 rinfo->set_target_cell(reinterpret_cast<Cell*>(cell));
Ben Murdochb0fe1622011-05-05 13:52:32 +010013060 }
13061}
13062
13063
Steve Blocka7e24c12009-10-30 11:49:00 +000013064void ObjectVisitor::VisitDebugTarget(RelocInfo* rinfo) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000013065 DCHECK(RelocInfo::IsDebugBreakSlot(rinfo->rmode()) &&
13066 rinfo->IsPatchedDebugBreakSlotSequence());
13067 Object* target = Code::GetCodeFromTargetAddress(rinfo->debug_call_address());
Steve Blocka7e24c12009-10-30 11:49:00 +000013068 Object* old_target = target;
13069 VisitPointer(&target);
13070 CHECK_EQ(target, old_target); // VisitPointer doesn't change Code* *target.
13071}
13072
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013073
Ben Murdoch3ef787d2012-04-12 10:51:47 +010013074void ObjectVisitor::VisitEmbeddedPointer(RelocInfo* rinfo) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013075 DCHECK(rinfo->rmode() == RelocInfo::EMBEDDED_OBJECT);
13076 Object* p = rinfo->target_object();
13077 VisitPointer(&p);
Ben Murdoch3ef787d2012-04-12 10:51:47 +010013078}
13079
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013080
Ben Murdoch3ef787d2012-04-12 10:51:47 +010013081void ObjectVisitor::VisitExternalReference(RelocInfo* rinfo) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000013082 Address p = rinfo->target_external_reference();
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013083 VisitExternalReference(&p);
Ben Murdoch3ef787d2012-04-12 10:51:47 +010013084}
13085
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013086
Ben Murdochb0fe1622011-05-05 13:52:32 +010013087void Code::InvalidateRelocation() {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013088 InvalidateEmbeddedObjects();
Ben Murdoch3ef787d2012-04-12 10:51:47 +010013089 set_relocation_info(GetHeap()->empty_byte_array());
Ben Murdochb0fe1622011-05-05 13:52:32 +010013090}
13091
13092
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013093void Code::InvalidateEmbeddedObjects() {
13094 Object* undefined = GetHeap()->undefined_value();
13095 Cell* undefined_cell = GetHeap()->undefined_cell();
13096 int mode_mask = RelocInfo::ModeMask(RelocInfo::EMBEDDED_OBJECT) |
13097 RelocInfo::ModeMask(RelocInfo::CELL);
13098 for (RelocIterator it(this, mode_mask); !it.done(); it.next()) {
13099 RelocInfo::Mode mode = it.rinfo()->rmode();
13100 if (mode == RelocInfo::EMBEDDED_OBJECT) {
13101 it.rinfo()->set_target_object(undefined, SKIP_WRITE_BARRIER);
13102 } else if (mode == RelocInfo::CELL) {
13103 it.rinfo()->set_target_cell(undefined_cell, SKIP_WRITE_BARRIER);
13104 }
13105 }
13106}
13107
13108
Steve Blockd0582a62009-12-15 09:54:21 +000013109void Code::Relocate(intptr_t delta) {
Steve Blocka7e24c12009-10-30 11:49:00 +000013110 for (RelocIterator it(this, RelocInfo::kApplyMask); !it.done(); it.next()) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000013111 it.rinfo()->apply(delta);
Steve Blocka7e24c12009-10-30 11:49:00 +000013112 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000013113 Assembler::FlushICache(GetIsolate(), instruction_start(), instruction_size());
Steve Blocka7e24c12009-10-30 11:49:00 +000013114}
13115
13116
13117void Code::CopyFrom(const CodeDesc& desc) {
13118 // copy code
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013119 CopyBytes(instruction_start(), desc.buffer,
13120 static_cast<size_t>(desc.instr_size));
Steve Blocka7e24c12009-10-30 11:49:00 +000013121
Steve Blocka7e24c12009-10-30 11:49:00 +000013122 // copy reloc info
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013123 CopyBytes(relocation_start(),
13124 desc.buffer + desc.buffer_size - desc.reloc_size,
13125 static_cast<size_t>(desc.reloc_size));
Steve Blocka7e24c12009-10-30 11:49:00 +000013126
13127 // unbox handles and relocate
Steve Block3ce2e202009-11-05 08:53:23 +000013128 intptr_t delta = instruction_start() - desc.buffer;
Steve Blocka7e24c12009-10-30 11:49:00 +000013129 int mode_mask = RelocInfo::kCodeTargetMask |
13130 RelocInfo::ModeMask(RelocInfo::EMBEDDED_OBJECT) |
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013131 RelocInfo::ModeMask(RelocInfo::CELL) |
13132 RelocInfo::ModeMask(RelocInfo::RUNTIME_ENTRY) |
Steve Blocka7e24c12009-10-30 11:49:00 +000013133 RelocInfo::kApplyMask;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013134 // Needed to find target_object and runtime_entry on X64
13135 Assembler* origin = desc.origin;
13136 AllowDeferredHandleDereference embedding_raw_address;
Steve Blocka7e24c12009-10-30 11:49:00 +000013137 for (RelocIterator it(this, mode_mask); !it.done(); it.next()) {
13138 RelocInfo::Mode mode = it.rinfo()->rmode();
13139 if (mode == RelocInfo::EMBEDDED_OBJECT) {
Steve Block3ce2e202009-11-05 08:53:23 +000013140 Handle<Object> p = it.rinfo()->target_object_handle(origin);
Ben Murdochda12d292016-06-02 14:46:10 +010013141 it.rinfo()->set_target_object(*p, UPDATE_WRITE_BARRIER,
13142 SKIP_ICACHE_FLUSH);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013143 } else if (mode == RelocInfo::CELL) {
13144 Handle<Cell> cell = it.rinfo()->target_cell_handle();
Ben Murdochda12d292016-06-02 14:46:10 +010013145 it.rinfo()->set_target_cell(*cell, UPDATE_WRITE_BARRIER,
13146 SKIP_ICACHE_FLUSH);
Steve Blocka7e24c12009-10-30 11:49:00 +000013147 } else if (RelocInfo::IsCodeTarget(mode)) {
13148 // rewrite code handles in inline cache targets to direct
13149 // pointers to the first instruction in the code object
Steve Block3ce2e202009-11-05 08:53:23 +000013150 Handle<Object> p = it.rinfo()->target_object_handle(origin);
Steve Blocka7e24c12009-10-30 11:49:00 +000013151 Code* code = Code::cast(*p);
Ben Murdoch3ef787d2012-04-12 10:51:47 +010013152 it.rinfo()->set_target_address(code->instruction_start(),
Ben Murdochda12d292016-06-02 14:46:10 +010013153 UPDATE_WRITE_BARRIER, SKIP_ICACHE_FLUSH);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013154 } else if (RelocInfo::IsRuntimeEntry(mode)) {
13155 Address p = it.rinfo()->target_runtime_entry(origin);
Ben Murdochda12d292016-06-02 14:46:10 +010013156 it.rinfo()->set_target_runtime_entry(p, UPDATE_WRITE_BARRIER,
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013157 SKIP_ICACHE_FLUSH);
13158 } else if (mode == RelocInfo::CODE_AGE_SEQUENCE) {
13159 Handle<Object> p = it.rinfo()->code_age_stub_handle(origin);
13160 Code* code = Code::cast(*p);
13161 it.rinfo()->set_code_age_stub(code, SKIP_ICACHE_FLUSH);
Steve Blocka7e24c12009-10-30 11:49:00 +000013162 } else {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000013163 it.rinfo()->apply(delta);
Steve Blocka7e24c12009-10-30 11:49:00 +000013164 }
13165 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000013166 Assembler::FlushICache(GetIsolate(), instruction_start(), instruction_size());
Steve Blocka7e24c12009-10-30 11:49:00 +000013167}
13168
Ben Murdoch097c5b22016-05-18 11:27:45 +010013169// Locate the source position which is closest to the code offset. This is
13170// using the source position information embedded in the relocation info.
Steve Blocka7e24c12009-10-30 11:49:00 +000013171// The position returned is relative to the beginning of the script where the
13172// source for this function is found.
Ben Murdoch097c5b22016-05-18 11:27:45 +010013173int Code::SourcePosition(int code_offset) {
13174 Address pc = instruction_start() + code_offset;
Steve Blocka7e24c12009-10-30 11:49:00 +000013175 int distance = kMaxInt;
13176 int position = RelocInfo::kNoPosition; // Initially no position found.
13177 // Run through all the relocation info to find the best matching source
13178 // position. All the code needs to be considered as the sequence of the
13179 // instructions in the code does not necessarily follow the same order as the
13180 // source.
13181 RelocIterator it(this, RelocInfo::kPositionMask);
13182 while (!it.done()) {
13183 // Only look at positions after the current pc.
13184 if (it.rinfo()->pc() < pc) {
13185 // Get position and distance.
Steve Blockd0582a62009-12-15 09:54:21 +000013186
13187 int dist = static_cast<int>(pc - it.rinfo()->pc());
13188 int pos = static_cast<int>(it.rinfo()->data());
Steve Blocka7e24c12009-10-30 11:49:00 +000013189 // If this position is closer than the current candidate or if it has the
13190 // same distance as the current candidate and the position is higher then
13191 // this position is the new candidate.
13192 if ((dist < distance) ||
13193 (dist == distance && pos > position)) {
13194 position = pos;
13195 distance = dist;
13196 }
13197 }
13198 it.next();
13199 }
Ben Murdochda12d292016-06-02 14:46:10 +010013200 DCHECK(kind() == FUNCTION || (is_optimized_code() && is_turbofanned()) ||
13201 is_wasm_code() || position == RelocInfo::kNoPosition);
Steve Blocka7e24c12009-10-30 11:49:00 +000013202 return position;
13203}
13204
13205
13206// Same as Code::SourcePosition above except it only looks for statement
13207// positions.
Ben Murdoch097c5b22016-05-18 11:27:45 +010013208int Code::SourceStatementPosition(int code_offset) {
Steve Blocka7e24c12009-10-30 11:49:00 +000013209 // First find the position as close as possible using all position
13210 // information.
Ben Murdoch097c5b22016-05-18 11:27:45 +010013211 int position = SourcePosition(code_offset);
Steve Blocka7e24c12009-10-30 11:49:00 +000013212 // Now find the closest statement position before the position.
13213 int statement_position = 0;
13214 RelocIterator it(this, RelocInfo::kPositionMask);
13215 while (!it.done()) {
13216 if (RelocInfo::IsStatementPosition(it.rinfo()->rmode())) {
Steve Blockd0582a62009-12-15 09:54:21 +000013217 int p = static_cast<int>(it.rinfo()->data());
Steve Blocka7e24c12009-10-30 11:49:00 +000013218 if (statement_position < p && p <= position) {
13219 statement_position = p;
13220 }
13221 }
13222 it.next();
13223 }
13224 return statement_position;
13225}
13226
13227
Ben Murdochb8e0da22011-05-16 14:20:40 +010013228SafepointEntry Code::GetSafepointEntry(Address pc) {
Ben Murdochb0fe1622011-05-05 13:52:32 +010013229 SafepointTable table(this);
Ben Murdochb8e0da22011-05-16 14:20:40 +010013230 return table.FindEntry(pc);
Ben Murdochb0fe1622011-05-05 13:52:32 +010013231}
13232
13233
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013234Object* Code::FindNthObject(int n, Map* match_map) {
13235 DCHECK(is_inline_cache_stub());
13236 DisallowHeapAllocation no_allocation;
Ben Murdochb0fe1622011-05-05 13:52:32 +010013237 int mask = RelocInfo::ModeMask(RelocInfo::EMBEDDED_OBJECT);
13238 for (RelocIterator it(this, mask); !it.done(); it.next()) {
13239 RelocInfo* info = it.rinfo();
13240 Object* object = info->target_object();
Emily Bernierd0a1eb72015-03-24 16:35:39 -040013241 if (object->IsWeakCell()) object = WeakCell::cast(object)->value();
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013242 if (object->IsHeapObject()) {
13243 if (HeapObject::cast(object)->map() == match_map) {
13244 if (--n == 0) return object;
13245 }
13246 }
13247 }
13248 return NULL;
13249}
13250
13251
13252AllocationSite* Code::FindFirstAllocationSite() {
13253 Object* result = FindNthObject(1, GetHeap()->allocation_site_map());
13254 return (result != NULL) ? AllocationSite::cast(result) : NULL;
13255}
13256
13257
13258Map* Code::FindFirstMap() {
13259 Object* result = FindNthObject(1, GetHeap()->meta_map());
13260 return (result != NULL) ? Map::cast(result) : NULL;
13261}
13262
13263
13264void Code::FindAndReplace(const FindAndReplacePattern& pattern) {
13265 DCHECK(is_inline_cache_stub() || is_handler());
13266 DisallowHeapAllocation no_allocation;
13267 int mask = RelocInfo::ModeMask(RelocInfo::EMBEDDED_OBJECT);
13268 STATIC_ASSERT(FindAndReplacePattern::kMaxCount < 32);
13269 int current_pattern = 0;
13270 for (RelocIterator it(this, mask); !it.done(); it.next()) {
13271 RelocInfo* info = it.rinfo();
13272 Object* object = info->target_object();
13273 if (object->IsHeapObject()) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -040013274 if (object->IsWeakCell()) {
13275 object = HeapObject::cast(WeakCell::cast(object)->value());
13276 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013277 Map* map = HeapObject::cast(object)->map();
13278 if (map == *pattern.find_[current_pattern]) {
13279 info->set_target_object(*pattern.replace_[current_pattern]);
13280 if (++current_pattern == pattern.count_) return;
13281 }
13282 }
13283 }
13284 UNREACHABLE();
13285}
13286
13287
Ben Murdoch8f9999f2012-04-23 10:39:17 +010013288void Code::ClearInlineCaches() {
13289 int mask = RelocInfo::ModeMask(RelocInfo::CODE_TARGET) |
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013290 RelocInfo::ModeMask(RelocInfo::CODE_TARGET_WITH_ID);
Ben Murdoch8f9999f2012-04-23 10:39:17 +010013291 for (RelocIterator it(this, mask); !it.done(); it.next()) {
13292 RelocInfo* info = it.rinfo();
13293 Code* target(Code::GetCodeFromTargetAddress(info->target_address()));
13294 if (target->is_inline_cache_stub()) {
Ben Murdochc5610432016-08-08 18:44:38 +010013295 IC::Clear(this->GetIsolate(), info->pc(), info->host()->constant_pool());
Ben Murdoch8f9999f2012-04-23 10:39:17 +010013296 }
13297 }
13298}
13299
Ben Murdoch097c5b22016-05-18 11:27:45 +010013300int AbstractCode::SourcePosition(int offset) {
13301 return IsBytecodeArray() ? GetBytecodeArray()->SourcePosition(offset)
13302 : GetCode()->SourcePosition(offset);
13303}
13304
13305int AbstractCode::SourceStatementPosition(int offset) {
13306 return IsBytecodeArray() ? GetBytecodeArray()->SourceStatementPosition(offset)
13307 : GetCode()->SourceStatementPosition(offset);
13308}
Ben Murdoch8f9999f2012-04-23 10:39:17 +010013309
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013310void SharedFunctionInfo::ClearTypeFeedbackInfo() {
Emily Bernierd0a1eb72015-03-24 16:35:39 -040013311 feedback_vector()->ClearSlots(this);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013312}
13313
13314
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000013315void SharedFunctionInfo::ClearTypeFeedbackInfoAtGCTime() {
13316 feedback_vector()->ClearSlotsAtGCTime(this);
13317}
13318
13319
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013320BailoutId Code::TranslatePcOffsetToAstId(uint32_t pc_offset) {
13321 DisallowHeapAllocation no_gc;
13322 DCHECK(kind() == FUNCTION);
13323 BackEdgeTable back_edges(this, &no_gc);
13324 for (uint32_t i = 0; i < back_edges.length(); i++) {
13325 if (back_edges.pc_offset(i) == pc_offset) return back_edges.ast_id(i);
13326 }
13327 return BailoutId::None();
13328}
13329
13330
13331uint32_t Code::TranslateAstIdToPcOffset(BailoutId ast_id) {
13332 DisallowHeapAllocation no_gc;
13333 DCHECK(kind() == FUNCTION);
13334 BackEdgeTable back_edges(this, &no_gc);
13335 for (uint32_t i = 0; i < back_edges.length(); i++) {
13336 if (back_edges.ast_id(i) == ast_id) return back_edges.pc_offset(i);
13337 }
13338 UNREACHABLE(); // We expect to find the back edge.
13339 return 0;
13340}
13341
13342
13343void Code::MakeCodeAgeSequenceYoung(byte* sequence, Isolate* isolate) {
13344 PatchPlatformCodeAge(isolate, sequence, kNoAgeCodeAge, NO_MARKING_PARITY);
13345}
13346
13347
13348void Code::MarkCodeAsExecuted(byte* sequence, Isolate* isolate) {
13349 PatchPlatformCodeAge(isolate, sequence, kExecutedOnceCodeAge,
13350 NO_MARKING_PARITY);
13351}
13352
13353
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000013354// NextAge defines the Code::Age state transitions during a GC cycle.
13355static Code::Age NextAge(Code::Age age) {
13356 switch (age) {
13357 case Code::kNotExecutedCodeAge: // Keep, until we've been executed.
13358 case Code::kToBeExecutedOnceCodeAge: // Keep, until we've been executed.
13359 case Code::kLastCodeAge: // Clamp at last Code::Age value.
13360 return age;
13361 case Code::kExecutedOnceCodeAge:
13362 // Pre-age code that has only been executed once.
13363 return static_cast<Code::Age>(Code::kPreAgedCodeAge + 1);
13364 default:
13365 return static_cast<Code::Age>(age + 1); // Default case: Increase age.
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013366 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000013367}
13368
13369
13370// IsOldAge defines the collection criteria for a Code object.
13371static bool IsOldAge(Code::Age age) {
13372 return age >= Code::kIsOldCodeAge || age == Code::kNotExecutedCodeAge;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013373}
13374
13375
Emily Bernierd0a1eb72015-03-24 16:35:39 -040013376void Code::MakeYoung(Isolate* isolate) {
13377 byte* sequence = FindCodeAgeSequence();
13378 if (sequence != NULL) MakeCodeAgeSequenceYoung(sequence, isolate);
13379}
13380
Ben Murdochda12d292016-06-02 14:46:10 +010013381void Code::PreAge(Isolate* isolate) {
13382 byte* sequence = FindCodeAgeSequence();
13383 if (sequence != NULL) {
13384 PatchPlatformCodeAge(isolate, sequence, kPreAgedCodeAge, NO_MARKING_PARITY);
13385 }
13386}
Emily Bernierd0a1eb72015-03-24 16:35:39 -040013387
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000013388void Code::MarkToBeExecutedOnce(Isolate* isolate) {
13389 byte* sequence = FindCodeAgeSequence();
13390 if (sequence != NULL) {
13391 PatchPlatformCodeAge(isolate, sequence, kToBeExecutedOnceCodeAge,
13392 NO_MARKING_PARITY);
13393 }
13394}
13395
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013396void Code::MakeOlder(MarkingParity current_parity) {
13397 byte* sequence = FindCodeAgeSequence();
13398 if (sequence != NULL) {
13399 Age age;
13400 MarkingParity code_parity;
13401 Isolate* isolate = GetIsolate();
13402 GetCodeAgeAndParity(isolate, sequence, &age, &code_parity);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000013403 Age next_age = NextAge(age);
13404 if (age != next_age && code_parity != current_parity) {
13405 PatchPlatformCodeAge(isolate, sequence, next_age, current_parity);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013406 }
13407 }
13408}
13409
13410
13411bool Code::IsOld() {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000013412 return IsOldAge(GetAge());
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013413}
13414
13415
13416byte* Code::FindCodeAgeSequence() {
13417 return FLAG_age_code &&
13418 prologue_offset() != Code::kPrologueOffsetNotSet &&
13419 (kind() == OPTIMIZED_FUNCTION ||
13420 (kind() == FUNCTION && !has_debug_break_slots()))
13421 ? instruction_start() + prologue_offset()
13422 : NULL;
13423}
13424
13425
13426Code::Age Code::GetAge() {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013427 byte* sequence = FindCodeAgeSequence();
13428 if (sequence == NULL) {
13429 return kNoAgeCodeAge;
13430 }
13431 Age age;
13432 MarkingParity parity;
13433 GetCodeAgeAndParity(GetIsolate(), sequence, &age, &parity);
13434 return age;
13435}
13436
13437
13438void Code::GetCodeAgeAndParity(Code* code, Age* age,
13439 MarkingParity* parity) {
13440 Isolate* isolate = code->GetIsolate();
13441 Builtins* builtins = isolate->builtins();
13442 Code* stub = NULL;
13443#define HANDLE_CODE_AGE(AGE) \
13444 stub = *builtins->Make##AGE##CodeYoungAgainEvenMarking(); \
13445 if (code == stub) { \
13446 *age = k##AGE##CodeAge; \
13447 *parity = EVEN_MARKING_PARITY; \
13448 return; \
13449 } \
13450 stub = *builtins->Make##AGE##CodeYoungAgainOddMarking(); \
13451 if (code == stub) { \
13452 *age = k##AGE##CodeAge; \
13453 *parity = ODD_MARKING_PARITY; \
13454 return; \
13455 }
13456 CODE_AGE_LIST(HANDLE_CODE_AGE)
13457#undef HANDLE_CODE_AGE
13458 stub = *builtins->MarkCodeAsExecutedOnce();
13459 if (code == stub) {
13460 *age = kNotExecutedCodeAge;
13461 *parity = NO_MARKING_PARITY;
13462 return;
13463 }
13464 stub = *builtins->MarkCodeAsExecutedTwice();
13465 if (code == stub) {
13466 *age = kExecutedOnceCodeAge;
13467 *parity = NO_MARKING_PARITY;
13468 return;
13469 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000013470 stub = *builtins->MarkCodeAsToBeExecutedOnce();
13471 if (code == stub) {
13472 *age = kToBeExecutedOnceCodeAge;
13473 *parity = NO_MARKING_PARITY;
13474 return;
13475 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013476 UNREACHABLE();
13477}
13478
13479
13480Code* Code::GetCodeAgeStub(Isolate* isolate, Age age, MarkingParity parity) {
13481 Builtins* builtins = isolate->builtins();
13482 switch (age) {
13483#define HANDLE_CODE_AGE(AGE) \
13484 case k##AGE##CodeAge: { \
13485 Code* stub = parity == EVEN_MARKING_PARITY \
13486 ? *builtins->Make##AGE##CodeYoungAgainEvenMarking() \
13487 : *builtins->Make##AGE##CodeYoungAgainOddMarking(); \
13488 return stub; \
13489 }
13490 CODE_AGE_LIST(HANDLE_CODE_AGE)
13491#undef HANDLE_CODE_AGE
13492 case kNotExecutedCodeAge: {
13493 DCHECK(parity == NO_MARKING_PARITY);
13494 return *builtins->MarkCodeAsExecutedOnce();
13495 }
13496 case kExecutedOnceCodeAge: {
13497 DCHECK(parity == NO_MARKING_PARITY);
13498 return *builtins->MarkCodeAsExecutedTwice();
13499 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000013500 case kToBeExecutedOnceCodeAge: {
13501 DCHECK(parity == NO_MARKING_PARITY);
13502 return *builtins->MarkCodeAsToBeExecutedOnce();
13503 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013504 default:
13505 UNREACHABLE();
13506 break;
13507 }
13508 return NULL;
13509}
13510
13511
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000013512void Code::PrintDeoptLocation(FILE* out, Address pc) {
13513 Deoptimizer::DeoptInfo info = Deoptimizer::GetDeoptInfo(this, pc);
13514 class SourcePosition pos = info.position;
13515 if (info.deopt_reason != Deoptimizer::kNoReason || !pos.IsUnknown()) {
13516 if (FLAG_hydrogen_track_positions) {
13517 PrintF(out, " ;;; deoptimize at %d_%d: %s\n",
13518 pos.inlining_id(), pos.position(),
13519 Deoptimizer::GetDeoptReason(info.deopt_reason));
13520 } else {
13521 PrintF(out, " ;;; deoptimize at %d: %s\n", pos.raw(),
13522 Deoptimizer::GetDeoptReason(info.deopt_reason));
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013523 }
13524 }
13525}
13526
13527
13528bool Code::CanDeoptAt(Address pc) {
13529 DeoptimizationInputData* deopt_data =
13530 DeoptimizationInputData::cast(deoptimization_data());
13531 Address code_start_address = instruction_start();
13532 for (int i = 0; i < deopt_data->DeoptCount(); i++) {
13533 if (deopt_data->Pc(i)->value() == -1) continue;
13534 Address address = code_start_address + deopt_data->Pc(i)->value();
Ben Murdoch097c5b22016-05-18 11:27:45 +010013535 if (address == pc && deopt_data->AstId(i) != BailoutId::None()) {
13536 return true;
13537 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013538 }
13539 return false;
13540}
13541
13542
13543// Identify kind of code.
13544const char* Code::Kind2String(Kind kind) {
13545 switch (kind) {
13546#define CASE(name) case name: return #name;
13547 CODE_KIND_LIST(CASE)
13548#undef CASE
13549 case NUMBER_OF_KINDS: break;
13550 }
13551 UNREACHABLE();
13552 return NULL;
13553}
13554
13555
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000013556Handle<WeakCell> Code::WeakCellFor(Handle<Code> code) {
13557 DCHECK(code->kind() == OPTIMIZED_FUNCTION);
13558 WeakCell* raw_cell = code->CachedWeakCell();
13559 if (raw_cell != NULL) return Handle<WeakCell>(raw_cell);
13560 Handle<WeakCell> cell = code->GetIsolate()->factory()->NewWeakCell(code);
13561 DeoptimizationInputData::cast(code->deoptimization_data())
13562 ->SetWeakCellCache(*cell);
13563 return cell;
13564}
13565
13566
13567WeakCell* Code::CachedWeakCell() {
13568 DCHECK(kind() == OPTIMIZED_FUNCTION);
13569 Object* weak_cell_cache =
13570 DeoptimizationInputData::cast(deoptimization_data())->WeakCellCache();
13571 if (weak_cell_cache->IsWeakCell()) {
13572 DCHECK(this == WeakCell::cast(weak_cell_cache)->value());
13573 return WeakCell::cast(weak_cell_cache);
13574 }
13575 return NULL;
13576}
13577
13578
Steve Blocka7e24c12009-10-30 11:49:00 +000013579#ifdef ENABLE_DISASSEMBLER
Ben Murdochb0fe1622011-05-05 13:52:32 +010013580
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013581void DeoptimizationInputData::DeoptimizationInputDataPrint(
Emily Bernierd0a1eb72015-03-24 16:35:39 -040013582 std::ostream& os) { // NOLINT
Ben Murdochb0fe1622011-05-05 13:52:32 +010013583 disasm::NameConverter converter;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000013584 int const inlined_function_count = InlinedFunctionCount()->value();
13585 os << "Inlined functions (count = " << inlined_function_count << ")\n";
13586 for (int id = 0; id < inlined_function_count; ++id) {
13587 Object* info = LiteralArray()->get(id);
13588 os << " " << Brief(SharedFunctionInfo::cast(info)) << "\n";
13589 }
13590 os << "\n";
Ben Murdochb0fe1622011-05-05 13:52:32 +010013591 int deopt_count = DeoptCount();
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013592 os << "Deoptimization Input Data (deopt points = " << deopt_count << ")\n";
13593 if (0 != deopt_count) {
13594 os << " index ast id argc pc";
13595 if (FLAG_print_code_verbose) os << " commands";
13596 os << "\n";
13597 }
Ben Murdochb0fe1622011-05-05 13:52:32 +010013598 for (int i = 0; i < deopt_count; i++) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000013599 os << std::setw(6) << i << " " << std::setw(6) << AstId(i).ToInt() << " "
13600 << std::setw(6) << ArgumentsStackHeight(i)->value() << " "
13601 << std::setw(6) << Pc(i)->value();
Ben Murdoch69a99ed2011-11-30 16:03:39 +000013602
13603 if (!FLAG_print_code_verbose) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013604 os << "\n";
Ben Murdoch69a99ed2011-11-30 16:03:39 +000013605 continue;
13606 }
13607 // Print details of the frame translation.
Ben Murdochb0fe1622011-05-05 13:52:32 +010013608 int translation_index = TranslationIndex(i)->value();
13609 TranslationIterator iterator(TranslationByteArray(), translation_index);
13610 Translation::Opcode opcode =
13611 static_cast<Translation::Opcode>(iterator.Next());
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013612 DCHECK(Translation::BEGIN == opcode);
Ben Murdochb0fe1622011-05-05 13:52:32 +010013613 int frame_count = iterator.Next();
Ben Murdoch3ef787d2012-04-12 10:51:47 +010013614 int jsframe_count = iterator.Next();
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013615 os << " " << Translation::StringFor(opcode)
13616 << " {frame count=" << frame_count
13617 << ", js frame count=" << jsframe_count << "}\n";
Ben Murdochb0fe1622011-05-05 13:52:32 +010013618
Ben Murdoch69a99ed2011-11-30 16:03:39 +000013619 while (iterator.HasNext() &&
13620 Translation::BEGIN !=
13621 (opcode = static_cast<Translation::Opcode>(iterator.Next()))) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000013622 os << std::setw(31) << " " << Translation::StringFor(opcode) << " ";
Ben Murdoch69a99ed2011-11-30 16:03:39 +000013623
13624 switch (opcode) {
13625 case Translation::BEGIN:
13626 UNREACHABLE();
13627 break;
13628
Ben Murdoch3ef787d2012-04-12 10:51:47 +010013629 case Translation::JS_FRAME: {
Ben Murdoch69a99ed2011-11-30 16:03:39 +000013630 int ast_id = iterator.Next();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000013631 int shared_info_id = iterator.Next();
Ben Murdoch69a99ed2011-11-30 16:03:39 +000013632 unsigned height = iterator.Next();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000013633 Object* shared_info = LiteralArray()->get(shared_info_id);
13634 os << "{ast_id=" << ast_id << ", function="
13635 << Brief(SharedFunctionInfo::cast(shared_info)->DebugName())
13636 << ", height=" << height << "}";
13637 break;
13638 }
13639
13640 case Translation::INTERPRETED_FRAME: {
13641 int bytecode_offset = iterator.Next();
13642 int shared_info_id = iterator.Next();
13643 unsigned height = iterator.Next();
13644 Object* shared_info = LiteralArray()->get(shared_info_id);
13645 os << "{bytecode_offset=" << bytecode_offset << ", function="
13646 << Brief(SharedFunctionInfo::cast(shared_info)->DebugName())
13647 << ", height=" << height << "}";
13648 break;
13649 }
13650
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013651 case Translation::COMPILED_STUB_FRAME: {
13652 Code::Kind stub_kind = static_cast<Code::Kind>(iterator.Next());
13653 os << "{kind=" << stub_kind << "}";
Ben Murdoch69a99ed2011-11-30 16:03:39 +000013654 break;
13655 }
13656
Ben Murdoch3ef787d2012-04-12 10:51:47 +010013657 case Translation::ARGUMENTS_ADAPTOR_FRAME:
13658 case Translation::CONSTRUCT_STUB_FRAME: {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000013659 int shared_info_id = iterator.Next();
13660 Object* shared_info = LiteralArray()->get(shared_info_id);
Ben Murdoch3ef787d2012-04-12 10:51:47 +010013661 unsigned height = iterator.Next();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000013662 os << "{function="
13663 << Brief(SharedFunctionInfo::cast(shared_info)->DebugName())
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013664 << ", height=" << height << "}";
Ben Murdoch3ef787d2012-04-12 10:51:47 +010013665 break;
13666 }
13667
Ben Murdochda12d292016-06-02 14:46:10 +010013668 case Translation::TAIL_CALLER_FRAME: {
13669 int shared_info_id = iterator.Next();
13670 Object* shared_info = LiteralArray()->get(shared_info_id);
13671 os << "{function="
13672 << Brief(SharedFunctionInfo::cast(shared_info)->DebugName())
13673 << "}";
13674 break;
13675 }
13676
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013677 case Translation::GETTER_STUB_FRAME:
13678 case Translation::SETTER_STUB_FRAME: {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000013679 int shared_info_id = iterator.Next();
13680 Object* shared_info = LiteralArray()->get(shared_info_id);
13681 os << "{function=" << Brief(SharedFunctionInfo::cast(shared_info)
13682 ->DebugName()) << "}";
Ben Murdoch69a99ed2011-11-30 16:03:39 +000013683 break;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013684 }
Ben Murdoch69a99ed2011-11-30 16:03:39 +000013685
13686 case Translation::REGISTER: {
13687 int reg_code = iterator.Next();
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013688 os << "{input=" << converter.NameOfCPURegister(reg_code) << "}";
Ben Murdoch69a99ed2011-11-30 16:03:39 +000013689 break;
13690 }
13691
13692 case Translation::INT32_REGISTER: {
13693 int reg_code = iterator.Next();
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013694 os << "{input=" << converter.NameOfCPURegister(reg_code) << "}";
13695 break;
13696 }
13697
13698 case Translation::UINT32_REGISTER: {
13699 int reg_code = iterator.Next();
13700 os << "{input=" << converter.NameOfCPURegister(reg_code)
13701 << " (unsigned)}";
Ben Murdoch69a99ed2011-11-30 16:03:39 +000013702 break;
13703 }
13704
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000013705 case Translation::BOOL_REGISTER: {
13706 int reg_code = iterator.Next();
13707 os << "{input=" << converter.NameOfCPURegister(reg_code)
13708 << " (bool)}";
13709 break;
13710 }
13711
Ben Murdoch69a99ed2011-11-30 16:03:39 +000013712 case Translation::DOUBLE_REGISTER: {
13713 int reg_code = iterator.Next();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000013714 os << "{input=" << DoubleRegister::from_code(reg_code).ToString()
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013715 << "}";
Ben Murdoch69a99ed2011-11-30 16:03:39 +000013716 break;
13717 }
13718
13719 case Translation::STACK_SLOT: {
13720 int input_slot_index = iterator.Next();
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013721 os << "{input=" << input_slot_index << "}";
Ben Murdoch69a99ed2011-11-30 16:03:39 +000013722 break;
13723 }
13724
13725 case Translation::INT32_STACK_SLOT: {
13726 int input_slot_index = iterator.Next();
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013727 os << "{input=" << input_slot_index << "}";
13728 break;
13729 }
13730
13731 case Translation::UINT32_STACK_SLOT: {
13732 int input_slot_index = iterator.Next();
13733 os << "{input=" << input_slot_index << " (unsigned)}";
Ben Murdoch69a99ed2011-11-30 16:03:39 +000013734 break;
13735 }
13736
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000013737 case Translation::BOOL_STACK_SLOT: {
13738 int input_slot_index = iterator.Next();
13739 os << "{input=" << input_slot_index << " (bool)}";
13740 break;
13741 }
13742
Ben Murdoch69a99ed2011-11-30 16:03:39 +000013743 case Translation::DOUBLE_STACK_SLOT: {
13744 int input_slot_index = iterator.Next();
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013745 os << "{input=" << input_slot_index << "}";
Ben Murdoch69a99ed2011-11-30 16:03:39 +000013746 break;
13747 }
13748
13749 case Translation::LITERAL: {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000013750 int literal_index = iterator.Next();
13751 Object* literal_value = LiteralArray()->get(literal_index);
13752 os << "{literal_id=" << literal_index << " (" << Brief(literal_value)
13753 << ")}";
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013754 break;
13755 }
13756
13757 case Translation::DUPLICATED_OBJECT: {
13758 int object_index = iterator.Next();
13759 os << "{object_index=" << object_index << "}";
Ben Murdoch69a99ed2011-11-30 16:03:39 +000013760 break;
13761 }
13762
13763 case Translation::ARGUMENTS_OBJECT:
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013764 case Translation::CAPTURED_OBJECT: {
13765 int args_length = iterator.Next();
13766 os << "{length=" << args_length << "}";
Ben Murdoch69a99ed2011-11-30 16:03:39 +000013767 break;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013768 }
Ben Murdochb0fe1622011-05-05 13:52:32 +010013769 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013770 os << "\n";
Ben Murdochb0fe1622011-05-05 13:52:32 +010013771 }
Ben Murdochb0fe1622011-05-05 13:52:32 +010013772 }
13773}
13774
13775
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013776void DeoptimizationOutputData::DeoptimizationOutputDataPrint(
Emily Bernierd0a1eb72015-03-24 16:35:39 -040013777 std::ostream& os) { // NOLINT
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013778 os << "Deoptimization Output Data (deopt points = " << this->DeoptPoints()
13779 << ")\n";
Ben Murdochb0fe1622011-05-05 13:52:32 +010013780 if (this->DeoptPoints() == 0) return;
13781
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013782 os << "ast id pc state\n";
Ben Murdochb0fe1622011-05-05 13:52:32 +010013783 for (int i = 0; i < this->DeoptPoints(); i++) {
13784 int pc_and_state = this->PcAndState(i)->value();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000013785 os << std::setw(6) << this->AstId(i).ToInt() << " " << std::setw(8)
13786 << FullCodeGenerator::PcField::decode(pc_and_state) << " "
Ben Murdochc5610432016-08-08 18:44:38 +010013787 << Deoptimizer::BailoutStateToString(
13788 FullCodeGenerator::BailoutStateField::decode(pc_and_state))
13789 << "\n";
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000013790 }
13791}
13792
13793
13794void HandlerTable::HandlerTableRangePrint(std::ostream& os) {
13795 os << " from to hdlr\n";
13796 for (int i = 0; i < length(); i += kRangeEntrySize) {
13797 int pc_start = Smi::cast(get(i + kRangeStartIndex))->value();
13798 int pc_end = Smi::cast(get(i + kRangeEndIndex))->value();
13799 int handler_field = Smi::cast(get(i + kRangeHandlerIndex))->value();
13800 int handler_offset = HandlerOffsetField::decode(handler_field);
13801 CatchPrediction prediction = HandlerPredictionField::decode(handler_field);
Ben Murdoch097c5b22016-05-18 11:27:45 +010013802 int data = Smi::cast(get(i + kRangeDataIndex))->value();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000013803 os << " (" << std::setw(4) << pc_start << "," << std::setw(4) << pc_end
13804 << ") -> " << std::setw(4) << handler_offset
Ben Murdoch097c5b22016-05-18 11:27:45 +010013805 << " (prediction=" << prediction << ", data=" << data << ")\n";
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000013806 }
13807}
13808
13809
13810void HandlerTable::HandlerTableReturnPrint(std::ostream& os) {
13811 os << " off hdlr (c)\n";
13812 for (int i = 0; i < length(); i += kReturnEntrySize) {
13813 int pc_offset = Smi::cast(get(i + kReturnOffsetIndex))->value();
13814 int handler_field = Smi::cast(get(i + kReturnHandlerIndex))->value();
13815 int handler_offset = HandlerOffsetField::decode(handler_field);
13816 CatchPrediction prediction = HandlerPredictionField::decode(handler_field);
13817 os << " " << std::setw(4) << pc_offset << " -> " << std::setw(4)
13818 << handler_offset << " (prediction=" << prediction << ")\n";
Ben Murdochb0fe1622011-05-05 13:52:32 +010013819 }
13820}
13821
Ben Murdochb0fe1622011-05-05 13:52:32 +010013822
Steve Blocka7e24c12009-10-30 11:49:00 +000013823const char* Code::ICState2String(InlineCacheState state) {
13824 switch (state) {
13825 case UNINITIALIZED: return "UNINITIALIZED";
13826 case PREMONOMORPHIC: return "PREMONOMORPHIC";
13827 case MONOMORPHIC: return "MONOMORPHIC";
Ben Murdochc5610432016-08-08 18:44:38 +010013828 case RECOMPUTE_HANDLER:
13829 return "RECOMPUTE_HANDLER";
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013830 case POLYMORPHIC: return "POLYMORPHIC";
Steve Blocka7e24c12009-10-30 11:49:00 +000013831 case MEGAMORPHIC: return "MEGAMORPHIC";
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013832 case GENERIC: return "GENERIC";
13833 case DEBUG_STUB: return "DEBUG_STUB";
Steve Blocka7e24c12009-10-30 11:49:00 +000013834 }
13835 UNREACHABLE();
13836 return NULL;
13837}
13838
13839
Emily Bernierd0a1eb72015-03-24 16:35:39 -040013840void Code::PrintExtraICState(std::ostream& os, // NOLINT
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013841 Kind kind, ExtraICState extra) {
13842 os << "extra_ic_state = ";
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000013843 if ((kind == STORE_IC || kind == KEYED_STORE_IC) &&
13844 is_strict(static_cast<LanguageMode>(extra))) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013845 os << "STRICT\n";
Steve Block1e0659c2011-05-24 12:43:12 +010013846 } else {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013847 os << extra << "\n";
Steve Block1e0659c2011-05-24 12:43:12 +010013848 }
13849}
13850
13851
Emily Bernierd0a1eb72015-03-24 16:35:39 -040013852void Code::Disassemble(const char* name, std::ostream& os) { // NOLINT
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013853 os << "kind = " << Kind2String(kind()) << "\n";
13854 if (IsCodeStubOrIC()) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000013855 const char* n = CodeStub::MajorName(CodeStub::GetMajorKey(this));
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013856 os << "major_key = " << (n == NULL ? "null" : n) << "\n";
13857 }
Steve Blocka7e24c12009-10-30 11:49:00 +000013858 if (is_inline_cache_stub()) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013859 os << "ic_state = " << ICState2String(ic_state()) << "\n";
13860 PrintExtraICState(os, kind(), extra_ic_state());
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013861 if (is_compare_ic_stub()) {
13862 DCHECK(CodeStub::GetMajorKey(this) == CodeStub::CompareIC);
13863 CompareICStub stub(stub_key(), GetIsolate());
13864 os << "compare_state = " << CompareICState::GetStateName(stub.left())
13865 << "*" << CompareICState::GetStateName(stub.right()) << " -> "
13866 << CompareICState::GetStateName(stub.state()) << "\n";
13867 os << "compare_operation = " << Token::Name(stub.op()) << "\n";
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000013868 }
Steve Blocka7e24c12009-10-30 11:49:00 +000013869 }
Ben Murdochda12d292016-06-02 14:46:10 +010013870 if ((name != nullptr) && (name[0] != '\0')) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013871 os << "name = " << name << "\n";
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000013872 } else if (kind() == BUILTIN) {
13873 name = GetIsolate()->builtins()->Lookup(instruction_start());
Ben Murdochda12d292016-06-02 14:46:10 +010013874 if (name != nullptr) {
13875 os << "name = " << name << "\n";
13876 }
13877 } else if (kind() == BYTECODE_HANDLER) {
13878 name = GetIsolate()->interpreter()->LookupNameOfBytecodeHandler(this);
13879 if (name != nullptr) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000013880 os << "name = " << name << "\n";
13881 }
Ben Murdochb0fe1622011-05-05 13:52:32 +010013882 }
13883 if (kind() == OPTIMIZED_FUNCTION) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013884 os << "stack_slots = " << stack_slots() << "\n";
Steve Blocka7e24c12009-10-30 11:49:00 +000013885 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000013886 os << "compiler = " << (is_turbofanned()
13887 ? "turbofan"
13888 : is_crankshafted() ? "crankshaft"
13889 : kind() == Code::FUNCTION
13890 ? "full-codegen"
13891 : "unknown") << "\n";
Steve Blocka7e24c12009-10-30 11:49:00 +000013892
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013893 os << "Instructions (size = " << instruction_size() << ")\n";
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013894 {
Emily Bernierd0a1eb72015-03-24 16:35:39 -040013895 Isolate* isolate = GetIsolate();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000013896 int size = instruction_size();
13897 int safepoint_offset =
13898 is_crankshafted() ? static_cast<int>(safepoint_table_offset()) : size;
13899 int back_edge_offset = (kind() == Code::FUNCTION)
13900 ? static_cast<int>(back_edge_table_offset())
13901 : size;
13902 int constant_pool_offset = FLAG_enable_embedded_constant_pool
13903 ? this->constant_pool_offset()
13904 : size;
13905
13906 // Stop before reaching any embedded tables
13907 int code_size = Min(safepoint_offset, back_edge_offset);
13908 code_size = Min(code_size, constant_pool_offset);
Emily Bernierd0a1eb72015-03-24 16:35:39 -040013909 byte* begin = instruction_start();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000013910 byte* end = begin + code_size;
Emily Bernierd0a1eb72015-03-24 16:35:39 -040013911 Disassembler::Decode(isolate, &os, begin, end, this);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000013912
13913 if (constant_pool_offset < size) {
13914 int constant_pool_size = size - constant_pool_offset;
13915 DCHECK((constant_pool_size & kPointerAlignmentMask) == 0);
13916 os << "\nConstant Pool (size = " << constant_pool_size << ")\n";
13917 Vector<char> buf = Vector<char>::New(50);
13918 intptr_t* ptr = reinterpret_cast<intptr_t*>(begin + constant_pool_offset);
13919 for (int i = 0; i < constant_pool_size; i += kPointerSize, ptr++) {
13920 SNPrintF(buf, "%4d %08" V8PRIxPTR, i, *ptr);
13921 os << static_cast<const void*>(ptr) << " " << buf.start() << "\n";
13922 }
13923 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013924 }
13925 os << "\n";
Ben Murdochb0fe1622011-05-05 13:52:32 +010013926
Ben Murdochb0fe1622011-05-05 13:52:32 +010013927 if (kind() == FUNCTION) {
13928 DeoptimizationOutputData* data =
13929 DeoptimizationOutputData::cast(this->deoptimization_data());
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013930 data->DeoptimizationOutputDataPrint(os);
Ben Murdochb0fe1622011-05-05 13:52:32 +010013931 } else if (kind() == OPTIMIZED_FUNCTION) {
13932 DeoptimizationInputData* data =
13933 DeoptimizationInputData::cast(this->deoptimization_data());
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013934 data->DeoptimizationInputDataPrint(os);
Ben Murdochb0fe1622011-05-05 13:52:32 +010013935 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013936 os << "\n";
Ben Murdochb0fe1622011-05-05 13:52:32 +010013937
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013938 if (is_crankshafted()) {
Ben Murdochb0fe1622011-05-05 13:52:32 +010013939 SafepointTable table(this);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013940 os << "Safepoints (size = " << table.size() << ")\n";
Ben Murdochb0fe1622011-05-05 13:52:32 +010013941 for (unsigned i = 0; i < table.length(); i++) {
13942 unsigned pc_offset = table.GetPcOffset(i);
Emily Bernierd0a1eb72015-03-24 16:35:39 -040013943 os << static_cast<const void*>(instruction_start() + pc_offset) << " ";
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000013944 os << std::setw(4) << pc_offset << " ";
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013945 table.PrintEntry(i, os);
13946 os << " (sp -> fp) ";
Ben Murdochb8e0da22011-05-16 14:20:40 +010013947 SafepointEntry entry = table.GetEntry(i);
13948 if (entry.deoptimization_index() != Safepoint::kNoDeoptimizationIndex) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000013949 os << std::setw(6) << entry.deoptimization_index();
Ben Murdochb0fe1622011-05-05 13:52:32 +010013950 } else {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013951 os << "<none>";
Ben Murdochb0fe1622011-05-05 13:52:32 +010013952 }
Ben Murdochb8e0da22011-05-16 14:20:40 +010013953 if (entry.argument_count() > 0) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013954 os << " argc: " << entry.argument_count();
Ben Murdochb8e0da22011-05-16 14:20:40 +010013955 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013956 os << "\n";
Ben Murdochb0fe1622011-05-05 13:52:32 +010013957 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013958 os << "\n";
Ben Murdochb0fe1622011-05-05 13:52:32 +010013959 } else if (kind() == FUNCTION) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013960 unsigned offset = back_edge_table_offset();
13961 // If there is no back edge table, the "table start" will be at or after
Ben Murdochb0fe1622011-05-05 13:52:32 +010013962 // (due to alignment) the end of the instruction stream.
13963 if (static_cast<int>(offset) < instruction_size()) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013964 DisallowHeapAllocation no_gc;
13965 BackEdgeTable back_edges(this, &no_gc);
13966
13967 os << "Back edges (size = " << back_edges.length() << ")\n";
13968 os << "ast_id pc_offset loop_depth\n";
13969
13970 for (uint32_t i = 0; i < back_edges.length(); i++) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000013971 os << std::setw(6) << back_edges.ast_id(i).ToInt() << " "
13972 << std::setw(9) << back_edges.pc_offset(i) << " " << std::setw(10)
13973 << back_edges.loop_depth(i) << "\n";
Ben Murdochb0fe1622011-05-05 13:52:32 +010013974 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013975
13976 os << "\n";
Ben Murdochb0fe1622011-05-05 13:52:32 +010013977 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013978#ifdef OBJECT_PRINT
13979 if (!type_feedback_info()->IsUndefined()) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013980 TypeFeedbackInfo::cast(type_feedback_info())->TypeFeedbackInfoPrint(os);
13981 os << "\n";
13982 }
13983#endif
Ben Murdochb0fe1622011-05-05 13:52:32 +010013984 }
Steve Blocka7e24c12009-10-30 11:49:00 +000013985
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000013986 if (handler_table()->length() > 0) {
13987 os << "Handler Table (size = " << handler_table()->Size() << ")\n";
13988 if (kind() == FUNCTION) {
13989 HandlerTable::cast(handler_table())->HandlerTableRangePrint(os);
13990 } else if (kind() == OPTIMIZED_FUNCTION) {
13991 HandlerTable::cast(handler_table())->HandlerTableReturnPrint(os);
13992 }
13993 os << "\n";
13994 }
13995
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013996 os << "RelocInfo (size = " << relocation_size() << ")\n";
13997 for (RelocIterator it(this); !it.done(); it.next()) {
13998 it.rinfo()->Print(GetIsolate(), os);
13999 }
14000 os << "\n";
Steve Blocka7e24c12009-10-30 11:49:00 +000014001}
14002#endif // ENABLE_DISASSEMBLER
14003
Ben Murdoch097c5b22016-05-18 11:27:45 +010014004int BytecodeArray::SourcePosition(int offset) {
14005 int last_position = 0;
Ben Murdochda12d292016-06-02 14:46:10 +010014006 for (interpreter::SourcePositionTableIterator iterator(
14007 source_position_table());
Ben Murdoch097c5b22016-05-18 11:27:45 +010014008 !iterator.done() && iterator.bytecode_offset() <= offset;
14009 iterator.Advance()) {
14010 last_position = iterator.source_position();
14011 }
14012 return last_position;
14013}
14014
14015int BytecodeArray::SourceStatementPosition(int offset) {
14016 // First find the position as close as possible using all position
14017 // information.
14018 int position = SourcePosition(offset);
14019 // Now find the closest statement position before the position.
14020 int statement_position = 0;
Ben Murdochda12d292016-06-02 14:46:10 +010014021 interpreter::SourcePositionTableIterator iterator(source_position_table());
Ben Murdoch097c5b22016-05-18 11:27:45 +010014022 while (!iterator.done()) {
14023 if (iterator.is_statement()) {
14024 int p = iterator.source_position();
14025 if (statement_position < p && p <= position) {
14026 statement_position = p;
14027 }
14028 }
14029 iterator.Advance();
14030 }
14031 return statement_position;
14032}
Steve Blocka7e24c12009-10-30 11:49:00 +000014033
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000014034void BytecodeArray::Disassemble(std::ostream& os) {
14035 os << "Parameter count " << parameter_count() << "\n";
14036 os << "Frame size " << frame_size() << "\n";
Steve Block8defd9f2010-07-08 12:39:36 +010014037
Ben Murdochda12d292016-06-02 14:46:10 +010014038 const uint8_t* base_address = GetFirstBytecodeAddress();
14039 interpreter::SourcePositionTableIterator source_positions(
14040 source_position_table());
Ben Murdoch097c5b22016-05-18 11:27:45 +010014041
Ben Murdochda12d292016-06-02 14:46:10 +010014042 interpreter::BytecodeArrayIterator iterator(handle(this));
14043 while (!iterator.done()) {
14044 if (!source_positions.done() &&
14045 iterator.current_offset() == source_positions.bytecode_offset()) {
Ben Murdoch097c5b22016-05-18 11:27:45 +010014046 os << std::setw(5) << source_positions.source_position();
14047 os << (source_positions.is_statement() ? " S> " : " E> ");
14048 source_positions.Advance();
14049 } else {
14050 os << " ";
14051 }
Ben Murdochda12d292016-06-02 14:46:10 +010014052 const uint8_t* current_address = base_address + iterator.current_offset();
Ben Murdochc5610432016-08-08 18:44:38 +010014053 os << reinterpret_cast<const void*>(current_address) << " @ "
14054 << std::setw(4) << iterator.current_offset() << " : ";
Ben Murdochda12d292016-06-02 14:46:10 +010014055 interpreter::Bytecodes::Decode(os, current_address, parameter_count());
14056 if (interpreter::Bytecodes::IsJump(iterator.current_bytecode())) {
Ben Murdochc5610432016-08-08 18:44:38 +010014057 const void* jump_target = base_address + iterator.GetJumpTargetOffset();
14058 os << " (" << jump_target << " @ " << iterator.GetJumpTargetOffset()
14059 << ")";
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014060 }
Ben Murdoch097c5b22016-05-18 11:27:45 +010014061 os << std::endl;
Ben Murdochda12d292016-06-02 14:46:10 +010014062 iterator.Advance();
Ben Murdoch3ef787d2012-04-12 10:51:47 +010014063 }
14064
Ben Murdoch097c5b22016-05-18 11:27:45 +010014065 if (constant_pool()->length() > 0) {
14066 os << "Constant pool (size = " << constant_pool()->length() << ")\n";
14067 constant_pool()->Print();
14068 }
14069
14070#ifdef ENABLE_DISASSEMBLER
14071 if (handler_table()->length() > 0) {
14072 os << "Handler Table (size = " << handler_table()->Size() << ")\n";
14073 HandlerTable::cast(handler_table())->HandlerTableRangePrint(os);
14074 }
14075#endif
Steve Blocka7e24c12009-10-30 11:49:00 +000014076}
14077
Ben Murdoch097c5b22016-05-18 11:27:45 +010014078void BytecodeArray::CopyBytecodesTo(BytecodeArray* to) {
14079 BytecodeArray* from = this;
14080 DCHECK_EQ(from->length(), to->length());
14081 CopyBytes(to->GetFirstBytecodeAddress(), from->GetFirstBytecodeAddress(),
14082 from->length());
14083}
Steve Blocka7e24c12009-10-30 11:49:00 +000014084
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014085// static
14086void JSArray::Initialize(Handle<JSArray> array, int capacity, int length) {
14087 DCHECK(capacity >= 0);
14088 array->GetIsolate()->factory()->NewJSArrayStorage(
14089 array, length, capacity, INITIALIZE_ARRAY_ELEMENTS_WITH_HOLE);
14090}
14091
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000014092void JSArray::SetLength(Handle<JSArray> array, uint32_t new_length) {
Steve Block3ce2e202009-11-05 08:53:23 +000014093 // We should never end in here with a pixel or external array.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000014094 DCHECK(array->AllowsSetLength());
14095 if (array->SetLengthWouldNormalize(new_length)) {
14096 JSObject::NormalizeElements(array);
14097 }
14098 array->GetElementsAccessor()->SetLength(array, new_length);
14099}
14100
14101
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014102// static
14103void Map::AddDependentCode(Handle<Map> map,
14104 DependentCode::DependencyGroup group,
14105 Handle<Code> code) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000014106 Handle<WeakCell> cell = Code::WeakCellFor(code);
14107 Handle<DependentCode> codes = DependentCode::InsertWeakCode(
14108 Handle<DependentCode>(map->dependent_code()), group, cell);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014109 if (*codes != map->dependent_code()) map->set_dependent_code(*codes);
14110}
14111
14112
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000014113Handle<DependentCode> DependentCode::InsertCompilationDependencies(
14114 Handle<DependentCode> entries, DependencyGroup group,
14115 Handle<Foreign> info) {
14116 return Insert(entries, group, info);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014117}
14118
14119
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000014120Handle<DependentCode> DependentCode::InsertWeakCode(
14121 Handle<DependentCode> entries, DependencyGroup group,
14122 Handle<WeakCell> code_cell) {
14123 return Insert(entries, group, code_cell);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014124}
14125
14126
14127Handle<DependentCode> DependentCode::Insert(Handle<DependentCode> entries,
14128 DependencyGroup group,
14129 Handle<Object> object) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000014130 if (entries->length() == 0 || entries->group() > group) {
14131 // There is no such group.
14132 return DependentCode::New(group, object, entries);
14133 }
14134 if (entries->group() < group) {
14135 // The group comes later in the list.
14136 Handle<DependentCode> old_next(entries->next_link());
14137 Handle<DependentCode> new_next = Insert(old_next, group, object);
14138 if (!old_next.is_identical_to(new_next)) {
14139 entries->set_next_link(*new_next);
14140 }
14141 return entries;
14142 }
14143 DCHECK_EQ(group, entries->group());
14144 int count = entries->count();
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014145 // Check for existing entry to avoid duplicates.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000014146 for (int i = 0; i < count; i++) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014147 if (entries->object_at(i) == *object) return entries;
14148 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000014149 if (entries->length() < kCodesStartIndex + count + 1) {
14150 entries = EnsureSpace(entries);
14151 // Count could have changed, reload it.
14152 count = entries->count();
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014153 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000014154 entries->set_object_at(count, *object);
14155 entries->set_count(count + 1);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014156 return entries;
14157}
14158
14159
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000014160Handle<DependentCode> DependentCode::New(DependencyGroup group,
14161 Handle<Object> object,
14162 Handle<DependentCode> next) {
14163 Isolate* isolate = next->GetIsolate();
14164 Handle<DependentCode> result = Handle<DependentCode>::cast(
14165 isolate->factory()->NewFixedArray(kCodesStartIndex + 1, TENURED));
14166 result->set_next_link(*next);
14167 result->set_flags(GroupField::encode(group) | CountField::encode(1));
14168 result->set_object_at(0, *object);
14169 return result;
14170}
14171
14172
14173Handle<DependentCode> DependentCode::EnsureSpace(
14174 Handle<DependentCode> entries) {
14175 if (entries->Compact()) return entries;
14176 Isolate* isolate = entries->GetIsolate();
14177 int capacity = kCodesStartIndex + DependentCode::Grow(entries->count());
14178 int grow_by = capacity - entries->length();
14179 return Handle<DependentCode>::cast(
14180 isolate->factory()->CopyFixedArrayAndGrow(entries, grow_by, TENURED));
14181}
14182
14183
14184bool DependentCode::Compact() {
14185 int old_count = count();
14186 int new_count = 0;
14187 for (int i = 0; i < old_count; i++) {
14188 Object* obj = object_at(i);
14189 if (!obj->IsWeakCell() || !WeakCell::cast(obj)->cleared()) {
14190 if (i != new_count) {
14191 copy(i, new_count);
14192 }
14193 new_count++;
14194 }
14195 }
14196 set_count(new_count);
14197 for (int i = new_count; i < old_count; i++) {
14198 clear_at(i);
14199 }
14200 return new_count < old_count;
14201}
14202
14203
14204void DependentCode::UpdateToFinishedCode(DependencyGroup group, Foreign* info,
14205 WeakCell* code_cell) {
14206 if (this->length() == 0 || this->group() > group) {
14207 // There is no such group.
14208 return;
14209 }
14210 if (this->group() < group) {
14211 // The group comes later in the list.
14212 next_link()->UpdateToFinishedCode(group, info, code_cell);
14213 return;
14214 }
14215 DCHECK_EQ(group, this->group());
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014216 DisallowHeapAllocation no_gc;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000014217 int count = this->count();
14218 for (int i = 0; i < count; i++) {
14219 if (object_at(i) == info) {
14220 set_object_at(i, code_cell);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014221 break;
14222 }
14223 }
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000014224#ifdef DEBUG
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000014225 for (int i = 0; i < count; i++) {
14226 DCHECK(object_at(i) != info);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014227 }
14228#endif
14229}
14230
14231
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000014232void DependentCode::RemoveCompilationDependencies(
14233 DependentCode::DependencyGroup group, Foreign* info) {
14234 if (this->length() == 0 || this->group() > group) {
14235 // There is no such group.
14236 return;
14237 }
14238 if (this->group() < group) {
14239 // The group comes later in the list.
14240 next_link()->RemoveCompilationDependencies(group, info);
14241 return;
14242 }
14243 DCHECK_EQ(group, this->group());
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014244 DisallowHeapAllocation no_allocation;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000014245 int old_count = count();
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014246 // Find compilation info wrapper.
14247 int info_pos = -1;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000014248 for (int i = 0; i < old_count; i++) {
14249 if (object_at(i) == info) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014250 info_pos = i;
14251 break;
14252 }
14253 }
14254 if (info_pos == -1) return; // Not found.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000014255 // Use the last code to fill the gap.
14256 if (info_pos < old_count - 1) {
14257 copy(old_count - 1, info_pos);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014258 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000014259 clear_at(old_count - 1);
14260 set_count(old_count - 1);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014261
14262#ifdef DEBUG
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000014263 for (int i = 0; i < old_count - 1; i++) {
14264 DCHECK(object_at(i) != info);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014265 }
14266#endif
14267}
14268
14269
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000014270bool DependentCode::Contains(DependencyGroup group, WeakCell* code_cell) {
14271 if (this->length() == 0 || this->group() > group) {
14272 // There is no such group.
14273 return false;
14274 }
14275 if (this->group() < group) {
14276 // The group comes later in the list.
14277 return next_link()->Contains(group, code_cell);
14278 }
14279 DCHECK_EQ(group, this->group());
14280 int count = this->count();
14281 for (int i = 0; i < count; i++) {
14282 if (object_at(i) == code_cell) return true;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014283 }
14284 return false;
14285}
14286
14287
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000014288bool DependentCode::IsEmpty(DependencyGroup group) {
14289 if (this->length() == 0 || this->group() > group) {
14290 // There is no such group.
14291 return true;
14292 }
14293 if (this->group() < group) {
14294 // The group comes later in the list.
14295 return next_link()->IsEmpty(group);
14296 }
14297 DCHECK_EQ(group, this->group());
14298 return count() == 0;
14299}
14300
14301
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014302bool DependentCode::MarkCodeForDeoptimization(
14303 Isolate* isolate,
14304 DependentCode::DependencyGroup group) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000014305 if (this->length() == 0 || this->group() > group) {
14306 // There is no such group.
14307 return false;
14308 }
14309 if (this->group() < group) {
14310 // The group comes later in the list.
14311 return next_link()->MarkCodeForDeoptimization(isolate, group);
14312 }
14313 DCHECK_EQ(group, this->group());
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014314 DisallowHeapAllocation no_allocation_scope;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014315 // Mark all the code that needs to be deoptimized.
14316 bool marked = false;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000014317 bool invalidate_embedded_objects = group == kWeakCodeGroup;
14318 int count = this->count();
14319 for (int i = 0; i < count; i++) {
14320 Object* obj = object_at(i);
14321 if (obj->IsWeakCell()) {
14322 WeakCell* cell = WeakCell::cast(obj);
14323 if (cell->cleared()) continue;
14324 Code* code = Code::cast(cell->value());
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014325 if (!code->marked_for_deoptimization()) {
14326 SetMarkedForDeoptimization(code, group);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000014327 if (invalidate_embedded_objects) {
14328 code->InvalidateEmbeddedObjects();
14329 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014330 marked = true;
14331 }
14332 } else {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000014333 DCHECK(obj->IsForeign());
14334 CompilationDependencies* info =
14335 reinterpret_cast<CompilationDependencies*>(
14336 Foreign::cast(obj)->foreign_address());
14337 info->Abort();
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014338 }
14339 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000014340 for (int i = 0; i < count; i++) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014341 clear_at(i);
14342 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000014343 set_count(0);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014344 return marked;
14345}
14346
14347
14348void DependentCode::DeoptimizeDependentCodeGroup(
14349 Isolate* isolate,
14350 DependentCode::DependencyGroup group) {
14351 DCHECK(AllowCodeDependencyChange::IsAllowed());
14352 DisallowHeapAllocation no_allocation_scope;
14353 bool marked = MarkCodeForDeoptimization(isolate, group);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014354 if (marked) Deoptimizer::DeoptimizeMarkedCode(isolate);
14355}
14356
14357
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014358void DependentCode::SetMarkedForDeoptimization(Code* code,
14359 DependencyGroup group) {
14360 code->set_marked_for_deoptimization(true);
14361 if (FLAG_trace_deopt &&
14362 (code->deoptimization_data() != code->GetHeap()->empty_fixed_array())) {
14363 DeoptimizationInputData* deopt_data =
14364 DeoptimizationInputData::cast(code->deoptimization_data());
14365 CodeTracer::Scope scope(code->GetHeap()->isolate()->GetCodeTracer());
14366 PrintF(scope.file(), "[marking dependent code 0x%08" V8PRIxPTR
14367 " (opt #%d) for deoptimization, reason: %s]\n",
14368 reinterpret_cast<intptr_t>(code),
14369 deopt_data->OptimizationId()->value(), DependencyGroupName(group));
14370 }
14371}
14372
14373
14374const char* DependentCode::DependencyGroupName(DependencyGroup group) {
14375 switch (group) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014376 case kWeakCodeGroup:
14377 return "weak-code";
14378 case kTransitionGroup:
14379 return "transition";
14380 case kPrototypeCheckGroup:
14381 return "prototype-check";
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014382 case kPropertyCellChangedGroup:
14383 return "property-cell-changed";
14384 case kFieldTypeGroup:
14385 return "field-type";
14386 case kInitialMapChangedGroup:
14387 return "initial-map-changed";
14388 case kAllocationSiteTenuringChangedGroup:
14389 return "allocation-site-tenuring-changed";
14390 case kAllocationSiteTransitionChangedGroup:
14391 return "allocation-site-transition-changed";
14392 }
14393 UNREACHABLE();
14394 return "?";
14395}
14396
14397
14398Handle<Map> Map::TransitionToPrototype(Handle<Map> map,
Emily Bernierd0a1eb72015-03-24 16:35:39 -040014399 Handle<Object> prototype,
14400 PrototypeOptimizationMode mode) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000014401 Handle<Map> new_map = TransitionArray::GetPrototypeTransition(map, prototype);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014402 if (new_map.is_null()) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -040014403 new_map = Copy(map, "TransitionToPrototype");
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000014404 TransitionArray::PutPrototypeTransition(map, prototype, new_map);
14405 Map::SetPrototype(new_map, prototype, mode);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014406 }
14407 return new_map;
14408}
14409
14410
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000014411Maybe<bool> JSReceiver::SetPrototype(Handle<JSReceiver> object,
14412 Handle<Object> value, bool from_javascript,
14413 ShouldThrow should_throw) {
14414 if (object->IsJSProxy()) {
14415 return JSProxy::SetPrototype(Handle<JSProxy>::cast(object), value,
14416 from_javascript, should_throw);
14417 }
14418 return JSObject::SetPrototype(Handle<JSObject>::cast(object), value,
14419 from_javascript, should_throw);
14420}
14421
14422
14423// ES6: 9.5.2 [[SetPrototypeOf]] (V)
14424// static
14425Maybe<bool> JSProxy::SetPrototype(Handle<JSProxy> proxy, Handle<Object> value,
14426 bool from_javascript,
14427 ShouldThrow should_throw) {
14428 Isolate* isolate = proxy->GetIsolate();
Ben Murdochc5610432016-08-08 18:44:38 +010014429 STACK_CHECK(isolate, Nothing<bool>());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000014430 Handle<Name> trap_name = isolate->factory()->setPrototypeOf_string();
14431 // 1. Assert: Either Type(V) is Object or Type(V) is Null.
14432 DCHECK(value->IsJSReceiver() || value->IsNull());
14433 // 2. Let handler be the value of the [[ProxyHandler]] internal slot of O.
14434 Handle<Object> handler(proxy->handler(), isolate);
14435 // 3. If handler is null, throw a TypeError exception.
14436 // 4. Assert: Type(handler) is Object.
14437 if (proxy->IsRevoked()) {
14438 isolate->Throw(*isolate->factory()->NewTypeError(
14439 MessageTemplate::kProxyRevoked, trap_name));
14440 return Nothing<bool>();
14441 }
14442 // 5. Let target be the value of the [[ProxyTarget]] internal slot.
14443 Handle<JSReceiver> target(proxy->target(), isolate);
14444 // 6. Let trap be ? GetMethod(handler, "getPrototypeOf").
14445 Handle<Object> trap;
14446 ASSIGN_RETURN_ON_EXCEPTION_VALUE(
14447 isolate, trap,
14448 Object::GetMethod(Handle<JSReceiver>::cast(handler), trap_name),
14449 Nothing<bool>());
14450 // 7. If trap is undefined, then return target.[[SetPrototypeOf]]().
14451 if (trap->IsUndefined()) {
14452 return JSReceiver::SetPrototype(target, value, from_javascript,
14453 should_throw);
14454 }
14455 // 8. Let booleanTrapResult be ToBoolean(? Call(trap, handler, «target, V»)).
14456 Handle<Object> argv[] = {target, value};
14457 Handle<Object> trap_result;
14458 ASSIGN_RETURN_ON_EXCEPTION_VALUE(
14459 isolate, trap_result,
14460 Execution::Call(isolate, trap, handler, arraysize(argv), argv),
14461 Nothing<bool>());
14462 bool bool_trap_result = trap_result->BooleanValue();
Ben Murdoch097c5b22016-05-18 11:27:45 +010014463 // 9. If booleanTrapResult is false, return false.
14464 if (!bool_trap_result) {
14465 RETURN_FAILURE(
14466 isolate, should_throw,
14467 NewTypeError(MessageTemplate::kProxyTrapReturnedFalsish, trap_name));
14468 }
14469 // 10. Let extensibleTarget be ? IsExtensible(target).
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000014470 Maybe<bool> is_extensible = JSReceiver::IsExtensible(target);
14471 if (is_extensible.IsNothing()) return Nothing<bool>();
Ben Murdoch097c5b22016-05-18 11:27:45 +010014472 // 11. If extensibleTarget is true, return true.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000014473 if (is_extensible.FromJust()) {
14474 if (bool_trap_result) return Just(true);
14475 RETURN_FAILURE(
14476 isolate, should_throw,
14477 NewTypeError(MessageTemplate::kProxyTrapReturnedFalsish, trap_name));
14478 }
Ben Murdoch097c5b22016-05-18 11:27:45 +010014479 // 12. Let targetProto be ? target.[[GetPrototypeOf]]().
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000014480 Handle<Object> target_proto;
14481 ASSIGN_RETURN_ON_EXCEPTION_VALUE(isolate, target_proto,
Ben Murdoch097c5b22016-05-18 11:27:45 +010014482 JSReceiver::GetPrototype(isolate, target),
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000014483 Nothing<bool>());
Ben Murdoch097c5b22016-05-18 11:27:45 +010014484 // 13. If SameValue(V, targetProto) is false, throw a TypeError exception.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000014485 if (bool_trap_result && !value->SameValue(*target_proto)) {
14486 isolate->Throw(*isolate->factory()->NewTypeError(
14487 MessageTemplate::kProxySetPrototypeOfNonExtensible));
14488 return Nothing<bool>();
14489 }
Ben Murdoch097c5b22016-05-18 11:27:45 +010014490 // 14. Return true.
14491 return Just(true);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000014492}
14493
14494
14495Maybe<bool> JSObject::SetPrototype(Handle<JSObject> object,
14496 Handle<Object> value, bool from_javascript,
14497 ShouldThrow should_throw) {
14498 Isolate* isolate = object->GetIsolate();
14499
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014500#ifdef DEBUG
14501 int size = object->Size();
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000014502#endif
14503
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000014504 if (from_javascript) {
14505 if (object->IsAccessCheckNeeded() &&
14506 !isolate->MayAccess(handle(isolate->context()), object)) {
14507 isolate->ReportFailedAccessCheck(object);
14508 RETURN_VALUE_IF_SCHEDULED_EXCEPTION(isolate, Nothing<bool>());
14509 RETURN_FAILURE(isolate, should_throw,
14510 NewTypeError(MessageTemplate::kNoAccess));
14511 }
14512 } else {
14513 DCHECK(!object->IsAccessCheckNeeded());
14514 }
14515
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014516 Heap* heap = isolate->heap();
Andrei Popescu402d9372010-02-26 13:31:12 +000014517 // Silently ignore the change if value is not a JSObject or null.
14518 // SpiderMonkey behaves this way.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000014519 if (!value->IsJSReceiver() && !value->IsNull()) return Just(true);
14520
14521 bool dictionary_elements_in_chain =
14522 object->map()->DictionaryElementsInPrototypeChainOnly();
14523
14524 bool all_extensible = object->map()->is_extensible();
14525 Handle<JSObject> real_receiver = object;
14526 if (from_javascript) {
14527 // Find the first object in the chain whose prototype object is not
14528 // hidden.
Ben Murdoch097c5b22016-05-18 11:27:45 +010014529 PrototypeIterator iter(isolate, real_receiver,
14530 PrototypeIterator::START_AT_PROTOTYPE,
14531 PrototypeIterator::END_AT_NON_HIDDEN);
14532 while (!iter.IsAtEnd()) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000014533 // Casting to JSObject is fine because hidden prototypes are never
14534 // JSProxies.
14535 real_receiver = PrototypeIterator::GetCurrent<JSObject>(iter);
14536 iter.Advance();
14537 all_extensible = all_extensible && real_receiver->map()->is_extensible();
14538 }
14539 }
14540 Handle<Map> map(real_receiver->map());
14541
14542 // Nothing to do if prototype is already set.
14543 if (map->prototype() == *value) return Just(true);
Andrei Popescu402d9372010-02-26 13:31:12 +000014544
Ben Murdoch8b112d22011-06-08 16:22:53 +010014545 // From 8.6.2 Object Internal Methods
14546 // ...
14547 // In addition, if [[Extensible]] is false the value of the [[Class]] and
14548 // [[Prototype]] internal properties of the object may not be modified.
14549 // ...
14550 // Implementation specific extensions that modify [[Class]], [[Prototype]]
14551 // or [[Extensible]] must not violate the invariants defined in the preceding
14552 // paragraph.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000014553 if (!all_extensible) {
14554 RETURN_FAILURE(isolate, should_throw,
14555 NewTypeError(MessageTemplate::kNonExtensibleProto, object));
Ben Murdoch8b112d22011-06-08 16:22:53 +010014556 }
14557
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000014558 // Before we can set the prototype we need to be sure prototype cycles are
14559 // prevented. It is sufficient to validate that the receiver is not in the
14560 // new prototype chain.
Ben Murdoch097c5b22016-05-18 11:27:45 +010014561 if (value->IsJSReceiver()) {
14562 for (PrototypeIterator iter(isolate, JSReceiver::cast(*value),
14563 PrototypeIterator::START_AT_RECEIVER);
14564 !iter.IsAtEnd(); iter.Advance()) {
14565 if (iter.GetCurrent<JSReceiver>() == *object) {
14566 // Cycle detected.
14567 RETURN_FAILURE(isolate, should_throw,
14568 NewTypeError(MessageTemplate::kCyclicProto));
14569 }
Andrei Popescu402d9372010-02-26 13:31:12 +000014570 }
14571 }
14572
14573 // Set the new prototype of the object.
Steve Block053d10c2011-06-13 19:13:29 +010014574
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000014575 isolate->UpdateArrayProtectorOnSetPrototype(real_receiver);
Steve Block053d10c2011-06-13 19:13:29 +010014576
Emily Bernierd0a1eb72015-03-24 16:35:39 -040014577 PrototypeOptimizationMode mode =
14578 from_javascript ? REGULAR_PROTOTYPE : FAST_PROTOTYPE;
14579 Handle<Map> new_map = Map::TransitionToPrototype(map, value, mode);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014580 DCHECK(new_map->prototype() == *value);
14581 JSObject::MigrateToMap(real_receiver, new_map);
14582
Emily Bernierd0a1eb72015-03-24 16:35:39 -040014583 if (from_javascript && !dictionary_elements_in_chain &&
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014584 new_map->DictionaryElementsInPrototypeChainOnly()) {
14585 // If the prototype chain didn't previously have element callbacks, then
14586 // KeyedStoreICs need to be cleared to ensure any that involve this
14587 // map go generic.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000014588 TypeFeedbackVector::ClearAllKeyedStoreICs(isolate);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014589 }
Andrei Popescu402d9372010-02-26 13:31:12 +000014590
Steve Block44f0eee2011-05-26 01:26:41 +010014591 heap->ClearInstanceofCache();
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014592 DCHECK(size == object->Size());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000014593 return Just(true);
Andrei Popescu402d9372010-02-26 13:31:12 +000014594}
14595
14596
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014597void JSObject::EnsureCanContainElements(Handle<JSObject> object,
14598 Arguments* args,
14599 uint32_t first_arg,
14600 uint32_t arg_count,
14601 EnsureElementsMode mode) {
Ben Murdoch3ef787d2012-04-12 10:51:47 +010014602 // Elements in |Arguments| are ordered backwards (because they're on the
14603 // stack), but the method that's called here iterates over them in forward
14604 // direction.
14605 return EnsureCanContainElements(
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014606 object, args->arguments() - first_arg - (arg_count - 1), arg_count, mode);
Ben Murdoch592a9fc2012-03-05 11:04:45 +000014607}
14608
14609
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000014610ElementsAccessor* JSObject::GetElementsAccessor() {
14611 return ElementsAccessor::ForKind(GetElementsKind());
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014612}
14613
14614
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000014615void JSObject::ValidateElements(Handle<JSObject> object) {
14616#ifdef ENABLE_SLOW_DCHECKS
14617 if (FLAG_enable_slow_asserts) {
14618 ElementsAccessor* accessor = object->GetElementsAccessor();
14619 accessor->Validate(object);
Steve Blocka7e24c12009-10-30 11:49:00 +000014620 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000014621#endif
Steve Blocka7e24c12009-10-30 11:49:00 +000014622}
14623
14624
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000014625static bool ShouldConvertToSlowElements(JSObject* object, uint32_t capacity,
14626 uint32_t index,
14627 uint32_t* new_capacity) {
14628 STATIC_ASSERT(JSObject::kMaxUncheckedOldFastElementsLength <=
14629 JSObject::kMaxUncheckedFastElementsLength);
14630 if (index < capacity) {
14631 *new_capacity = capacity;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000014632 return false;
14633 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000014634 if (index - capacity >= JSObject::kMaxGap) return true;
14635 *new_capacity = JSObject::NewElementsCapacity(index + 1);
14636 DCHECK_LT(index, *new_capacity);
14637 if (*new_capacity <= JSObject::kMaxUncheckedOldFastElementsLength ||
14638 (*new_capacity <= JSObject::kMaxUncheckedFastElementsLength &&
14639 object->GetHeap()->InNewSpace(object))) {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000014640 return false;
14641 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000014642 // If the fast-case backing storage takes up roughly three times as
14643 // much space (in machine words) as a dictionary backing storage
14644 // would, the object should have slow elements.
14645 int used_elements = object->GetFastElementsUsage();
14646 int dictionary_size = SeededNumberDictionary::ComputeCapacity(used_elements) *
14647 SeededNumberDictionary::kEntrySize;
14648 return 3 * static_cast<uint32_t>(dictionary_size) <= *new_capacity;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000014649}
14650
14651
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000014652bool JSObject::WouldConvertToSlowElements(uint32_t index) {
14653 if (HasFastElements()) {
14654 Handle<FixedArrayBase> backing_store(FixedArrayBase::cast(elements()));
14655 uint32_t capacity = static_cast<uint32_t>(backing_store->length());
14656 uint32_t new_capacity;
14657 return ShouldConvertToSlowElements(this, capacity, index, &new_capacity);
14658 }
14659 return false;
14660}
14661
14662
14663static ElementsKind BestFittingFastElementsKind(JSObject* object) {
14664 if (object->HasSloppyArgumentsElements()) {
14665 return FAST_SLOPPY_ARGUMENTS_ELEMENTS;
14666 }
Ben Murdoch097c5b22016-05-18 11:27:45 +010014667 if (object->HasStringWrapperElements()) {
14668 return FAST_STRING_WRAPPER_ELEMENTS;
14669 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000014670 DCHECK(object->HasDictionaryElements());
14671 SeededNumberDictionary* dictionary = object->element_dictionary();
14672 ElementsKind kind = FAST_HOLEY_SMI_ELEMENTS;
14673 for (int i = 0; i < dictionary->Capacity(); i++) {
14674 Object* key = dictionary->KeyAt(i);
14675 if (key->IsNumber()) {
14676 Object* value = dictionary->ValueAt(i);
14677 if (!value->IsNumber()) return FAST_HOLEY_ELEMENTS;
14678 if (!value->IsSmi()) {
14679 if (!FLAG_unbox_double_arrays) return FAST_HOLEY_ELEMENTS;
14680 kind = FAST_HOLEY_DOUBLE_ELEMENTS;
14681 }
14682 }
14683 }
14684 return kind;
14685}
14686
14687
14688static bool ShouldConvertToFastElements(JSObject* object,
14689 SeededNumberDictionary* dictionary,
14690 uint32_t index,
14691 uint32_t* new_capacity) {
14692 // If properties with non-standard attributes or accessors were added, we
14693 // cannot go back to fast elements.
14694 if (dictionary->requires_slow_elements()) return false;
14695
14696 // Adding a property with this index will require slow elements.
14697 if (index >= static_cast<uint32_t>(Smi::kMaxValue)) return false;
14698
14699 if (object->IsJSArray()) {
14700 Object* length = JSArray::cast(object)->length();
14701 if (!length->IsSmi()) return false;
14702 *new_capacity = static_cast<uint32_t>(Smi::cast(length)->value());
14703 } else {
14704 *new_capacity = dictionary->max_number_key() + 1;
14705 }
14706 *new_capacity = Max(index + 1, *new_capacity);
14707
14708 uint32_t dictionary_size = static_cast<uint32_t>(dictionary->Capacity()) *
14709 SeededNumberDictionary::kEntrySize;
14710
14711 // Turn fast if the dictionary only saves 50% space.
14712 return 2 * dictionary_size >= *new_capacity;
14713}
14714
14715
14716// static
14717MaybeHandle<Object> JSObject::AddDataElement(Handle<JSObject> object,
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014718 uint32_t index,
14719 Handle<Object> value,
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000014720 PropertyAttributes attributes) {
14721 MAYBE_RETURN_NULL(
14722 AddDataElement(object, index, value, attributes, THROW_ON_ERROR));
Ben Murdoch3ef787d2012-04-12 10:51:47 +010014723 return value;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000014724}
14725
14726
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000014727// static
14728Maybe<bool> JSObject::AddDataElement(Handle<JSObject> object, uint32_t index,
14729 Handle<Object> value,
14730 PropertyAttributes attributes,
14731 ShouldThrow should_throw) {
14732 DCHECK(object->map()->is_extensible());
14733
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014734 Isolate* isolate = object->GetIsolate();
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000014735
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000014736 uint32_t old_length = 0;
14737 uint32_t new_capacity = 0;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000014738
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000014739 if (object->IsJSArray()) {
14740 CHECK(JSArray::cast(*object)->length()->ToArrayLength(&old_length));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000014741 }
14742
14743 ElementsKind kind = object->GetElementsKind();
14744 FixedArrayBase* elements = object->elements();
14745 ElementsKind dictionary_kind = DICTIONARY_ELEMENTS;
14746 if (IsSloppyArgumentsElements(kind)) {
14747 elements = FixedArrayBase::cast(FixedArray::cast(elements)->get(1));
14748 dictionary_kind = SLOW_SLOPPY_ARGUMENTS_ELEMENTS;
Ben Murdoch097c5b22016-05-18 11:27:45 +010014749 } else if (IsStringWrapperElementsKind(kind)) {
14750 dictionary_kind = SLOW_STRING_WRAPPER_ELEMENTS;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000014751 }
14752
14753 if (attributes != NONE) {
14754 kind = dictionary_kind;
14755 } else if (elements->IsSeededNumberDictionary()) {
14756 kind = ShouldConvertToFastElements(*object,
14757 SeededNumberDictionary::cast(elements),
14758 index, &new_capacity)
14759 ? BestFittingFastElementsKind(*object)
14760 : dictionary_kind; // Overwrite in case of arguments.
14761 } else if (ShouldConvertToSlowElements(
14762 *object, static_cast<uint32_t>(elements->length()), index,
14763 &new_capacity)) {
14764 kind = dictionary_kind;
14765 }
14766
14767 ElementsKind to = value->OptimalElementsKind();
14768 if (IsHoleyElementsKind(kind) || !object->IsJSArray() || index > old_length) {
14769 to = GetHoleyElementsKind(to);
14770 kind = GetHoleyElementsKind(kind);
14771 }
14772 to = GetMoreGeneralElementsKind(kind, to);
14773 ElementsAccessor* accessor = ElementsAccessor::ForKind(to);
14774 accessor->Add(object, index, value, attributes, new_capacity);
14775
14776 uint32_t new_length = old_length;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014777 Handle<Object> new_length_handle;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000014778 if (object->IsJSArray() && index >= old_length) {
14779 new_length = index + 1;
14780 new_length_handle = isolate->factory()->NewNumberFromUint(new_length);
14781 JSArray::cast(*object)->set_length(*new_length_handle);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014782 }
14783
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000014784 return Just(true);
Steve Blocka7e24c12009-10-30 11:49:00 +000014785}
14786
14787
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000014788bool JSArray::SetLengthWouldNormalize(uint32_t new_length) {
14789 if (!HasFastElements()) return false;
14790 uint32_t capacity = static_cast<uint32_t>(elements()->length());
14791 uint32_t new_capacity;
14792 return JSArray::SetLengthWouldNormalize(GetHeap(), new_length) &&
14793 ShouldConvertToSlowElements(this, capacity, new_length - 1,
14794 &new_capacity);
Steve Blocka7e24c12009-10-30 11:49:00 +000014795}
14796
14797
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014798const double AllocationSite::kPretenureRatio = 0.85;
14799
14800
14801void AllocationSite::ResetPretenureDecision() {
14802 set_pretenure_decision(kUndecided);
14803 set_memento_found_count(0);
14804 set_memento_create_count(0);
Ben Murdoch3ef787d2012-04-12 10:51:47 +010014805}
14806
14807
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014808PretenureFlag AllocationSite::GetPretenureMode() {
14809 PretenureDecision mode = pretenure_decision();
14810 // Zombie objects "decide" to be untenured.
14811 return mode == kTenure ? TENURED : NOT_TENURED;
14812}
Ben Murdoch3ef787d2012-04-12 10:51:47 +010014813
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014814
14815bool AllocationSite::IsNestedSite() {
14816 DCHECK(FLAG_trace_track_allocation_sites);
14817 Object* current = GetHeap()->allocation_sites_list();
14818 while (current->IsAllocationSite()) {
14819 AllocationSite* current_site = AllocationSite::cast(current);
14820 if (current_site->nested_site() == this) {
14821 return true;
Ben Murdoch3ef787d2012-04-12 10:51:47 +010014822 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014823 current = current_site->weak_next();
14824 }
14825 return false;
14826}
14827
14828
14829void AllocationSite::DigestTransitionFeedback(Handle<AllocationSite> site,
14830 ElementsKind to_kind) {
14831 Isolate* isolate = site->GetIsolate();
14832
14833 if (site->SitePointsToLiteral() && site->transition_info()->IsJSArray()) {
14834 Handle<JSArray> transition_info =
14835 handle(JSArray::cast(site->transition_info()));
14836 ElementsKind kind = transition_info->GetElementsKind();
14837 // if kind is holey ensure that to_kind is as well.
14838 if (IsHoleyElementsKind(kind)) {
14839 to_kind = GetHoleyElementsKind(to_kind);
14840 }
14841 if (IsMoreGeneralElementsKindTransition(kind, to_kind)) {
14842 // If the array is huge, it's not likely to be defined in a local
14843 // function, so we shouldn't make new instances of it very often.
14844 uint32_t length = 0;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000014845 CHECK(transition_info->length()->ToArrayLength(&length));
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014846 if (length <= kMaximumArrayBytesToPretransition) {
14847 if (FLAG_trace_track_allocation_sites) {
14848 bool is_nested = site->IsNestedSite();
14849 PrintF(
14850 "AllocationSite: JSArray %p boilerplate %s updated %s->%s\n",
14851 reinterpret_cast<void*>(*site),
14852 is_nested ? "(nested)" : "",
14853 ElementsKindToString(kind),
14854 ElementsKindToString(to_kind));
14855 }
14856 JSObject::TransitionElementsKind(transition_info, to_kind);
14857 site->dependent_code()->DeoptimizeDependentCodeGroup(
14858 isolate, DependentCode::kAllocationSiteTransitionChangedGroup);
14859 }
14860 }
14861 } else {
14862 ElementsKind kind = site->GetElementsKind();
14863 // if kind is holey ensure that to_kind is as well.
14864 if (IsHoleyElementsKind(kind)) {
14865 to_kind = GetHoleyElementsKind(to_kind);
14866 }
14867 if (IsMoreGeneralElementsKindTransition(kind, to_kind)) {
14868 if (FLAG_trace_track_allocation_sites) {
14869 PrintF("AllocationSite: JSArray %p site updated %s->%s\n",
14870 reinterpret_cast<void*>(*site),
14871 ElementsKindToString(kind),
14872 ElementsKindToString(to_kind));
14873 }
14874 site->SetElementsKind(to_kind);
14875 site->dependent_code()->DeoptimizeDependentCodeGroup(
14876 isolate, DependentCode::kAllocationSiteTransitionChangedGroup);
14877 }
14878 }
14879}
14880
14881
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014882const char* AllocationSite::PretenureDecisionName(PretenureDecision decision) {
14883 switch (decision) {
14884 case kUndecided: return "undecided";
14885 case kDontTenure: return "don't tenure";
14886 case kMaybeTenure: return "maybe tenure";
14887 case kTenure: return "tenure";
14888 case kZombie: return "zombie";
14889 default: UNREACHABLE();
14890 }
14891 return NULL;
14892}
14893
14894
14895void JSObject::UpdateAllocationSite(Handle<JSObject> object,
14896 ElementsKind to_kind) {
14897 if (!object->IsJSArray()) return;
14898
14899 Heap* heap = object->GetHeap();
14900 if (!heap->InNewSpace(*object)) return;
14901
14902 Handle<AllocationSite> site;
14903 {
14904 DisallowHeapAllocation no_allocation;
14905
Ben Murdoch097c5b22016-05-18 11:27:45 +010014906 AllocationMemento* memento =
14907 heap->FindAllocationMemento<Heap::kForRuntime>(*object);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014908 if (memento == NULL) return;
14909
14910 // Walk through to the Allocation Site
14911 site = handle(memento->GetAllocationSite());
14912 }
14913 AllocationSite::DigestTransitionFeedback(site, to_kind);
14914}
14915
14916
14917void JSObject::TransitionElementsKind(Handle<JSObject> object,
14918 ElementsKind to_kind) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000014919 ElementsKind from_kind = object->GetElementsKind();
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014920
14921 if (IsFastHoleyElementsKind(from_kind)) {
14922 to_kind = GetHoleyElementsKind(to_kind);
Ben Murdoch3ef787d2012-04-12 10:51:47 +010014923 }
14924
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014925 if (from_kind == to_kind) return;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014926
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000014927 // This method should never be called for any other case.
14928 DCHECK(IsFastElementsKind(from_kind));
14929 DCHECK(IsFastElementsKind(to_kind));
14930 DCHECK_NE(TERMINAL_FAST_ELEMENTS_KIND, from_kind);
14931
14932 UpdateAllocationSite(object, to_kind);
14933 if (object->elements() == object->GetHeap()->empty_fixed_array() ||
14934 IsFastDoubleElementsKind(from_kind) ==
14935 IsFastDoubleElementsKind(to_kind)) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014936 // No change is needed to the elements() buffer, the transition
14937 // only requires a map change.
14938 Handle<Map> new_map = GetElementsTransitionMap(object, to_kind);
14939 MigrateToMap(object, new_map);
14940 if (FLAG_trace_elements_transitions) {
14941 Handle<FixedArrayBase> elms(object->elements());
14942 PrintElementsTransition(stdout, object, from_kind, elms, to_kind, elms);
14943 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000014944 } else {
14945 DCHECK((IsFastSmiElementsKind(from_kind) &&
14946 IsFastDoubleElementsKind(to_kind)) ||
14947 (IsFastDoubleElementsKind(from_kind) &&
14948 IsFastObjectElementsKind(to_kind)));
14949 uint32_t c = static_cast<uint32_t>(object->elements()->length());
14950 ElementsAccessor::ForKind(to_kind)->GrowCapacityAndConvert(object, c);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014951 }
Ben Murdoch3ef787d2012-04-12 10:51:47 +010014952}
14953
14954
14955// static
14956bool Map::IsValidElementsTransition(ElementsKind from_kind,
14957 ElementsKind to_kind) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014958 // Transitions can't go backwards.
14959 if (!IsMoreGeneralElementsKindTransition(from_kind, to_kind)) {
14960 return false;
14961 }
14962
14963 // Transitions from HOLEY -> PACKED are not allowed.
14964 return !IsFastHoleyElementsKind(from_kind) ||
14965 IsFastHoleyElementsKind(to_kind);
Ben Murdoch3ef787d2012-04-12 10:51:47 +010014966}
14967
14968
Emily Bernierd0a1eb72015-03-24 16:35:39 -040014969bool JSArray::HasReadOnlyLength(Handle<JSArray> array) {
Ben Murdochda12d292016-06-02 14:46:10 +010014970 Map* map = array->map();
14971 // Fast path: "length" is the first fast property of arrays. Since it's not
14972 // configurable, it's guaranteed to be the first in the descriptor array.
14973 if (!map->is_dictionary_map()) {
14974 DCHECK(map->instance_descriptors()->GetKey(0) ==
14975 array->GetHeap()->length_string());
14976 return map->instance_descriptors()->GetDetails(0).IsReadOnly();
14977 }
14978
14979 Isolate* isolate = array->GetIsolate();
14980 LookupIterator it(array, isolate->factory()->length_string(), array,
Emily Bernierd0a1eb72015-03-24 16:35:39 -040014981 LookupIterator::OWN_SKIP_INTERCEPTOR);
Emily Bernierd0a1eb72015-03-24 16:35:39 -040014982 CHECK_EQ(LookupIterator::ACCESSOR, it.state());
14983 return it.IsReadOnly();
14984}
14985
14986
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014987bool JSArray::WouldChangeReadOnlyLength(Handle<JSArray> array,
14988 uint32_t index) {
14989 uint32_t length = 0;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000014990 CHECK(array->length()->ToArrayLength(&length));
Emily Bernierd0a1eb72015-03-24 16:35:39 -040014991 if (length <= index) return HasReadOnlyLength(array);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014992 return false;
14993}
14994
14995
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000014996template <typename BackingStore>
14997static int FastHoleyElementsUsage(JSObject* object, BackingStore* store) {
14998 int limit = object->IsJSArray()
14999 ? Smi::cast(JSArray::cast(object)->length())->value()
15000 : store->length();
Ben Murdoch69a99ed2011-11-30 16:03:39 +000015001 int used = 0;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000015002 for (int i = 0; i < limit; ++i) {
15003 if (!store->is_the_hole(i)) ++used;
15004 }
15005 return used;
Ben Murdoch69a99ed2011-11-30 16:03:39 +000015006}
15007
15008
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000015009int JSObject::GetFastElementsUsage() {
15010 FixedArrayBase* store = elements();
Steve Blocka7e24c12009-10-30 11:49:00 +000015011 switch (GetElementsKind()) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015012 case FAST_SMI_ELEMENTS:
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000015013 case FAST_DOUBLE_ELEMENTS:
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000015014 case FAST_ELEMENTS:
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000015015 return IsJSArray() ? Smi::cast(JSArray::cast(this)->length())->value()
15016 : store->length();
15017 case FAST_SLOPPY_ARGUMENTS_ELEMENTS:
15018 store = FixedArray::cast(FixedArray::cast(store)->get(1));
15019 // Fall through.
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015020 case FAST_HOLEY_SMI_ELEMENTS:
15021 case FAST_HOLEY_ELEMENTS:
Ben Murdoch097c5b22016-05-18 11:27:45 +010015022 case FAST_STRING_WRAPPER_ELEMENTS:
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000015023 return FastHoleyElementsUsage(this, FixedArray::cast(store));
15024 case FAST_HOLEY_DOUBLE_ELEMENTS:
15025 if (elements()->length() == 0) return 0;
15026 return FastHoleyElementsUsage(this, FixedDoubleArray::cast(store));
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015027
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000015028 case SLOW_SLOPPY_ARGUMENTS_ELEMENTS:
Ben Murdoch097c5b22016-05-18 11:27:45 +010015029 case SLOW_STRING_WRAPPER_ELEMENTS:
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000015030 case DICTIONARY_ELEMENTS:
Ben Murdoch097c5b22016-05-18 11:27:45 +010015031 case NO_ELEMENTS:
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015032#define TYPED_ARRAY_CASE(Type, type, TYPE, ctype, size) \
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015033 case TYPE##_ELEMENTS: \
15034
15035 TYPED_ARRAYS(TYPED_ARRAY_CASE)
15036#undef TYPED_ARRAY_CASE
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000015037 UNREACHABLE();
Steve Blocka7e24c12009-10-30 11:49:00 +000015038 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000015039 return 0;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000015040}
15041
15042
Steve Blocka7e24c12009-10-30 11:49:00 +000015043// Certain compilers request function template instantiation when they
15044// see the definition of the other template functions in the
15045// class. This requires us to have the template functions put
15046// together, so even though this function belongs in objects-debug.cc,
15047// we keep it here instead to satisfy certain compilers.
Ben Murdochb0fe1622011-05-05 13:52:32 +010015048#ifdef OBJECT_PRINT
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015049template <typename Derived, typename Shape, typename Key>
Emily Bernierd0a1eb72015-03-24 16:35:39 -040015050void Dictionary<Derived, Shape, Key>::Print(std::ostream& os) { // NOLINT
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000015051 int capacity = this->Capacity();
Steve Blocka7e24c12009-10-30 11:49:00 +000015052 for (int i = 0; i < capacity; i++) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000015053 Object* k = this->KeyAt(i);
15054 if (this->IsKey(k)) {
15055 os << "\n ";
Steve Blocka7e24c12009-10-30 11:49:00 +000015056 if (k->IsString()) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015057 String::cast(k)->StringPrint(os);
Steve Blocka7e24c12009-10-30 11:49:00 +000015058 } else {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015059 os << Brief(k);
Steve Blocka7e24c12009-10-30 11:49:00 +000015060 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000015061 os << ": " << Brief(this->ValueAt(i)) << " " << this->DetailsAt(i);
Steve Blocka7e24c12009-10-30 11:49:00 +000015062 }
15063 }
15064}
15065#endif
15066
15067
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015068template<typename Derived, typename Shape, typename Key>
15069void Dictionary<Derived, Shape, Key>::CopyValuesTo(FixedArray* elements) {
Steve Blocka7e24c12009-10-30 11:49:00 +000015070 int pos = 0;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000015071 int capacity = this->Capacity();
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015072 DisallowHeapAllocation no_gc;
Leon Clarke4515c472010-02-03 11:58:03 +000015073 WriteBarrierMode mode = elements->GetWriteBarrierMode(no_gc);
Steve Blocka7e24c12009-10-30 11:49:00 +000015074 for (int i = 0; i < capacity; i++) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000015075 Object* k = this->KeyAt(i);
15076 if (this->IsKey(k)) {
15077 elements->set(pos++, this->ValueAt(i), mode);
Steve Blocka7e24c12009-10-30 11:49:00 +000015078 }
15079 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015080 DCHECK(pos == elements->length());
Steve Blocka7e24c12009-10-30 11:49:00 +000015081}
15082
15083
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000015084MaybeHandle<Object> JSObject::GetPropertyWithInterceptor(LookupIterator* it,
15085 bool* done) {
15086 *done = false;
15087 Isolate* isolate = it->isolate();
15088 // Make sure that the top context does not change when doing callbacks or
15089 // interceptor calls.
15090 AssertNoContextChange ncc(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +000015091
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000015092 DCHECK_EQ(LookupIterator::INTERCEPTOR, it->state());
15093 Handle<InterceptorInfo> interceptor = it->GetInterceptor();
15094 if (interceptor->getter()->IsUndefined()) {
15095 return isolate->factory()->undefined_value();
Emily Bernierd0a1eb72015-03-24 16:35:39 -040015096 }
15097
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000015098 Handle<JSObject> holder = it->GetHolder<JSObject>();
Ben Murdochda12d292016-06-02 14:46:10 +010015099 Handle<Object> result;
15100 Handle<Object> receiver = it->GetReceiver();
15101 if (!receiver->IsJSReceiver()) {
15102 ASSIGN_RETURN_ON_EXCEPTION(
15103 isolate, receiver, Object::ConvertReceiver(isolate, receiver), Object);
15104 }
15105 PropertyCallbackArguments args(isolate, interceptor->data(), *receiver,
15106 *holder, Object::DONT_THROW);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015107
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000015108 if (it->IsElement()) {
15109 uint32_t index = it->index();
15110 v8::IndexedPropertyGetterCallback getter =
15111 v8::ToCData<v8::IndexedPropertyGetterCallback>(interceptor->getter());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000015112 result = args.Call(getter, index);
15113 } else {
15114 Handle<Name> name = it->name();
15115 DCHECK(!name->IsPrivate());
15116
15117 if (name->IsSymbol() && !interceptor->can_intercept_symbols()) {
15118 return isolate->factory()->undefined_value();
15119 }
15120
15121 v8::GenericNamedPropertyGetterCallback getter =
15122 v8::ToCData<v8::GenericNamedPropertyGetterCallback>(
15123 interceptor->getter());
Ben Murdochda12d292016-06-02 14:46:10 +010015124 result = args.Call(getter, name);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000015125 }
15126
15127 RETURN_EXCEPTION_IF_SCHEDULED_EXCEPTION(isolate, Object);
Ben Murdochda12d292016-06-02 14:46:10 +010015128 if (result.is_null()) return isolate->factory()->undefined_value();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000015129 *done = true;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015130 // Rebox handle before return
Ben Murdochda12d292016-06-02 14:46:10 +010015131 return handle(*result, isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +000015132}
15133
15134
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015135Maybe<bool> JSObject::HasRealNamedProperty(Handle<JSObject> object,
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000015136 Handle<Name> name) {
15137 LookupIterator it = LookupIterator::PropertyOrElement(
15138 name->GetIsolate(), object, name, LookupIterator::OWN_SKIP_INTERCEPTOR);
15139 return HasProperty(&it);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015140}
15141
15142
15143Maybe<bool> JSObject::HasRealElementProperty(Handle<JSObject> object,
15144 uint32_t index) {
15145 Isolate* isolate = object->GetIsolate();
Ben Murdochda12d292016-06-02 14:46:10 +010015146 LookupIterator it(isolate, object, index, object,
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000015147 LookupIterator::OWN_SKIP_INTERCEPTOR);
15148 return HasProperty(&it);
Steve Blocka7e24c12009-10-30 11:49:00 +000015149}
15150
15151
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015152Maybe<bool> JSObject::HasRealNamedCallbackProperty(Handle<JSObject> object,
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000015153 Handle<Name> name) {
15154 LookupIterator it = LookupIterator::PropertyOrElement(
15155 name->GetIsolate(), object, name, LookupIterator::OWN_SKIP_INTERCEPTOR);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015156 Maybe<PropertyAttributes> maybe_result = GetPropertyAttributes(&it);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000015157 return maybe_result.IsJust() ? Just(it.state() == LookupIterator::ACCESSOR)
15158 : Nothing<bool>();
Steve Blocka7e24c12009-10-30 11:49:00 +000015159}
15160
15161
15162void FixedArray::SwapPairs(FixedArray* numbers, int i, int j) {
15163 Object* temp = get(i);
15164 set(i, get(j));
15165 set(j, temp);
15166 if (this != numbers) {
15167 temp = numbers->get(i);
Ben Murdoch3ef787d2012-04-12 10:51:47 +010015168 numbers->set(i, Smi::cast(numbers->get(j)));
15169 numbers->set(j, Smi::cast(temp));
Steve Blocka7e24c12009-10-30 11:49:00 +000015170 }
15171}
15172
15173
15174static void InsertionSortPairs(FixedArray* content,
15175 FixedArray* numbers,
15176 int len) {
15177 for (int i = 1; i < len; i++) {
15178 int j = i;
15179 while (j > 0 &&
15180 (NumberToUint32(numbers->get(j - 1)) >
15181 NumberToUint32(numbers->get(j)))) {
15182 content->SwapPairs(numbers, j - 1, j);
15183 j--;
15184 }
15185 }
15186}
15187
15188
15189void HeapSortPairs(FixedArray* content, FixedArray* numbers, int len) {
15190 // In-place heap sort.
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015191 DCHECK(content->length() == numbers->length());
Steve Blocka7e24c12009-10-30 11:49:00 +000015192
15193 // Bottom-up max-heap construction.
15194 for (int i = 1; i < len; ++i) {
15195 int child_index = i;
15196 while (child_index > 0) {
15197 int parent_index = ((child_index + 1) >> 1) - 1;
15198 uint32_t parent_value = NumberToUint32(numbers->get(parent_index));
15199 uint32_t child_value = NumberToUint32(numbers->get(child_index));
15200 if (parent_value < child_value) {
15201 content->SwapPairs(numbers, parent_index, child_index);
15202 } else {
15203 break;
15204 }
15205 child_index = parent_index;
15206 }
15207 }
15208
15209 // Extract elements and create sorted array.
15210 for (int i = len - 1; i > 0; --i) {
15211 // Put max element at the back of the array.
15212 content->SwapPairs(numbers, 0, i);
15213 // Sift down the new top element.
15214 int parent_index = 0;
15215 while (true) {
15216 int child_index = ((parent_index + 1) << 1) - 1;
15217 if (child_index >= i) break;
15218 uint32_t child1_value = NumberToUint32(numbers->get(child_index));
15219 uint32_t child2_value = NumberToUint32(numbers->get(child_index + 1));
15220 uint32_t parent_value = NumberToUint32(numbers->get(parent_index));
15221 if (child_index + 1 >= i || child1_value > child2_value) {
15222 if (parent_value > child1_value) break;
15223 content->SwapPairs(numbers, parent_index, child_index);
15224 parent_index = child_index;
15225 } else {
15226 if (parent_value > child2_value) break;
15227 content->SwapPairs(numbers, parent_index, child_index + 1);
15228 parent_index = child_index + 1;
15229 }
15230 }
15231 }
15232}
15233
15234
15235// Sort this array and the numbers as pairs wrt. the (distinct) numbers.
15236void FixedArray::SortPairs(FixedArray* numbers, uint32_t len) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015237 DCHECK(this->length() == numbers->length());
Steve Blocka7e24c12009-10-30 11:49:00 +000015238 // For small arrays, simply use insertion sort.
15239 if (len <= 10) {
15240 InsertionSortPairs(this, numbers, len);
15241 return;
15242 }
15243 // Check the range of indices.
15244 uint32_t min_index = NumberToUint32(numbers->get(0));
15245 uint32_t max_index = min_index;
15246 uint32_t i;
15247 for (i = 1; i < len; i++) {
15248 if (NumberToUint32(numbers->get(i)) < min_index) {
15249 min_index = NumberToUint32(numbers->get(i));
15250 } else if (NumberToUint32(numbers->get(i)) > max_index) {
15251 max_index = NumberToUint32(numbers->get(i));
15252 }
15253 }
15254 if (max_index - min_index + 1 == len) {
15255 // Indices form a contiguous range, unless there are duplicates.
15256 // Do an in-place linear time sort assuming distinct numbers, but
15257 // avoid hanging in case they are not.
15258 for (i = 0; i < len; i++) {
15259 uint32_t p;
15260 uint32_t j = 0;
15261 // While the current element at i is not at its correct position p,
15262 // swap the elements at these two positions.
15263 while ((p = NumberToUint32(numbers->get(i)) - min_index) != i &&
15264 j++ < len) {
15265 SwapPairs(numbers, i, p);
15266 }
15267 }
15268 } else {
15269 HeapSortPairs(this, numbers, len);
15270 return;
15271 }
15272}
15273
Ben Murdochc5610432016-08-08 18:44:38 +010015274bool JSObject::WasConstructedFromApiFunction() {
15275 auto instance_type = map()->instance_type();
15276 bool is_api_object = instance_type == JS_API_OBJECT_TYPE ||
15277 instance_type == JS_SPECIAL_API_OBJECT_TYPE;
15278#ifdef ENABLE_SLOW_DCHECKS
15279 if (FLAG_enable_slow_asserts) {
15280 Object* maybe_constructor = map()->GetConstructor();
15281 if (!maybe_constructor->IsJSFunction()) return false;
15282 JSFunction* constructor = JSFunction::cast(maybe_constructor);
15283 if (constructor->shared()->IsApiFunction()) {
15284 DCHECK(is_api_object);
15285 } else {
15286 DCHECK(!is_api_object);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000015287 }
15288 }
Ben Murdochc5610432016-08-08 18:44:38 +010015289#endif
15290 return is_api_object;
Steve Blocka7e24c12009-10-30 11:49:00 +000015291}
15292
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000015293MaybeHandle<String> Object::ObjectProtoToString(Isolate* isolate,
15294 Handle<Object> object) {
15295 if (object->IsUndefined()) return isolate->factory()->undefined_to_string();
15296 if (object->IsNull()) return isolate->factory()->null_to_string();
15297
Ben Murdoch097c5b22016-05-18 11:27:45 +010015298 Handle<JSReceiver> receiver =
15299 Object::ToObject(isolate, object).ToHandleChecked();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000015300
15301 Handle<String> tag;
Ben Murdochda12d292016-06-02 14:46:10 +010015302 Handle<Object> to_string_tag;
15303 ASSIGN_RETURN_ON_EXCEPTION(
15304 isolate, to_string_tag,
15305 JSReceiver::GetProperty(receiver,
15306 isolate->factory()->to_string_tag_symbol()),
15307 String);
15308 if (to_string_tag->IsString()) {
15309 tag = Handle<String>::cast(to_string_tag);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000015310 }
15311
15312 if (tag.is_null()) {
15313 ASSIGN_RETURN_ON_EXCEPTION(isolate, tag,
15314 JSReceiver::BuiltinStringTag(receiver), String);
15315 }
15316
15317 IncrementalStringBuilder builder(isolate);
15318 builder.AppendCString("[object ");
15319 builder.AppendString(tag);
15320 builder.AppendCharacter(']');
15321 return builder.Finish();
Steve Blocka7e24c12009-10-30 11:49:00 +000015322}
15323
15324
Emily Bernierd0a1eb72015-03-24 16:35:39 -040015325const char* Symbol::PrivateSymbolToName() const {
15326 Heap* heap = GetIsolate()->heap();
15327#define SYMBOL_CHECK_AND_PRINT(name) \
15328 if (this == heap->name()) return #name;
15329 PRIVATE_SYMBOL_LIST(SYMBOL_CHECK_AND_PRINT)
15330#undef SYMBOL_CHECK_AND_PRINT
15331 return "UNKNOWN";
15332}
15333
15334
15335void Symbol::SymbolShortPrint(std::ostream& os) {
15336 os << "<Symbol: " << Hash();
15337 if (!name()->IsUndefined()) {
15338 os << " ";
15339 HeapStringAllocator allocator;
15340 StringStream accumulator(&allocator);
15341 String::cast(name())->StringShortPrint(&accumulator);
15342 os << accumulator.ToCString().get();
15343 } else {
15344 os << " (" << PrivateSymbolToName() << ")";
15345 }
15346 os << ">";
15347}
15348
15349
Steve Blocka7e24c12009-10-30 11:49:00 +000015350// StringSharedKeys are used as keys in the eval cache.
15351class StringSharedKey : public HashTableKey {
15352 public:
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000015353 StringSharedKey(Handle<String> source, Handle<SharedFunctionInfo> shared,
15354 LanguageMode language_mode, int scope_position)
Steve Block1e0659c2011-05-24 12:43:12 +010015355 : source_(source),
15356 shared_(shared),
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000015357 language_mode_(language_mode),
15358 scope_position_(scope_position) {}
Steve Blocka7e24c12009-10-30 11:49:00 +000015359
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000015360 bool IsMatch(Object* other) override {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015361 DisallowHeapAllocation no_allocation;
Emily Bernierd0a1eb72015-03-24 16:35:39 -040015362 if (!other->IsFixedArray()) {
15363 if (!other->IsNumber()) return false;
15364 uint32_t other_hash = static_cast<uint32_t>(other->Number());
15365 return Hash() == other_hash;
15366 }
Ben Murdoch3ef787d2012-04-12 10:51:47 +010015367 FixedArray* other_array = FixedArray::cast(other);
15368 SharedFunctionInfo* shared = SharedFunctionInfo::cast(other_array->get(0));
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015369 if (shared != *shared_) return false;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000015370 int language_unchecked = Smi::cast(other_array->get(2))->value();
15371 DCHECK(is_valid_language_mode(language_unchecked));
15372 LanguageMode language_mode = static_cast<LanguageMode>(language_unchecked);
15373 if (language_mode != language_mode_) return false;
Ben Murdoch3ef787d2012-04-12 10:51:47 +010015374 int scope_position = Smi::cast(other_array->get(3))->value();
15375 if (scope_position != scope_position_) return false;
15376 String* source = String::cast(other_array->get(1));
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015377 return source->Equals(*source_);
Steve Blocka7e24c12009-10-30 11:49:00 +000015378 }
15379
15380 static uint32_t StringSharedHashHelper(String* source,
Steve Block1e0659c2011-05-24 12:43:12 +010015381 SharedFunctionInfo* shared,
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000015382 LanguageMode language_mode,
Ben Murdoch3ef787d2012-04-12 10:51:47 +010015383 int scope_position) {
Steve Blocka7e24c12009-10-30 11:49:00 +000015384 uint32_t hash = source->Hash();
15385 if (shared->HasSourceCode()) {
15386 // Instead of using the SharedFunctionInfo pointer in the hash
15387 // code computation, we use a combination of the hash of the
Ben Murdoch3ef787d2012-04-12 10:51:47 +010015388 // script source code and the start position of the calling scope.
15389 // We do this to ensure that the cache entries can survive garbage
Steve Blocka7e24c12009-10-30 11:49:00 +000015390 // collection.
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015391 Script* script(Script::cast(shared->script()));
Steve Blocka7e24c12009-10-30 11:49:00 +000015392 hash ^= String::cast(script->source())->Hash();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000015393 STATIC_ASSERT(LANGUAGE_END == 3);
15394 if (is_strict(language_mode)) hash ^= 0x8000;
Ben Murdoch3ef787d2012-04-12 10:51:47 +010015395 hash += scope_position;
Steve Blocka7e24c12009-10-30 11:49:00 +000015396 }
15397 return hash;
15398 }
15399
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000015400 uint32_t Hash() override {
15401 return StringSharedHashHelper(*source_, *shared_, language_mode_,
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015402 scope_position_);
Steve Blocka7e24c12009-10-30 11:49:00 +000015403 }
15404
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000015405 uint32_t HashForObject(Object* obj) override {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015406 DisallowHeapAllocation no_allocation;
Emily Bernierd0a1eb72015-03-24 16:35:39 -040015407 if (obj->IsNumber()) {
15408 return static_cast<uint32_t>(obj->Number());
15409 }
Ben Murdoch3ef787d2012-04-12 10:51:47 +010015410 FixedArray* other_array = FixedArray::cast(obj);
15411 SharedFunctionInfo* shared = SharedFunctionInfo::cast(other_array->get(0));
15412 String* source = String::cast(other_array->get(1));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000015413 int language_unchecked = Smi::cast(other_array->get(2))->value();
15414 DCHECK(is_valid_language_mode(language_unchecked));
15415 LanguageMode language_mode = static_cast<LanguageMode>(language_unchecked);
Ben Murdoch3ef787d2012-04-12 10:51:47 +010015416 int scope_position = Smi::cast(other_array->get(3))->value();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000015417 return StringSharedHashHelper(source, shared, language_mode,
15418 scope_position);
Steve Blocka7e24c12009-10-30 11:49:00 +000015419 }
15420
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015421
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000015422 Handle<Object> AsHandle(Isolate* isolate) override {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015423 Handle<FixedArray> array = isolate->factory()->NewFixedArray(4);
15424 array->set(0, *shared_);
15425 array->set(1, *source_);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000015426 array->set(2, Smi::FromInt(language_mode_));
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015427 array->set(3, Smi::FromInt(scope_position_));
15428 return array;
Steve Blocka7e24c12009-10-30 11:49:00 +000015429 }
15430
15431 private:
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015432 Handle<String> source_;
15433 Handle<SharedFunctionInfo> shared_;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000015434 LanguageMode language_mode_;
Ben Murdoch3ef787d2012-04-12 10:51:47 +010015435 int scope_position_;
Steve Blocka7e24c12009-10-30 11:49:00 +000015436};
15437
15438
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000015439namespace {
15440
15441JSRegExp::Flags RegExpFlagsFromString(Handle<String> flags, bool* success) {
15442 JSRegExp::Flags value = JSRegExp::kNone;
15443 int length = flags->length();
15444 // A longer flags string cannot be valid.
15445 if (length > 5) return JSRegExp::Flags(0);
15446 for (int i = 0; i < length; i++) {
15447 JSRegExp::Flag flag = JSRegExp::kNone;
15448 switch (flags->Get(i)) {
15449 case 'g':
15450 flag = JSRegExp::kGlobal;
15451 break;
15452 case 'i':
15453 flag = JSRegExp::kIgnoreCase;
15454 break;
15455 case 'm':
15456 flag = JSRegExp::kMultiline;
15457 break;
15458 case 'u':
15459 if (!FLAG_harmony_unicode_regexps) return JSRegExp::Flags(0);
15460 flag = JSRegExp::kUnicode;
15461 break;
15462 case 'y':
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000015463 flag = JSRegExp::kSticky;
15464 break;
15465 default:
15466 return JSRegExp::Flags(0);
15467 }
15468 // Duplicate flag.
15469 if (value & flag) return JSRegExp::Flags(0);
15470 value |= flag;
15471 }
15472 *success = true;
15473 return value;
15474}
15475
15476} // namespace
15477
15478
15479// static
15480MaybeHandle<JSRegExp> JSRegExp::New(Handle<String> pattern, Flags flags) {
15481 Isolate* isolate = pattern->GetIsolate();
15482 Handle<JSFunction> constructor = isolate->regexp_function();
15483 Handle<JSRegExp> regexp =
15484 Handle<JSRegExp>::cast(isolate->factory()->NewJSObject(constructor));
15485
15486 return JSRegExp::Initialize(regexp, pattern, flags);
15487}
15488
15489
15490// static
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000015491Handle<JSRegExp> JSRegExp::Copy(Handle<JSRegExp> regexp) {
15492 Isolate* const isolate = regexp->GetIsolate();
15493 return Handle<JSRegExp>::cast(isolate->factory()->CopyJSObject(regexp));
15494}
15495
15496
15497template <typename Char>
15498inline int CountRequiredEscapes(Handle<String> source) {
15499 DisallowHeapAllocation no_gc;
15500 int escapes = 0;
15501 Vector<const Char> src = source->GetCharVector<Char>();
15502 for (int i = 0; i < src.length(); i++) {
15503 if (src[i] == '/' && (i == 0 || src[i - 1] != '\\')) escapes++;
15504 }
15505 return escapes;
15506}
15507
15508
15509template <typename Char, typename StringType>
15510inline Handle<StringType> WriteEscapedRegExpSource(Handle<String> source,
15511 Handle<StringType> result) {
15512 DisallowHeapAllocation no_gc;
15513 Vector<const Char> src = source->GetCharVector<Char>();
15514 Vector<Char> dst(result->GetChars(), result->length());
15515 int s = 0;
15516 int d = 0;
15517 while (s < src.length()) {
15518 if (src[s] == '/' && (s == 0 || src[s - 1] != '\\')) dst[d++] = '\\';
15519 dst[d++] = src[s++];
15520 }
15521 DCHECK_EQ(result->length(), d);
15522 return result;
15523}
15524
15525
15526MaybeHandle<String> EscapeRegExpSource(Isolate* isolate,
15527 Handle<String> source) {
15528 String::Flatten(source);
15529 if (source->length() == 0) return isolate->factory()->query_colon_string();
15530 bool one_byte = source->IsOneByteRepresentationUnderneath();
15531 int escapes = one_byte ? CountRequiredEscapes<uint8_t>(source)
15532 : CountRequiredEscapes<uc16>(source);
15533 if (escapes == 0) return source;
15534 int length = source->length() + escapes;
15535 if (one_byte) {
15536 Handle<SeqOneByteString> result;
15537 ASSIGN_RETURN_ON_EXCEPTION(isolate, result,
15538 isolate->factory()->NewRawOneByteString(length),
15539 String);
15540 return WriteEscapedRegExpSource<uint8_t>(source, result);
15541 } else {
15542 Handle<SeqTwoByteString> result;
15543 ASSIGN_RETURN_ON_EXCEPTION(isolate, result,
15544 isolate->factory()->NewRawTwoByteString(length),
15545 String);
15546 return WriteEscapedRegExpSource<uc16>(source, result);
15547 }
15548}
15549
15550
15551// static
15552MaybeHandle<JSRegExp> JSRegExp::Initialize(Handle<JSRegExp> regexp,
15553 Handle<String> source,
15554 Handle<String> flags_string) {
15555 Isolate* isolate = source->GetIsolate();
15556 bool success = false;
15557 Flags flags = RegExpFlagsFromString(flags_string, &success);
15558 if (!success) {
15559 THROW_NEW_ERROR(
15560 isolate,
15561 NewSyntaxError(MessageTemplate::kInvalidRegExpFlags, flags_string),
15562 JSRegExp);
15563 }
15564 return Initialize(regexp, source, flags);
15565}
15566
15567
15568// static
15569MaybeHandle<JSRegExp> JSRegExp::Initialize(Handle<JSRegExp> regexp,
15570 Handle<String> source, Flags flags) {
15571 Isolate* isolate = regexp->GetIsolate();
15572 Factory* factory = isolate->factory();
15573 // If source is the empty string we set it to "(?:)" instead as
15574 // suggested by ECMA-262, 5th, section 15.10.4.1.
15575 if (source->length() == 0) source = factory->query_colon_string();
15576
15577 Handle<String> escaped_source;
15578 ASSIGN_RETURN_ON_EXCEPTION(isolate, escaped_source,
15579 EscapeRegExpSource(isolate, source), JSRegExp);
15580
Ben Murdochc5610432016-08-08 18:44:38 +010015581 RETURN_ON_EXCEPTION(isolate, RegExpImpl::Compile(regexp, source, flags),
15582 JSRegExp);
15583
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000015584 regexp->set_source(*escaped_source);
15585 regexp->set_flags(Smi::FromInt(flags));
15586
15587 Map* map = regexp->map();
15588 Object* constructor = map->GetConstructor();
15589 if (constructor->IsJSFunction() &&
15590 JSFunction::cast(constructor)->initial_map() == map) {
15591 // If we still have the original map, set in-object properties directly.
15592 regexp->InObjectPropertyAtPut(JSRegExp::kLastIndexFieldIndex,
15593 Smi::FromInt(0), SKIP_WRITE_BARRIER);
15594 } else {
15595 // Map has changed, so use generic, but slower, method.
15596 PropertyAttributes writable =
15597 static_cast<PropertyAttributes>(DONT_ENUM | DONT_DELETE);
15598 JSObject::SetOwnPropertyIgnoreAttributes(
15599 regexp, factory->last_index_string(),
15600 Handle<Smi>(Smi::FromInt(0), isolate), writable)
15601 .Check();
15602 }
15603
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000015604 return regexp;
15605}
15606
15607
Steve Blocka7e24c12009-10-30 11:49:00 +000015608// RegExpKey carries the source and flags of a regular expression as key.
15609class RegExpKey : public HashTableKey {
15610 public:
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015611 RegExpKey(Handle<String> string, JSRegExp::Flags flags)
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000015612 : string_(string), flags_(Smi::FromInt(flags)) {}
Steve Blocka7e24c12009-10-30 11:49:00 +000015613
Steve Block3ce2e202009-11-05 08:53:23 +000015614 // Rather than storing the key in the hash table, a pointer to the
15615 // stored value is stored where the key should be. IsMatch then
15616 // compares the search key to the found object, rather than comparing
15617 // a key to a key.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000015618 bool IsMatch(Object* obj) override {
Steve Blocka7e24c12009-10-30 11:49:00 +000015619 FixedArray* val = FixedArray::cast(obj);
15620 return string_->Equals(String::cast(val->get(JSRegExp::kSourceIndex)))
15621 && (flags_ == val->get(JSRegExp::kFlagsIndex));
15622 }
15623
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000015624 uint32_t Hash() override { return RegExpHash(*string_, flags_); }
Steve Blocka7e24c12009-10-30 11:49:00 +000015625
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000015626 Handle<Object> AsHandle(Isolate* isolate) override {
Steve Blocka7e24c12009-10-30 11:49:00 +000015627 // Plain hash maps, which is where regexp keys are used, don't
15628 // use this function.
15629 UNREACHABLE();
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015630 return MaybeHandle<Object>().ToHandleChecked();
Steve Blocka7e24c12009-10-30 11:49:00 +000015631 }
15632
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000015633 uint32_t HashForObject(Object* obj) override {
Steve Blocka7e24c12009-10-30 11:49:00 +000015634 FixedArray* val = FixedArray::cast(obj);
15635 return RegExpHash(String::cast(val->get(JSRegExp::kSourceIndex)),
15636 Smi::cast(val->get(JSRegExp::kFlagsIndex)));
15637 }
15638
15639 static uint32_t RegExpHash(String* string, Smi* flags) {
15640 return string->Hash() + flags->value();
15641 }
15642
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015643 Handle<String> string_;
Steve Blocka7e24c12009-10-30 11:49:00 +000015644 Smi* flags_;
15645};
15646
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015647
15648Handle<Object> OneByteStringKey::AsHandle(Isolate* isolate) {
15649 if (hash_field_ == 0) Hash();
15650 return isolate->factory()->NewOneByteInternalizedString(string_, hash_field_);
15651}
15652
15653
15654Handle<Object> TwoByteStringKey::AsHandle(Isolate* isolate) {
15655 if (hash_field_ == 0) Hash();
15656 return isolate->factory()->NewTwoByteInternalizedString(string_, hash_field_);
15657}
15658
15659
15660Handle<Object> SeqOneByteSubStringKey::AsHandle(Isolate* isolate) {
15661 if (hash_field_ == 0) Hash();
15662 return isolate->factory()->NewOneByteInternalizedSubString(
15663 string_, from_, length_, hash_field_);
15664}
15665
15666
15667bool SeqOneByteSubStringKey::IsMatch(Object* string) {
15668 Vector<const uint8_t> chars(string_->GetChars() + from_, length_);
15669 return String::cast(string)->IsOneByteEqualTo(chars);
15670}
15671
15672
15673// InternalizedStringKey carries a string/internalized-string object as key.
15674class InternalizedStringKey : public HashTableKey {
Steve Blocka7e24c12009-10-30 11:49:00 +000015675 public:
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015676 explicit InternalizedStringKey(Handle<String> string)
Ben Murdochda12d292016-06-02 14:46:10 +010015677 : string_(String::Flatten(string)) {}
Steve Blocka7e24c12009-10-30 11:49:00 +000015678
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000015679 bool IsMatch(Object* string) override {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015680 return String::cast(string)->Equals(*string_);
Steve Blocka7e24c12009-10-30 11:49:00 +000015681 }
15682
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000015683 uint32_t Hash() override { return string_->Hash(); }
Steve Blocka7e24c12009-10-30 11:49:00 +000015684
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000015685 uint32_t HashForObject(Object* other) override {
Steve Blocka7e24c12009-10-30 11:49:00 +000015686 return String::cast(other)->Hash();
15687 }
15688
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000015689 Handle<Object> AsHandle(Isolate* isolate) override {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015690 // Internalize the string if possible.
15691 MaybeHandle<Map> maybe_map =
15692 isolate->factory()->InternalizedStringMapForString(string_);
15693 Handle<Map> map;
15694 if (maybe_map.ToHandle(&map)) {
15695 string_->set_map_no_write_barrier(*map);
15696 DCHECK(string_->IsInternalizedString());
Steve Blocka7e24c12009-10-30 11:49:00 +000015697 return string_;
15698 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015699 // Otherwise allocate a new internalized string.
15700 return isolate->factory()->NewInternalizedStringImpl(
15701 string_, string_->length(), string_->hash_field());
Steve Blocka7e24c12009-10-30 11:49:00 +000015702 }
15703
15704 static uint32_t StringHash(Object* obj) {
15705 return String::cast(obj)->Hash();
15706 }
15707
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015708 Handle<String> string_;
Steve Blocka7e24c12009-10-30 11:49:00 +000015709};
15710
15711
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015712template<typename Derived, typename Shape, typename Key>
15713void HashTable<Derived, Shape, Key>::IteratePrefix(ObjectVisitor* v) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000015714 BodyDescriptorBase::IteratePointers(this, 0, kElementsStartOffset, v);
Steve Blocka7e24c12009-10-30 11:49:00 +000015715}
15716
15717
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015718template<typename Derived, typename Shape, typename Key>
15719void HashTable<Derived, Shape, Key>::IterateElements(ObjectVisitor* v) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000015720 BodyDescriptorBase::IteratePointers(this, kElementsStartOffset,
15721 kHeaderSize + length() * kPointerSize, v);
Steve Blocka7e24c12009-10-30 11:49:00 +000015722}
15723
15724
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015725template<typename Derived, typename Shape, typename Key>
15726Handle<Derived> HashTable<Derived, Shape, Key>::New(
15727 Isolate* isolate,
15728 int at_least_space_for,
15729 MinimumCapacity capacity_option,
15730 PretenureFlag pretenure) {
15731 DCHECK(0 <= at_least_space_for);
15732 DCHECK(!capacity_option || base::bits::IsPowerOfTwo32(at_least_space_for));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000015733
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015734 int capacity = (capacity_option == USE_CUSTOM_MINIMUM_CAPACITY)
15735 ? at_least_space_for
15736 : ComputeCapacity(at_least_space_for);
Ben Murdoch69a99ed2011-11-30 16:03:39 +000015737 if (capacity > HashTable::kMaxCapacity) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015738 v8::internal::Heap::FatalProcessOutOfMemory("invalid table size", true);
Leon Clarkee46be812010-01-19 14:06:41 +000015739 }
15740
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015741 Factory* factory = isolate->factory();
15742 int length = EntryToIndex(capacity);
15743 Handle<FixedArray> array = factory->NewFixedArray(length, pretenure);
15744 array->set_map_no_write_barrier(*factory->hash_table_map());
15745 Handle<Derived> table = Handle<Derived>::cast(array);
15746
15747 table->SetNumberOfElements(0);
15748 table->SetNumberOfDeletedElements(0);
15749 table->SetCapacity(capacity);
15750 return table;
Steve Blocka7e24c12009-10-30 11:49:00 +000015751}
15752
15753
Leon Clarkee46be812010-01-19 14:06:41 +000015754// Find entry for key otherwise return kNotFound.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000015755template <typename Derived, typename Shape>
15756int NameDictionaryBase<Derived, Shape>::FindEntry(Handle<Name> key) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015757 if (!key->IsUniqueName()) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000015758 return DerivedDictionary::FindEntry(key);
Ben Murdoch3bec4d22010-07-22 14:51:16 +010015759 }
15760
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015761 // Optimized for unique names. Knowledge of the key type allows:
15762 // 1. Move the check if the key is unique out of the loop.
15763 // 2. Avoid comparing hash codes in unique-to-unique comparison.
15764 // 3. Detect a case when a dictionary key is not unique but the key is.
15765 // In case of positive result the dictionary key may be replaced by the
15766 // internalized string with minimal performance penalty. It gives a chance
15767 // to perform further lookups in code stubs (and significant performance
15768 // boost a certain style of code).
Ben Murdoch3bec4d22010-07-22 14:51:16 +010015769
15770 // EnsureCapacity will guarantee the hash table is never full.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000015771 uint32_t capacity = this->Capacity();
15772 uint32_t entry = Derived::FirstProbe(key->Hash(), capacity);
Ben Murdoch3bec4d22010-07-22 14:51:16 +010015773 uint32_t count = 1;
15774
15775 while (true) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000015776 int index = Derived::EntryToIndex(entry);
15777 Object* element = this->get(index);
Ben Murdoch3bec4d22010-07-22 14:51:16 +010015778 if (element->IsUndefined()) break; // Empty entry.
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015779 if (*key == element) return entry;
15780 if (!element->IsUniqueName() &&
Ben Murdoch3ef787d2012-04-12 10:51:47 +010015781 !element->IsTheHole() &&
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015782 Name::cast(element)->Equals(*key)) {
15783 // Replace a key that is a non-internalized string by the equivalent
15784 // internalized string for faster further lookups.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000015785 this->set(index, *key);
Ben Murdoch3bec4d22010-07-22 14:51:16 +010015786 return entry;
15787 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015788 DCHECK(element->IsTheHole() || !Name::cast(element)->Equals(*key));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000015789 entry = Derived::NextProbe(entry, count++, capacity);
Ben Murdoch3bec4d22010-07-22 14:51:16 +010015790 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000015791 return Derived::kNotFound;
Ben Murdoch3bec4d22010-07-22 14:51:16 +010015792}
15793
15794
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015795template<typename Derived, typename Shape, typename Key>
15796void HashTable<Derived, Shape, Key>::Rehash(
15797 Handle<Derived> new_table,
15798 Key key) {
15799 DCHECK(NumberOfElements() < new_table->Capacity());
Ben Murdoch3ef787d2012-04-12 10:51:47 +010015800
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015801 DisallowHeapAllocation no_gc;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000015802 WriteBarrierMode mode = new_table->GetWriteBarrierMode(no_gc);
15803
15804 // Copy prefix to new array.
15805 for (int i = kPrefixStartIndex;
15806 i < kPrefixStartIndex + Shape::kPrefixSize;
15807 i++) {
15808 new_table->set(i, get(i), mode);
15809 }
15810
15811 // Rehash the elements.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000015812 int capacity = this->Capacity();
Ben Murdochc5610432016-08-08 18:44:38 +010015813 Heap* heap = new_table->GetHeap();
15814 Object* the_hole = heap->the_hole_value();
15815 Object* undefined = heap->undefined_value();
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000015816 for (int i = 0; i < capacity; i++) {
15817 uint32_t from_index = EntryToIndex(i);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000015818 Object* k = this->get(from_index);
Ben Murdochc5610432016-08-08 18:44:38 +010015819 if (k != the_hole && k != undefined) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000015820 uint32_t hash = this->HashForObject(key, k);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000015821 uint32_t insertion_index =
15822 EntryToIndex(new_table->FindInsertionEntry(hash));
15823 for (int j = 0; j < Shape::kEntrySize; j++) {
15824 new_table->set(insertion_index + j, get(from_index + j), mode);
15825 }
15826 }
15827 }
15828 new_table->SetNumberOfElements(NumberOfElements());
15829 new_table->SetNumberOfDeletedElements(0);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000015830}
15831
15832
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015833template<typename Derived, typename Shape, typename Key>
15834uint32_t HashTable<Derived, Shape, Key>::EntryForProbe(
15835 Key key,
15836 Object* k,
15837 int probe,
15838 uint32_t expected) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000015839 uint32_t hash = this->HashForObject(key, k);
15840 uint32_t capacity = this->Capacity();
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015841 uint32_t entry = FirstProbe(hash, capacity);
15842 for (int i = 1; i < probe; i++) {
15843 if (entry == expected) return expected;
15844 entry = NextProbe(entry, i, capacity);
15845 }
15846 return entry;
15847}
15848
15849
15850template<typename Derived, typename Shape, typename Key>
15851void HashTable<Derived, Shape, Key>::Swap(uint32_t entry1,
15852 uint32_t entry2,
15853 WriteBarrierMode mode) {
15854 int index1 = EntryToIndex(entry1);
15855 int index2 = EntryToIndex(entry2);
15856 Object* temp[Shape::kEntrySize];
15857 for (int j = 0; j < Shape::kEntrySize; j++) {
15858 temp[j] = get(index1 + j);
15859 }
15860 for (int j = 0; j < Shape::kEntrySize; j++) {
15861 set(index1 + j, get(index2 + j), mode);
15862 }
15863 for (int j = 0; j < Shape::kEntrySize; j++) {
15864 set(index2 + j, temp[j], mode);
15865 }
15866}
15867
15868
15869template<typename Derived, typename Shape, typename Key>
15870void HashTable<Derived, Shape, Key>::Rehash(Key key) {
15871 DisallowHeapAllocation no_gc;
15872 WriteBarrierMode mode = GetWriteBarrierMode(no_gc);
15873 uint32_t capacity = Capacity();
15874 bool done = false;
15875 for (int probe = 1; !done; probe++) {
15876 // All elements at entries given by one of the first _probe_ probes
15877 // are placed correctly. Other elements might need to be moved.
15878 done = true;
15879 for (uint32_t current = 0; current < capacity; current++) {
15880 Object* current_key = get(EntryToIndex(current));
15881 if (IsKey(current_key)) {
15882 uint32_t target = EntryForProbe(key, current_key, probe, current);
15883 if (current == target) continue;
15884 Object* target_key = get(EntryToIndex(target));
15885 if (!IsKey(target_key) ||
15886 EntryForProbe(key, target_key, probe, target) != target) {
15887 // Put the current element into the correct position.
15888 Swap(current, target, mode);
15889 // The other element will be processed on the next iteration.
15890 current--;
15891 } else {
15892 // The place for the current element is occupied. Leave the element
15893 // for the next probe.
15894 done = false;
15895 }
15896 }
15897 }
15898 }
Ben Murdoch097c5b22016-05-18 11:27:45 +010015899 // Wipe deleted entries.
15900 Heap* heap = GetHeap();
15901 Object* the_hole = heap->the_hole_value();
15902 Object* undefined = heap->undefined_value();
15903 for (uint32_t current = 0; current < capacity; current++) {
15904 if (get(EntryToIndex(current)) == the_hole) {
15905 set(EntryToIndex(current), undefined);
15906 }
15907 }
15908 SetNumberOfDeletedElements(0);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015909}
15910
15911
15912template<typename Derived, typename Shape, typename Key>
15913Handle<Derived> HashTable<Derived, Shape, Key>::EnsureCapacity(
15914 Handle<Derived> table,
15915 int n,
15916 Key key,
15917 PretenureFlag pretenure) {
15918 Isolate* isolate = table->GetIsolate();
15919 int capacity = table->Capacity();
15920 int nof = table->NumberOfElements() + n;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000015921
15922 if (table->HasSufficientCapacity(n)) return table;
Steve Blocka7e24c12009-10-30 11:49:00 +000015923
Steve Block6ded16b2010-05-10 14:33:55 +010015924 const int kMinCapacityForPretenure = 256;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015925 bool should_pretenure = pretenure == TENURED ||
15926 ((capacity > kMinCapacityForPretenure) &&
15927 !isolate->heap()->InNewSpace(*table));
15928 Handle<Derived> new_table = HashTable::New(
15929 isolate,
15930 nof * 2,
15931 USE_DEFAULT_MINIMUM_CAPACITY,
15932 should_pretenure ? TENURED : NOT_TENURED);
Leon Clarke4515c472010-02-03 11:58:03 +000015933
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015934 table->Rehash(new_table, key);
15935 return new_table;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000015936}
Steve Blocka7e24c12009-10-30 11:49:00 +000015937
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000015938
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000015939template <typename Derived, typename Shape, typename Key>
15940bool HashTable<Derived, Shape, Key>::HasSufficientCapacity(int n) {
15941 int capacity = Capacity();
15942 int nof = NumberOfElements() + n;
15943 int nod = NumberOfDeletedElements();
15944 // Return true if:
15945 // 50% is still free after adding n elements and
15946 // at most 50% of the free elements are deleted elements.
15947 if (nod <= (capacity - nof) >> 1) {
15948 int needed_free = nof >> 1;
15949 if (nof + needed_free <= capacity) return true;
15950 }
15951 return false;
15952}
15953
15954
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015955template<typename Derived, typename Shape, typename Key>
15956Handle<Derived> HashTable<Derived, Shape, Key>::Shrink(Handle<Derived> table,
15957 Key key) {
15958 int capacity = table->Capacity();
15959 int nof = table->NumberOfElements();
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000015960
15961 // Shrink to fit the number of elements if only a quarter of the
15962 // capacity is filled with elements.
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015963 if (nof > (capacity >> 2)) return table;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000015964 // Allocate a new dictionary with room for at least the current
15965 // number of elements. The allocation method will make sure that
15966 // there is extra room in the dictionary for additions. Don't go
15967 // lower than room for 16 elements.
15968 int at_least_room_for = nof;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015969 if (at_least_room_for < 16) return table;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000015970
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015971 Isolate* isolate = table->GetIsolate();
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000015972 const int kMinCapacityForPretenure = 256;
15973 bool pretenure =
15974 (at_least_room_for > kMinCapacityForPretenure) &&
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015975 !isolate->heap()->InNewSpace(*table);
15976 Handle<Derived> new_table = HashTable::New(
15977 isolate,
15978 at_least_room_for,
15979 USE_DEFAULT_MINIMUM_CAPACITY,
15980 pretenure ? TENURED : NOT_TENURED);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000015981
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015982 table->Rehash(new_table, key);
15983 return new_table;
Steve Blocka7e24c12009-10-30 11:49:00 +000015984}
15985
15986
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015987template<typename Derived, typename Shape, typename Key>
15988uint32_t HashTable<Derived, Shape, Key>::FindInsertionEntry(uint32_t hash) {
Steve Blocka7e24c12009-10-30 11:49:00 +000015989 uint32_t capacity = Capacity();
Leon Clarkee46be812010-01-19 14:06:41 +000015990 uint32_t entry = FirstProbe(hash, capacity);
15991 uint32_t count = 1;
15992 // EnsureCapacity will guarantee the hash table is never full.
Ben Murdochc5610432016-08-08 18:44:38 +010015993 Heap* heap = GetHeap();
15994 Object* the_hole = heap->the_hole_value();
15995 Object* undefined = heap->undefined_value();
Leon Clarkee46be812010-01-19 14:06:41 +000015996 while (true) {
15997 Object* element = KeyAt(entry);
Ben Murdochc5610432016-08-08 18:44:38 +010015998 if (element == the_hole || element == undefined) break;
Leon Clarkee46be812010-01-19 14:06:41 +000015999 entry = NextProbe(entry, count++, capacity);
Steve Blocka7e24c12009-10-30 11:49:00 +000016000 }
Steve Blocka7e24c12009-10-30 11:49:00 +000016001 return entry;
16002}
16003
Ben Murdochb8a8cc12014-11-26 15:28:44 +000016004
Steve Blocka7e24c12009-10-30 11:49:00 +000016005// Force instantiation of template instances class.
16006// Please note this list is compiler dependent.
16007
Ben Murdochb8a8cc12014-11-26 15:28:44 +000016008template class HashTable<StringTable, StringTableShape, HashTableKey*>;
Steve Blocka7e24c12009-10-30 11:49:00 +000016009
Ben Murdochb8a8cc12014-11-26 15:28:44 +000016010template class HashTable<CompilationCacheTable,
16011 CompilationCacheShape,
16012 HashTableKey*>;
Steve Blocka7e24c12009-10-30 11:49:00 +000016013
Ben Murdochb8a8cc12014-11-26 15:28:44 +000016014template class HashTable<ObjectHashTable,
16015 ObjectHashTableShape,
16016 Handle<Object> >;
Ben Murdoch3ef787d2012-04-12 10:51:47 +010016017
Ben Murdochb8a8cc12014-11-26 15:28:44 +000016018template class HashTable<WeakHashTable, WeakHashTableShape<2>, Handle<Object> >;
Ben Murdoch69a99ed2011-11-30 16:03:39 +000016019
Ben Murdochb8a8cc12014-11-26 15:28:44 +000016020template class Dictionary<NameDictionary, NameDictionaryShape, Handle<Name> >;
Steve Blocka7e24c12009-10-30 11:49:00 +000016021
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000016022template class Dictionary<GlobalDictionary, GlobalDictionaryShape,
16023 Handle<Name> >;
16024
Ben Murdochb8a8cc12014-11-26 15:28:44 +000016025template class Dictionary<SeededNumberDictionary,
16026 SeededNumberDictionaryShape,
16027 uint32_t>;
Steve Blocka7e24c12009-10-30 11:49:00 +000016028
Ben Murdochb8a8cc12014-11-26 15:28:44 +000016029template class Dictionary<UnseededNumberDictionary,
16030 UnseededNumberDictionaryShape,
16031 uint32_t>;
Ben Murdochc7cc0282012-03-05 14:35:55 +000016032
Ben Murdochb8a8cc12014-11-26 15:28:44 +000016033template Handle<SeededNumberDictionary>
16034Dictionary<SeededNumberDictionary, SeededNumberDictionaryShape, uint32_t>::
16035 New(Isolate*, int at_least_space_for, PretenureFlag pretenure);
Ben Murdochc7cc0282012-03-05 14:35:55 +000016036
Ben Murdochb8a8cc12014-11-26 15:28:44 +000016037template Handle<UnseededNumberDictionary>
16038Dictionary<UnseededNumberDictionary, UnseededNumberDictionaryShape, uint32_t>::
16039 New(Isolate*, int at_least_space_for, PretenureFlag pretenure);
Steve Blocka7e24c12009-10-30 11:49:00 +000016040
Ben Murdochb8a8cc12014-11-26 15:28:44 +000016041template Handle<NameDictionary>
16042Dictionary<NameDictionary, NameDictionaryShape, Handle<Name> >::
16043 New(Isolate*, int n, PretenureFlag pretenure);
Steve Blocka7e24c12009-10-30 11:49:00 +000016044
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000016045template Handle<GlobalDictionary>
16046Dictionary<GlobalDictionary, GlobalDictionaryShape, Handle<Name> >::New(
16047 Isolate*, int n, PretenureFlag pretenure);
16048
Ben Murdochb8a8cc12014-11-26 15:28:44 +000016049template Handle<SeededNumberDictionary>
16050Dictionary<SeededNumberDictionary, SeededNumberDictionaryShape, uint32_t>::
16051 AtPut(Handle<SeededNumberDictionary>, uint32_t, Handle<Object>);
Steve Blocka7e24c12009-10-30 11:49:00 +000016052
Ben Murdochb8a8cc12014-11-26 15:28:44 +000016053template Handle<UnseededNumberDictionary>
16054Dictionary<UnseededNumberDictionary, UnseededNumberDictionaryShape, uint32_t>::
16055 AtPut(Handle<UnseededNumberDictionary>, uint32_t, Handle<Object>);
Ben Murdochc7cc0282012-03-05 14:35:55 +000016056
Ben Murdochb8a8cc12014-11-26 15:28:44 +000016057template Object*
16058Dictionary<SeededNumberDictionary, SeededNumberDictionaryShape, uint32_t>::
Ben Murdoch3ef787d2012-04-12 10:51:47 +010016059 SlowReverseLookup(Object* value);
16060
Ben Murdochb8a8cc12014-11-26 15:28:44 +000016061template Object*
16062Dictionary<NameDictionary, NameDictionaryShape, Handle<Name> >::
Ben Murdochc7cc0282012-03-05 14:35:55 +000016063 SlowReverseLookup(Object* value);
Steve Blocka7e24c12009-10-30 11:49:00 +000016064
Ben Murdochb8a8cc12014-11-26 15:28:44 +000016065template Handle<Object>
16066Dictionary<NameDictionary, NameDictionaryShape, Handle<Name> >::DeleteProperty(
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000016067 Handle<NameDictionary>, int);
Steve Blocka7e24c12009-10-30 11:49:00 +000016068
Ben Murdochb8a8cc12014-11-26 15:28:44 +000016069template Handle<Object>
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000016070Dictionary<SeededNumberDictionary, SeededNumberDictionaryShape,
16071 uint32_t>::DeleteProperty(Handle<SeededNumberDictionary>, int);
Steve Blocka7e24c12009-10-30 11:49:00 +000016072
Ben Murdochda12d292016-06-02 14:46:10 +010016073template Handle<Object>
16074Dictionary<UnseededNumberDictionary, UnseededNumberDictionaryShape,
16075 uint32_t>::DeleteProperty(Handle<UnseededNumberDictionary>, int);
16076
Ben Murdochb8a8cc12014-11-26 15:28:44 +000016077template Handle<NameDictionary>
16078HashTable<NameDictionary, NameDictionaryShape, Handle<Name> >::
16079 New(Isolate*, int, MinimumCapacity, PretenureFlag);
Steve Blocka7e24c12009-10-30 11:49:00 +000016080
Ben Murdochb8a8cc12014-11-26 15:28:44 +000016081template Handle<NameDictionary>
16082HashTable<NameDictionary, NameDictionaryShape, Handle<Name> >::
16083 Shrink(Handle<NameDictionary>, Handle<Name>);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000016084
Ben Murdochb8a8cc12014-11-26 15:28:44 +000016085template Handle<SeededNumberDictionary>
16086HashTable<SeededNumberDictionary, SeededNumberDictionaryShape, uint32_t>::
16087 Shrink(Handle<SeededNumberDictionary>, uint32_t);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000016088
Ben Murdochda12d292016-06-02 14:46:10 +010016089template Handle<UnseededNumberDictionary>
16090 HashTable<UnseededNumberDictionary, UnseededNumberDictionaryShape,
16091 uint32_t>::Shrink(Handle<UnseededNumberDictionary>, uint32_t);
16092
Ben Murdochb8a8cc12014-11-26 15:28:44 +000016093template Handle<NameDictionary>
16094Dictionary<NameDictionary, NameDictionaryShape, Handle<Name> >::Add(
16095 Handle<NameDictionary>, Handle<Name>, Handle<Object>, PropertyDetails);
Steve Blocka7e24c12009-10-30 11:49:00 +000016096
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000016097template Handle<GlobalDictionary>
16098 Dictionary<GlobalDictionary, GlobalDictionaryShape, Handle<Name> >::Add(
16099 Handle<GlobalDictionary>, Handle<Name>, Handle<Object>,
16100 PropertyDetails);
16101
Emily Bernierd0a1eb72015-03-24 16:35:39 -040016102template Handle<FixedArray> Dictionary<
16103 NameDictionary, NameDictionaryShape,
16104 Handle<Name> >::BuildIterationIndicesArray(Handle<NameDictionary>);
16105
16106template Handle<FixedArray> Dictionary<
16107 NameDictionary, NameDictionaryShape,
16108 Handle<Name> >::GenerateNewEnumerationIndices(Handle<NameDictionary>);
Ben Murdochc7cc0282012-03-05 14:35:55 +000016109
Ben Murdochb8a8cc12014-11-26 15:28:44 +000016110template Handle<SeededNumberDictionary>
16111Dictionary<SeededNumberDictionary, SeededNumberDictionaryShape, uint32_t>::
16112 Add(Handle<SeededNumberDictionary>,
16113 uint32_t,
16114 Handle<Object>,
16115 PropertyDetails);
Steve Blocka7e24c12009-10-30 11:49:00 +000016116
Ben Murdochb8a8cc12014-11-26 15:28:44 +000016117template Handle<UnseededNumberDictionary>
16118Dictionary<UnseededNumberDictionary, UnseededNumberDictionaryShape, uint32_t>::
16119 Add(Handle<UnseededNumberDictionary>,
16120 uint32_t,
16121 Handle<Object>,
16122 PropertyDetails);
Steve Blocka7e24c12009-10-30 11:49:00 +000016123
Ben Murdochb8a8cc12014-11-26 15:28:44 +000016124template Handle<SeededNumberDictionary>
16125Dictionary<SeededNumberDictionary, SeededNumberDictionaryShape, uint32_t>::
16126 EnsureCapacity(Handle<SeededNumberDictionary>, int, uint32_t);
Ben Murdochc7cc0282012-03-05 14:35:55 +000016127
Ben Murdochb8a8cc12014-11-26 15:28:44 +000016128template Handle<UnseededNumberDictionary>
16129Dictionary<UnseededNumberDictionary, UnseededNumberDictionaryShape, uint32_t>::
16130 EnsureCapacity(Handle<UnseededNumberDictionary>, int, uint32_t);
Steve Blocka7e24c12009-10-30 11:49:00 +000016131
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000016132template void Dictionary<NameDictionary, NameDictionaryShape,
16133 Handle<Name> >::SetRequiresCopyOnCapacityChange();
16134
Ben Murdochb8a8cc12014-11-26 15:28:44 +000016135template Handle<NameDictionary>
16136Dictionary<NameDictionary, NameDictionaryShape, Handle<Name> >::
16137 EnsureCapacity(Handle<NameDictionary>, int, Handle<Name>);
Steve Blocka7e24c12009-10-30 11:49:00 +000016138
Emily Bernierd0a1eb72015-03-24 16:35:39 -040016139template int HashTable<SeededNumberDictionary, SeededNumberDictionaryShape,
16140 uint32_t>::FindEntry(uint32_t);
Leon Clarkee46be812010-01-19 14:06:41 +000016141
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000016142template int NameDictionaryBase<NameDictionary, NameDictionaryShape>::FindEntry(
16143 Handle<Name>);
16144
Ben Murdochc5610432016-08-08 18:44:38 +010016145template int Dictionary<GlobalDictionary, GlobalDictionaryShape, Handle<Name>>::
16146 NumberOfElementsFilterAttributes(PropertyFilter filter);
16147
16148template int Dictionary<NameDictionary, NameDictionaryShape, Handle<Name>>::
16149 NumberOfElementsFilterAttributes(PropertyFilter filter);
16150
16151template void Dictionary<GlobalDictionary, GlobalDictionaryShape,
16152 Handle<Name>>::CopyEnumKeysTo(FixedArray* storage);
16153
16154template void Dictionary<NameDictionary, NameDictionaryShape,
16155 Handle<Name>>::CopyEnumKeysTo(FixedArray* storage);
16156
16157template void
16158Dictionary<GlobalDictionary, GlobalDictionaryShape, Handle<Name>>::
16159 CollectKeysTo(Handle<Dictionary<GlobalDictionary, GlobalDictionaryShape,
16160 Handle<Name>>>
16161 dictionary,
16162 KeyAccumulator* keys, PropertyFilter filter);
16163
16164template void
16165Dictionary<NameDictionary, NameDictionaryShape, Handle<Name>>::CollectKeysTo(
16166 Handle<Dictionary<NameDictionary, NameDictionaryShape, Handle<Name>>>
16167 dictionary,
16168 KeyAccumulator* keys, PropertyFilter filter);
Leon Clarkee46be812010-01-19 14:06:41 +000016169
Ben Murdochb8a8cc12014-11-26 15:28:44 +000016170Handle<Object> JSObject::PrepareSlowElementsForSort(
16171 Handle<JSObject> object, uint32_t limit) {
16172 DCHECK(object->HasDictionaryElements());
16173 Isolate* isolate = object->GetIsolate();
Steve Blocka7e24c12009-10-30 11:49:00 +000016174 // Must stay in dictionary mode, either because of requires_slow_elements,
16175 // or because we are not going to sort (and therefore compact) all of the
16176 // elements.
Ben Murdochb8a8cc12014-11-26 15:28:44 +000016177 Handle<SeededNumberDictionary> dict(object->element_dictionary(), isolate);
16178 Handle<SeededNumberDictionary> new_dict =
16179 SeededNumberDictionary::New(isolate, dict->NumberOfElements());
Steve Blocka7e24c12009-10-30 11:49:00 +000016180
16181 uint32_t pos = 0;
16182 uint32_t undefs = 0;
Steve Block6ded16b2010-05-10 14:33:55 +010016183 int capacity = dict->Capacity();
Ben Murdochb8a8cc12014-11-26 15:28:44 +000016184 Handle<Smi> bailout(Smi::FromInt(-1), isolate);
16185 // Entry to the new dictionary does not cause it to grow, as we have
16186 // allocated one that is large enough for all entries.
16187 DisallowHeapAllocation no_gc;
Steve Blocka7e24c12009-10-30 11:49:00 +000016188 for (int i = 0; i < capacity; i++) {
16189 Object* k = dict->KeyAt(i);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000016190 if (!dict->IsKey(k)) continue;
16191
16192 DCHECK(k->IsNumber());
16193 DCHECK(!k->IsSmi() || Smi::cast(k)->value() >= 0);
16194 DCHECK(!k->IsHeapNumber() || HeapNumber::cast(k)->value() >= 0);
16195 DCHECK(!k->IsHeapNumber() || HeapNumber::cast(k)->value() <= kMaxUInt32);
16196
16197 HandleScope scope(isolate);
16198 Handle<Object> value(dict->ValueAt(i), isolate);
16199 PropertyDetails details = dict->DetailsAt(i);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000016200 if (details.type() == ACCESSOR_CONSTANT || details.IsReadOnly()) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000016201 // Bail out and do the sorting of undefineds and array holes in JS.
16202 // Also bail out if the element is not supposed to be moved.
16203 return bailout;
16204 }
16205
16206 uint32_t key = NumberToUint32(k);
16207 if (key < limit) {
16208 if (value->IsUndefined()) {
16209 undefs++;
16210 } else if (pos > static_cast<uint32_t>(Smi::kMaxValue)) {
16211 // Adding an entry with the key beyond smi-range requires
16212 // allocation. Bailout.
16213 return bailout;
Steve Blocka7e24c12009-10-30 11:49:00 +000016214 } else {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000016215 Handle<Object> result = SeededNumberDictionary::AddNumberEntry(
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000016216 new_dict, pos, value, details, object->map()->is_prototype_map());
Ben Murdochb8a8cc12014-11-26 15:28:44 +000016217 DCHECK(result.is_identical_to(new_dict));
16218 USE(result);
16219 pos++;
Steve Blocka7e24c12009-10-30 11:49:00 +000016220 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +000016221 } else if (key > static_cast<uint32_t>(Smi::kMaxValue)) {
16222 // Adding an entry with the key beyond smi-range requires
16223 // allocation. Bailout.
16224 return bailout;
16225 } else {
16226 Handle<Object> result = SeededNumberDictionary::AddNumberEntry(
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000016227 new_dict, key, value, details, object->map()->is_prototype_map());
Ben Murdochb8a8cc12014-11-26 15:28:44 +000016228 DCHECK(result.is_identical_to(new_dict));
16229 USE(result);
Steve Blocka7e24c12009-10-30 11:49:00 +000016230 }
16231 }
16232
16233 uint32_t result = pos;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000016234 PropertyDetails no_details = PropertyDetails::Empty();
Steve Blocka7e24c12009-10-30 11:49:00 +000016235 while (undefs > 0) {
Steve Block1e0659c2011-05-24 12:43:12 +010016236 if (pos > static_cast<uint32_t>(Smi::kMaxValue)) {
16237 // Adding an entry with the key beyond smi-range requires
16238 // allocation. Bailout.
Ben Murdochb8a8cc12014-11-26 15:28:44 +000016239 return bailout;
Steve Block1e0659c2011-05-24 12:43:12 +010016240 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +000016241 HandleScope scope(isolate);
16242 Handle<Object> result = SeededNumberDictionary::AddNumberEntry(
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000016243 new_dict, pos, isolate->factory()->undefined_value(), no_details,
16244 object->map()->is_prototype_map());
Ben Murdochb8a8cc12014-11-26 15:28:44 +000016245 DCHECK(result.is_identical_to(new_dict));
16246 USE(result);
Steve Blocka7e24c12009-10-30 11:49:00 +000016247 pos++;
16248 undefs--;
16249 }
16250
Ben Murdochb8a8cc12014-11-26 15:28:44 +000016251 object->set_elements(*new_dict);
Steve Blocka7e24c12009-10-30 11:49:00 +000016252
Ben Murdochb8a8cc12014-11-26 15:28:44 +000016253 AllowHeapAllocation allocate_return_value;
16254 return isolate->factory()->NewNumberFromUint(result);
Steve Blocka7e24c12009-10-30 11:49:00 +000016255}
16256
16257
16258// Collects all defined (non-hole) and non-undefined (array) elements at
16259// the start of the elements array.
16260// If the object is in dictionary mode, it is converted to fast elements
16261// mode.
Ben Murdochb8a8cc12014-11-26 15:28:44 +000016262Handle<Object> JSObject::PrepareElementsForSort(Handle<JSObject> object,
16263 uint32_t limit) {
16264 Isolate* isolate = object->GetIsolate();
Ben Murdochc5610432016-08-08 18:44:38 +010016265 if (object->HasSloppyArgumentsElements()) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000016266 return handle(Smi::FromInt(-1), isolate);
16267 }
Ben Murdoch8b112d22011-06-08 16:22:53 +010016268
Ben Murdoch097c5b22016-05-18 11:27:45 +010016269 if (object->HasStringWrapperElements()) {
16270 int len = String::cast(Handle<JSValue>::cast(object)->value())->length();
16271 return handle(Smi::FromInt(len), isolate);
16272 }
16273
Ben Murdochb8a8cc12014-11-26 15:28:44 +000016274 if (object->HasDictionaryElements()) {
Steve Blocka7e24c12009-10-30 11:49:00 +000016275 // Convert to fast elements containing only the existing properties.
16276 // Ordering is irrelevant, since we are going to sort anyway.
Ben Murdochb8a8cc12014-11-26 15:28:44 +000016277 Handle<SeededNumberDictionary> dict(object->element_dictionary());
16278 if (object->IsJSArray() || dict->requires_slow_elements() ||
Steve Blocka7e24c12009-10-30 11:49:00 +000016279 dict->max_number_key() >= limit) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000016280 return JSObject::PrepareSlowElementsForSort(object, limit);
Steve Blocka7e24c12009-10-30 11:49:00 +000016281 }
16282 // Convert to fast elements.
16283
Ben Murdochb8a8cc12014-11-26 15:28:44 +000016284 Handle<Map> new_map =
16285 JSObject::GetElementsTransitionMap(object, FAST_HOLEY_ELEMENTS);
Steve Block8defd9f2010-07-08 12:39:36 +010016286
Ben Murdochb8a8cc12014-11-26 15:28:44 +000016287 PretenureFlag tenure = isolate->heap()->InNewSpace(*object) ?
16288 NOT_TENURED: TENURED;
16289 Handle<FixedArray> fast_elements =
16290 isolate->factory()->NewFixedArray(dict->NumberOfElements(), tenure);
16291 dict->CopyValuesTo(*fast_elements);
16292 JSObject::ValidateElements(object);
Steve Block8defd9f2010-07-08 12:39:36 +010016293
Ben Murdochb8a8cc12014-11-26 15:28:44 +000016294 JSObject::SetMapAndElements(object, new_map, fast_elements);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000016295 } else if (object->HasFixedTypedArrayElements()) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000016296 // Typed arrays cannot have holes or undefined elements.
16297 return handle(Smi::FromInt(
16298 FixedArrayBase::cast(object->elements())->length()), isolate);
16299 } else if (!object->HasFastDoubleElements()) {
16300 EnsureWritableFastElements(object);
Steve Blocka7e24c12009-10-30 11:49:00 +000016301 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +000016302 DCHECK(object->HasFastSmiOrObjectElements() ||
16303 object->HasFastDoubleElements());
Steve Blocka7e24c12009-10-30 11:49:00 +000016304
16305 // Collect holes at the end, undefined before that and the rest at the
16306 // start, and return the number of non-hole, non-undefined values.
16307
Ben Murdochb8a8cc12014-11-26 15:28:44 +000016308 Handle<FixedArrayBase> elements_base(object->elements());
Ben Murdoch69a99ed2011-11-30 16:03:39 +000016309 uint32_t elements_length = static_cast<uint32_t>(elements_base->length());
Steve Blocka7e24c12009-10-30 11:49:00 +000016310 if (limit > elements_length) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000016311 limit = elements_length;
Steve Blocka7e24c12009-10-30 11:49:00 +000016312 }
16313 if (limit == 0) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000016314 return handle(Smi::FromInt(0), isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +000016315 }
16316
Ben Murdoch69a99ed2011-11-30 16:03:39 +000016317 uint32_t result = 0;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000016318 if (elements_base->map() == isolate->heap()->fixed_double_array_map()) {
16319 FixedDoubleArray* elements = FixedDoubleArray::cast(*elements_base);
Ben Murdoch69a99ed2011-11-30 16:03:39 +000016320 // Split elements into defined and the_hole, in that order.
16321 unsigned int holes = limit;
16322 // Assume most arrays contain no holes and undefined values, so minimize the
16323 // number of stores of non-undefined, non-the-hole values.
16324 for (unsigned int i = 0; i < holes; i++) {
16325 if (elements->is_the_hole(i)) {
16326 holes--;
16327 } else {
16328 continue;
16329 }
16330 // Position i needs to be filled.
16331 while (holes > i) {
16332 if (elements->is_the_hole(holes)) {
16333 holes--;
16334 } else {
16335 elements->set(i, elements->get_scalar(holes));
16336 break;
16337 }
16338 }
Steve Blocka7e24c12009-10-30 11:49:00 +000016339 }
Ben Murdoch69a99ed2011-11-30 16:03:39 +000016340 result = holes;
16341 while (holes < limit) {
16342 elements->set_the_hole(holes);
16343 holes++;
16344 }
16345 } else {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000016346 FixedArray* elements = FixedArray::cast(*elements_base);
16347 DisallowHeapAllocation no_gc;
Ben Murdoch69a99ed2011-11-30 16:03:39 +000016348
16349 // Split elements into defined, undefined and the_hole, in that order. Only
16350 // count locations for undefined and the hole, and fill them afterwards.
Ben Murdochb8a8cc12014-11-26 15:28:44 +000016351 WriteBarrierMode write_barrier = elements->GetWriteBarrierMode(no_gc);
Ben Murdoch69a99ed2011-11-30 16:03:39 +000016352 unsigned int undefs = limit;
16353 unsigned int holes = limit;
16354 // Assume most arrays contain no holes and undefined values, so minimize the
16355 // number of stores of non-undefined, non-the-hole values.
16356 for (unsigned int i = 0; i < undefs; i++) {
16357 Object* current = elements->get(i);
Steve Blocka7e24c12009-10-30 11:49:00 +000016358 if (current->IsTheHole()) {
16359 holes--;
16360 undefs--;
16361 } else if (current->IsUndefined()) {
16362 undefs--;
16363 } else {
Ben Murdoch69a99ed2011-11-30 16:03:39 +000016364 continue;
16365 }
16366 // Position i needs to be filled.
16367 while (undefs > i) {
16368 current = elements->get(undefs);
16369 if (current->IsTheHole()) {
16370 holes--;
16371 undefs--;
16372 } else if (current->IsUndefined()) {
16373 undefs--;
16374 } else {
16375 elements->set(i, current, write_barrier);
16376 break;
16377 }
Steve Blocka7e24c12009-10-30 11:49:00 +000016378 }
16379 }
Ben Murdoch69a99ed2011-11-30 16:03:39 +000016380 result = undefs;
16381 while (undefs < holes) {
16382 elements->set_undefined(undefs);
16383 undefs++;
16384 }
16385 while (holes < limit) {
16386 elements->set_the_hole(holes);
16387 holes++;
16388 }
Steve Blocka7e24c12009-10-30 11:49:00 +000016389 }
16390
Ben Murdochb8a8cc12014-11-26 15:28:44 +000016391 return isolate->factory()->NewNumberFromUint(result);
Steve Blocka7e24c12009-10-30 11:49:00 +000016392}
16393
16394
Ben Murdochb8a8cc12014-11-26 15:28:44 +000016395ExternalArrayType JSTypedArray::type() {
16396 switch (elements()->map()->instance_type()) {
16397#define INSTANCE_TYPE_TO_ARRAY_TYPE(Type, type, TYPE, ctype, size) \
Ben Murdochb8a8cc12014-11-26 15:28:44 +000016398 case FIXED_##TYPE##_ARRAY_TYPE: \
16399 return kExternal##Type##Array;
16400
16401 TYPED_ARRAYS(INSTANCE_TYPE_TO_ARRAY_TYPE)
16402#undef INSTANCE_TYPE_TO_ARRAY_TYPE
16403
16404 default:
16405 UNREACHABLE();
16406 return static_cast<ExternalArrayType>(-1);
16407 }
16408}
16409
16410
16411size_t JSTypedArray::element_size() {
16412 switch (elements()->map()->instance_type()) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000016413#define INSTANCE_TYPE_TO_ELEMENT_SIZE(Type, type, TYPE, ctype, size) \
16414 case FIXED_##TYPE##_ARRAY_TYPE: \
16415 return size;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000016416
16417 TYPED_ARRAYS(INSTANCE_TYPE_TO_ELEMENT_SIZE)
16418#undef INSTANCE_TYPE_TO_ELEMENT_SIZE
16419
16420 default:
16421 UNREACHABLE();
16422 return 0;
16423 }
16424}
16425
16426
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000016427void JSGlobalObject::InvalidatePropertyCell(Handle<JSGlobalObject> global,
16428 Handle<Name> name) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -040016429 DCHECK(!global->HasFastProperties());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000016430 auto dictionary = handle(global->global_dictionary());
16431 int entry = dictionary->FindEntry(name);
16432 if (entry == GlobalDictionary::kNotFound) return;
16433 PropertyCell::InvalidateEntry(dictionary, entry);
Emily Bernierd0a1eb72015-03-24 16:35:39 -040016434}
16435
16436
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000016437// TODO(ishell): rename to EnsureEmptyPropertyCell or something.
Ben Murdochb8a8cc12014-11-26 15:28:44 +000016438Handle<PropertyCell> JSGlobalObject::EnsurePropertyCell(
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000016439 Handle<JSGlobalObject> global, Handle<Name> name) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000016440 DCHECK(!global->HasFastProperties());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000016441 auto dictionary = handle(global->global_dictionary());
16442 int entry = dictionary->FindEntry(name);
16443 Handle<PropertyCell> cell;
16444 if (entry != GlobalDictionary::kNotFound) {
16445 // This call should be idempotent.
16446 DCHECK(dictionary->ValueAt(entry)->IsPropertyCell());
16447 cell = handle(PropertyCell::cast(dictionary->ValueAt(entry)));
16448 DCHECK(cell->property_details().cell_type() ==
16449 PropertyCellType::kUninitialized ||
16450 cell->property_details().cell_type() ==
16451 PropertyCellType::kInvalidated);
16452 DCHECK(cell->value()->IsTheHole());
Steve Blocka7e24c12009-10-30 11:49:00 +000016453 return cell;
Steve Blocka7e24c12009-10-30 11:49:00 +000016454 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000016455 Isolate* isolate = global->GetIsolate();
16456 cell = isolate->factory()->NewPropertyCell();
16457 PropertyDetails details(NONE, DATA, 0, PropertyCellType::kUninitialized);
16458 dictionary = GlobalDictionary::Add(dictionary, name, cell, details);
16459 global->set_properties(*dictionary);
16460 return cell;
Steve Blocka7e24c12009-10-30 11:49:00 +000016461}
16462
16463
Ben Murdochb8a8cc12014-11-26 15:28:44 +000016464// This class is used for looking up two character strings in the string table.
Steve Blockd0582a62009-12-15 09:54:21 +000016465// If we don't have a hit we don't want to waste much time so we unroll the
16466// string hash calculation loop here for speed. Doesn't work if the two
16467// characters form a decimal integer, since such strings have a different hash
16468// algorithm.
16469class TwoCharHashTableKey : public HashTableKey {
16470 public:
Ben Murdochb8a8cc12014-11-26 15:28:44 +000016471 TwoCharHashTableKey(uint16_t c1, uint16_t c2, uint32_t seed)
Steve Blockd0582a62009-12-15 09:54:21 +000016472 : c1_(c1), c2_(c2) {
16473 // Char 1.
Ben Murdochc7cc0282012-03-05 14:35:55 +000016474 uint32_t hash = seed;
16475 hash += c1;
16476 hash += hash << 10;
Steve Blockd0582a62009-12-15 09:54:21 +000016477 hash ^= hash >> 6;
16478 // Char 2.
16479 hash += c2;
16480 hash += hash << 10;
16481 hash ^= hash >> 6;
16482 // GetHash.
16483 hash += hash << 3;
16484 hash ^= hash >> 11;
16485 hash += hash << 15;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000016486 if ((hash & String::kHashBitMask) == 0) hash = StringHasher::kZeroHash;
16487 hash_ = hash;
Steve Blockd0582a62009-12-15 09:54:21 +000016488#ifdef DEBUG
Steve Blockd0582a62009-12-15 09:54:21 +000016489 // If this assert fails then we failed to reproduce the two-character
16490 // version of the string hashing algorithm above. One reason could be
16491 // that we were passed two digits as characters, since the hash
16492 // algorithm is different in that case.
Ben Murdochb8a8cc12014-11-26 15:28:44 +000016493 uint16_t chars[2] = {c1, c2};
16494 uint32_t check_hash = StringHasher::HashSequentialString(chars, 2, seed);
16495 hash = (hash << String::kHashShift) | String::kIsNotArrayIndexMask;
16496 DCHECK_EQ(static_cast<int32_t>(hash), static_cast<int32_t>(check_hash));
Steve Blockd0582a62009-12-15 09:54:21 +000016497#endif
Steve Blockd0582a62009-12-15 09:54:21 +000016498 }
16499
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000016500 bool IsMatch(Object* o) override {
Steve Blockd0582a62009-12-15 09:54:21 +000016501 if (!o->IsString()) return false;
16502 String* other = String::cast(o);
16503 if (other->length() != 2) return false;
16504 if (other->Get(0) != c1_) return false;
16505 return other->Get(1) == c2_;
16506 }
16507
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000016508 uint32_t Hash() override { return hash_; }
16509 uint32_t HashForObject(Object* key) override {
Steve Blockd0582a62009-12-15 09:54:21 +000016510 if (!key->IsString()) return 0;
16511 return String::cast(key)->Hash();
16512 }
16513
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000016514 Handle<Object> AsHandle(Isolate* isolate) override {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000016515 // The TwoCharHashTableKey is only used for looking in the string
Steve Blockd0582a62009-12-15 09:54:21 +000016516 // table, not for adding to it.
16517 UNREACHABLE();
Ben Murdochb8a8cc12014-11-26 15:28:44 +000016518 return MaybeHandle<Object>().ToHandleChecked();
Steve Blockd0582a62009-12-15 09:54:21 +000016519 }
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000016520
Steve Blockd0582a62009-12-15 09:54:21 +000016521 private:
Ben Murdochb8a8cc12014-11-26 15:28:44 +000016522 uint16_t c1_;
16523 uint16_t c2_;
Steve Blockd0582a62009-12-15 09:54:21 +000016524 uint32_t hash_;
16525};
16526
16527
Ben Murdochb8a8cc12014-11-26 15:28:44 +000016528MaybeHandle<String> StringTable::InternalizeStringIfExists(
16529 Isolate* isolate,
16530 Handle<String> string) {
16531 if (string->IsInternalizedString()) {
16532 return string;
16533 }
16534 return LookupStringIfExists(isolate, string);
16535}
16536
16537
16538MaybeHandle<String> StringTable::LookupStringIfExists(
16539 Isolate* isolate,
16540 Handle<String> string) {
16541 Handle<StringTable> string_table = isolate->factory()->string_table();
16542 InternalizedStringKey key(string);
16543 int entry = string_table->FindEntry(&key);
Steve Blocka7e24c12009-10-30 11:49:00 +000016544 if (entry == kNotFound) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000016545 return MaybeHandle<String>();
Steve Blocka7e24c12009-10-30 11:49:00 +000016546 } else {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000016547 Handle<String> result(String::cast(string_table->KeyAt(entry)), isolate);
16548 DCHECK(StringShape(*result).IsInternalized());
16549 return result;
Steve Blocka7e24c12009-10-30 11:49:00 +000016550 }
16551}
16552
16553
Ben Murdochb8a8cc12014-11-26 15:28:44 +000016554MaybeHandle<String> StringTable::LookupTwoCharsStringIfExists(
16555 Isolate* isolate,
16556 uint16_t c1,
16557 uint16_t c2) {
16558 Handle<StringTable> string_table = isolate->factory()->string_table();
16559 TwoCharHashTableKey key(c1, c2, isolate->heap()->HashSeed());
16560 int entry = string_table->FindEntry(&key);
Steve Blockd0582a62009-12-15 09:54:21 +000016561 if (entry == kNotFound) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000016562 return MaybeHandle<String>();
Steve Blockd0582a62009-12-15 09:54:21 +000016563 } else {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000016564 Handle<String> result(String::cast(string_table->KeyAt(entry)), isolate);
16565 DCHECK(StringShape(*result).IsInternalized());
16566 return result;
Steve Blockd0582a62009-12-15 09:54:21 +000016567 }
16568}
16569
16570
Emily Bernierd0a1eb72015-03-24 16:35:39 -040016571void StringTable::EnsureCapacityForDeserialization(Isolate* isolate,
16572 int expected) {
16573 Handle<StringTable> table = isolate->factory()->string_table();
16574 // We need a key instance for the virtual hash function.
Ben Murdochda12d292016-06-02 14:46:10 +010016575 InternalizedStringKey dummy_key(isolate->factory()->empty_string());
Emily Bernierd0a1eb72015-03-24 16:35:39 -040016576 table = StringTable::EnsureCapacity(table, expected, &dummy_key);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000016577 isolate->heap()->SetRootStringTable(*table);
Emily Bernierd0a1eb72015-03-24 16:35:39 -040016578}
16579
16580
Ben Murdochb8a8cc12014-11-26 15:28:44 +000016581Handle<String> StringTable::LookupString(Isolate* isolate,
16582 Handle<String> string) {
Ben Murdochda12d292016-06-02 14:46:10 +010016583 if (string->IsConsString() && string->IsFlat()) {
16584 string = String::Flatten(string);
16585 if (string->IsInternalizedString()) return string;
16586 }
16587
Ben Murdochb8a8cc12014-11-26 15:28:44 +000016588 InternalizedStringKey key(string);
Ben Murdochda12d292016-06-02 14:46:10 +010016589 Handle<String> result = LookupKey(isolate, &key);
16590
16591 if (string->IsConsString()) {
16592 Handle<ConsString> cons = Handle<ConsString>::cast(string);
16593 cons->set_first(*result);
16594 cons->set_second(isolate->heap()->empty_string());
Ben Murdochc5610432016-08-08 18:44:38 +010016595 } else if (string->IsSlicedString()) {
16596 STATIC_ASSERT(ConsString::kSize == SlicedString::kSize);
16597 DisallowHeapAllocation no_gc;
16598 bool one_byte = result->IsOneByteRepresentation();
16599 Handle<Map> map = one_byte ? isolate->factory()->cons_one_byte_string_map()
16600 : isolate->factory()->cons_string_map();
16601 string->set_map(*map);
16602 Handle<ConsString> cons = Handle<ConsString>::cast(string);
16603 cons->set_first(*result);
16604 cons->set_second(isolate->heap()->empty_string());
Ben Murdochda12d292016-06-02 14:46:10 +010016605 }
16606 return result;
Steve Blocka7e24c12009-10-30 11:49:00 +000016607}
16608
16609
Ben Murdochb8a8cc12014-11-26 15:28:44 +000016610Handle<String> StringTable::LookupKey(Isolate* isolate, HashTableKey* key) {
16611 Handle<StringTable> table = isolate->factory()->string_table();
16612 int entry = table->FindEntry(key);
Steve Block9fac8402011-05-12 15:51:54 +010016613
Ben Murdochb8a8cc12014-11-26 15:28:44 +000016614 // String already in table.
Steve Blocka7e24c12009-10-30 11:49:00 +000016615 if (entry != kNotFound) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000016616 return handle(String::cast(table->KeyAt(entry)), isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +000016617 }
16618
Ben Murdochb8a8cc12014-11-26 15:28:44 +000016619 // Adding new string. Grow table if needed.
16620 table = StringTable::EnsureCapacity(table, 1, key);
Steve Blocka7e24c12009-10-30 11:49:00 +000016621
Ben Murdochb8a8cc12014-11-26 15:28:44 +000016622 // Create string object.
16623 Handle<Object> string = key->AsHandle(isolate);
16624 // There must be no attempts to internalize strings that could throw
16625 // InvalidStringLength error.
16626 CHECK(!string.is_null());
Steve Blocka7e24c12009-10-30 11:49:00 +000016627
Ben Murdochb8a8cc12014-11-26 15:28:44 +000016628 // Add the new string and return it along with the string table.
Steve Blocka7e24c12009-10-30 11:49:00 +000016629 entry = table->FindInsertionEntry(key->Hash());
Ben Murdochb8a8cc12014-11-26 15:28:44 +000016630 table->set(EntryToIndex(entry), *string);
Steve Blocka7e24c12009-10-30 11:49:00 +000016631 table->ElementAdded();
Ben Murdochb8a8cc12014-11-26 15:28:44 +000016632
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000016633 isolate->heap()->SetRootStringTable(*table);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000016634 return Handle<String>::cast(string);
Steve Blocka7e24c12009-10-30 11:49:00 +000016635}
16636
16637
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000016638String* StringTable::LookupKeyIfExists(Isolate* isolate, HashTableKey* key) {
16639 Handle<StringTable> table = isolate->factory()->string_table();
16640 int entry = table->FindEntry(key);
16641 if (entry != kNotFound) return String::cast(table->KeyAt(entry));
16642 return NULL;
16643}
16644
Ben Murdochda12d292016-06-02 14:46:10 +010016645Handle<StringSet> StringSet::New(Isolate* isolate) {
16646 return HashTable::New(isolate, 0);
16647}
16648
16649Handle<StringSet> StringSet::Add(Handle<StringSet> stringset,
16650 Handle<String> name) {
16651 if (!stringset->Has(name)) {
16652 stringset = EnsureCapacity(stringset, 1, *name);
16653 uint32_t hash = StringSetShape::Hash(*name);
16654 int entry = stringset->FindInsertionEntry(hash);
16655 stringset->set(EntryToIndex(entry), *name);
16656 stringset->ElementAdded();
16657 }
16658 return stringset;
16659}
16660
16661bool StringSet::Has(Handle<String> name) {
16662 return FindEntry(*name) != kNotFound;
16663}
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000016664
Ben Murdochb8a8cc12014-11-26 15:28:44 +000016665Handle<Object> CompilationCacheTable::Lookup(Handle<String> src,
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000016666 Handle<Context> context,
16667 LanguageMode language_mode) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000016668 Isolate* isolate = GetIsolate();
16669 Handle<SharedFunctionInfo> shared(context->closure()->shared());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000016670 StringSharedKey key(src, shared, language_mode, RelocInfo::kNoPosition);
Steve Blocka7e24c12009-10-30 11:49:00 +000016671 int entry = FindEntry(&key);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000016672 if (entry == kNotFound) return isolate->factory()->undefined_value();
Emily Bernierd0a1eb72015-03-24 16:35:39 -040016673 int index = EntryToIndex(entry);
16674 if (!get(index)->IsFixedArray()) return isolate->factory()->undefined_value();
16675 return Handle<Object>(get(index + 1), isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +000016676}
16677
16678
Ben Murdochb8a8cc12014-11-26 15:28:44 +000016679Handle<Object> CompilationCacheTable::LookupEval(
16680 Handle<String> src, Handle<SharedFunctionInfo> outer_info,
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000016681 LanguageMode language_mode, int scope_position) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000016682 Isolate* isolate = GetIsolate();
16683 // Cache key is the tuple (source, outer shared function info, scope position)
16684 // to unambiguously identify the context chain the cached eval code assumes.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000016685 StringSharedKey key(src, outer_info, language_mode, scope_position);
Steve Blocka7e24c12009-10-30 11:49:00 +000016686 int entry = FindEntry(&key);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000016687 if (entry == kNotFound) return isolate->factory()->undefined_value();
Emily Bernierd0a1eb72015-03-24 16:35:39 -040016688 int index = EntryToIndex(entry);
16689 if (!get(index)->IsFixedArray()) return isolate->factory()->undefined_value();
Ben Murdochb8a8cc12014-11-26 15:28:44 +000016690 return Handle<Object>(get(EntryToIndex(entry) + 1), isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +000016691}
16692
16693
Ben Murdochb8a8cc12014-11-26 15:28:44 +000016694Handle<Object> CompilationCacheTable::LookupRegExp(Handle<String> src,
16695 JSRegExp::Flags flags) {
16696 Isolate* isolate = GetIsolate();
16697 DisallowHeapAllocation no_allocation;
Steve Blocka7e24c12009-10-30 11:49:00 +000016698 RegExpKey key(src, flags);
16699 int entry = FindEntry(&key);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000016700 if (entry == kNotFound) return isolate->factory()->undefined_value();
16701 return Handle<Object>(get(EntryToIndex(entry) + 1), isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +000016702}
16703
16704
Ben Murdochb8a8cc12014-11-26 15:28:44 +000016705Handle<CompilationCacheTable> CompilationCacheTable::Put(
16706 Handle<CompilationCacheTable> cache, Handle<String> src,
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000016707 Handle<Context> context, LanguageMode language_mode, Handle<Object> value) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000016708 Isolate* isolate = cache->GetIsolate();
16709 Handle<SharedFunctionInfo> shared(context->closure()->shared());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000016710 StringSharedKey key(src, shared, language_mode, RelocInfo::kNoPosition);
Ben Murdochc5610432016-08-08 18:44:38 +010016711 Handle<Object> k = key.AsHandle(isolate);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000016712 cache = EnsureCapacity(cache, 1, &key);
Steve Blocka7e24c12009-10-30 11:49:00 +000016713 int entry = cache->FindInsertionEntry(key.Hash());
Ben Murdochb8a8cc12014-11-26 15:28:44 +000016714 cache->set(EntryToIndex(entry), *k);
Ben Murdochc5610432016-08-08 18:44:38 +010016715 cache->set(EntryToIndex(entry) + 1, *value);
Steve Blocka7e24c12009-10-30 11:49:00 +000016716 cache->ElementAdded();
16717 return cache;
16718}
16719
16720
Ben Murdochb8a8cc12014-11-26 15:28:44 +000016721Handle<CompilationCacheTable> CompilationCacheTable::PutEval(
16722 Handle<CompilationCacheTable> cache, Handle<String> src,
16723 Handle<SharedFunctionInfo> outer_info, Handle<SharedFunctionInfo> value,
16724 int scope_position) {
16725 Isolate* isolate = cache->GetIsolate();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000016726 StringSharedKey key(src, outer_info, value->language_mode(), scope_position);
Emily Bernierd0a1eb72015-03-24 16:35:39 -040016727 {
16728 Handle<Object> k = key.AsHandle(isolate);
16729 DisallowHeapAllocation no_allocation_scope;
16730 int entry = cache->FindEntry(&key);
16731 if (entry != kNotFound) {
16732 cache->set(EntryToIndex(entry), *k);
16733 cache->set(EntryToIndex(entry) + 1, *value);
16734 return cache;
16735 }
16736 }
16737
Ben Murdochb8a8cc12014-11-26 15:28:44 +000016738 cache = EnsureCapacity(cache, 1, &key);
Steve Blocka7e24c12009-10-30 11:49:00 +000016739 int entry = cache->FindInsertionEntry(key.Hash());
Emily Bernierd0a1eb72015-03-24 16:35:39 -040016740 Handle<Object> k =
16741 isolate->factory()->NewNumber(static_cast<double>(key.Hash()));
Ben Murdochb8a8cc12014-11-26 15:28:44 +000016742 cache->set(EntryToIndex(entry), *k);
Emily Bernierd0a1eb72015-03-24 16:35:39 -040016743 cache->set(EntryToIndex(entry) + 1, Smi::FromInt(kHashGenerations));
Steve Blocka7e24c12009-10-30 11:49:00 +000016744 cache->ElementAdded();
16745 return cache;
16746}
16747
16748
Ben Murdochb8a8cc12014-11-26 15:28:44 +000016749Handle<CompilationCacheTable> CompilationCacheTable::PutRegExp(
16750 Handle<CompilationCacheTable> cache, Handle<String> src,
16751 JSRegExp::Flags flags, Handle<FixedArray> value) {
Steve Blocka7e24c12009-10-30 11:49:00 +000016752 RegExpKey key(src, flags);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000016753 cache = EnsureCapacity(cache, 1, &key);
Steve Blocka7e24c12009-10-30 11:49:00 +000016754 int entry = cache->FindInsertionEntry(key.Hash());
Steve Block3ce2e202009-11-05 08:53:23 +000016755 // We store the value in the key slot, and compare the search key
16756 // to the stored value with a custon IsMatch function during lookups.
Ben Murdochb8a8cc12014-11-26 15:28:44 +000016757 cache->set(EntryToIndex(entry), *value);
16758 cache->set(EntryToIndex(entry) + 1, *value);
Steve Blocka7e24c12009-10-30 11:49:00 +000016759 cache->ElementAdded();
16760 return cache;
16761}
16762
16763
Emily Bernierd0a1eb72015-03-24 16:35:39 -040016764void CompilationCacheTable::Age() {
16765 DisallowHeapAllocation no_allocation;
16766 Object* the_hole_value = GetHeap()->the_hole_value();
16767 for (int entry = 0, size = Capacity(); entry < size; entry++) {
16768 int entry_index = EntryToIndex(entry);
16769 int value_index = entry_index + 1;
16770
16771 if (get(entry_index)->IsNumber()) {
16772 Smi* count = Smi::cast(get(value_index));
16773 count = Smi::FromInt(count->value() - 1);
16774 if (count->value() == 0) {
16775 NoWriteBarrierSet(this, entry_index, the_hole_value);
16776 NoWriteBarrierSet(this, value_index, the_hole_value);
16777 ElementRemoved();
16778 } else {
16779 NoWriteBarrierSet(this, value_index, count);
16780 }
16781 } else if (get(entry_index)->IsFixedArray()) {
16782 SharedFunctionInfo* info = SharedFunctionInfo::cast(get(value_index));
16783 if (info->code()->kind() != Code::FUNCTION || info->code()->IsOld()) {
16784 NoWriteBarrierSet(this, entry_index, the_hole_value);
16785 NoWriteBarrierSet(this, value_index, the_hole_value);
16786 ElementRemoved();
16787 }
16788 }
16789 }
16790}
16791
16792
Ben Murdochb0fe1622011-05-05 13:52:32 +010016793void CompilationCacheTable::Remove(Object* value) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000016794 DisallowHeapAllocation no_allocation;
Ben Murdoch3ef787d2012-04-12 10:51:47 +010016795 Object* the_hole_value = GetHeap()->the_hole_value();
Ben Murdochb0fe1622011-05-05 13:52:32 +010016796 for (int entry = 0, size = Capacity(); entry < size; entry++) {
16797 int entry_index = EntryToIndex(entry);
16798 int value_index = entry_index + 1;
16799 if (get(value_index) == value) {
Ben Murdoch3ef787d2012-04-12 10:51:47 +010016800 NoWriteBarrierSet(this, entry_index, the_hole_value);
16801 NoWriteBarrierSet(this, value_index, the_hole_value);
Ben Murdochb0fe1622011-05-05 13:52:32 +010016802 ElementRemoved();
16803 }
16804 }
16805 return;
16806}
16807
16808
Ben Murdochb8a8cc12014-11-26 15:28:44 +000016809template<typename Derived, typename Shape, typename Key>
16810Handle<Derived> Dictionary<Derived, Shape, Key>::New(
16811 Isolate* isolate,
16812 int at_least_space_for,
16813 PretenureFlag pretenure) {
16814 DCHECK(0 <= at_least_space_for);
16815 Handle<Derived> dict = DerivedHashTable::New(isolate,
16816 at_least_space_for,
16817 USE_DEFAULT_MINIMUM_CAPACITY,
16818 pretenure);
16819
John Reck59135872010-11-02 12:39:01 -070016820 // Initialize the next enumeration index.
Ben Murdochb8a8cc12014-11-26 15:28:44 +000016821 dict->SetNextEnumerationIndex(PropertyDetails::kInitialIndex);
16822 return dict;
Steve Blocka7e24c12009-10-30 11:49:00 +000016823}
16824
16825
Emily Bernierd0a1eb72015-03-24 16:35:39 -040016826template <typename Derived, typename Shape, typename Key>
16827Handle<FixedArray> Dictionary<Derived, Shape, Key>::BuildIterationIndicesArray(
Ben Murdochb8a8cc12014-11-26 15:28:44 +000016828 Handle<Derived> dictionary) {
16829 Factory* factory = dictionary->GetIsolate()->factory();
16830 int length = dictionary->NumberOfElements();
Steve Blocka7e24c12009-10-30 11:49:00 +000016831
Ben Murdochb8a8cc12014-11-26 15:28:44 +000016832 Handle<FixedArray> iteration_order = factory->NewFixedArray(length);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000016833 Handle<FixedArray> enumeration_order = factory->NewFixedArray(length);
Steve Blocka7e24c12009-10-30 11:49:00 +000016834
Emily Bernierd0a1eb72015-03-24 16:35:39 -040016835 // Fill both the iteration order array and the enumeration order array
16836 // with property details.
Ben Murdochb8a8cc12014-11-26 15:28:44 +000016837 int capacity = dictionary->Capacity();
Steve Blocka7e24c12009-10-30 11:49:00 +000016838 int pos = 0;
16839 for (int i = 0; i < capacity; i++) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000016840 if (dictionary->IsKey(dictionary->KeyAt(i))) {
16841 int index = dictionary->DetailsAt(i).dictionary_index();
Emily Bernierd0a1eb72015-03-24 16:35:39 -040016842 iteration_order->set(pos, Smi::FromInt(i));
16843 enumeration_order->set(pos, Smi::FromInt(index));
16844 pos++;
Steve Blocka7e24c12009-10-30 11:49:00 +000016845 }
16846 }
Emily Bernierd0a1eb72015-03-24 16:35:39 -040016847 DCHECK(pos == length);
Steve Blocka7e24c12009-10-30 11:49:00 +000016848
16849 // Sort the arrays wrt. enumeration order.
Ben Murdochb8a8cc12014-11-26 15:28:44 +000016850 iteration_order->SortPairs(*enumeration_order, enumeration_order->length());
Emily Bernierd0a1eb72015-03-24 16:35:39 -040016851 return iteration_order;
16852}
Steve Blocka7e24c12009-10-30 11:49:00 +000016853
Emily Bernierd0a1eb72015-03-24 16:35:39 -040016854
16855template <typename Derived, typename Shape, typename Key>
16856Handle<FixedArray>
16857Dictionary<Derived, Shape, Key>::GenerateNewEnumerationIndices(
16858 Handle<Derived> dictionary) {
16859 int length = dictionary->NumberOfElements();
16860
16861 Handle<FixedArray> iteration_order = BuildIterationIndicesArray(dictionary);
16862 DCHECK(iteration_order->length() == length);
16863
16864 // Iterate over the dictionary using the enumeration order and update
16865 // the dictionary with new enumeration indices.
Steve Blocka7e24c12009-10-30 11:49:00 +000016866 for (int i = 0; i < length; i++) {
16867 int index = Smi::cast(iteration_order->get(i))->value();
Emily Bernierd0a1eb72015-03-24 16:35:39 -040016868 DCHECK(dictionary->IsKey(dictionary->KeyAt(index)));
Steve Blocka7e24c12009-10-30 11:49:00 +000016869
Emily Bernierd0a1eb72015-03-24 16:35:39 -040016870 int enum_index = PropertyDetails::kInitialIndex + i;
16871
16872 PropertyDetails details = dictionary->DetailsAt(index);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000016873 PropertyDetails new_details = details.set_index(enum_index);
Emily Bernierd0a1eb72015-03-24 16:35:39 -040016874 dictionary->DetailsAtPut(index, new_details);
Steve Blocka7e24c12009-10-30 11:49:00 +000016875 }
16876
16877 // Set the next enumeration index.
Ben Murdochb8a8cc12014-11-26 15:28:44 +000016878 dictionary->SetNextEnumerationIndex(PropertyDetails::kInitialIndex+length);
Emily Bernierd0a1eb72015-03-24 16:35:39 -040016879 return iteration_order;
Steve Blocka7e24c12009-10-30 11:49:00 +000016880}
16881
Ben Murdochb8a8cc12014-11-26 15:28:44 +000016882
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000016883template <typename Derived, typename Shape, typename Key>
16884void Dictionary<Derived, Shape, Key>::SetRequiresCopyOnCapacityChange() {
16885 DCHECK_EQ(0, DerivedHashTable::NumberOfElements());
16886 DCHECK_EQ(0, DerivedHashTable::NumberOfDeletedElements());
16887 // Make sure that HashTable::EnsureCapacity will create a copy.
16888 DerivedHashTable::SetNumberOfDeletedElements(DerivedHashTable::Capacity());
16889 DCHECK(!DerivedHashTable::HasSufficientCapacity(1));
16890}
16891
16892
16893template <typename Derived, typename Shape, typename Key>
Ben Murdochb8a8cc12014-11-26 15:28:44 +000016894Handle<Derived> Dictionary<Derived, Shape, Key>::EnsureCapacity(
16895 Handle<Derived> dictionary, int n, Key key) {
Steve Blocka7e24c12009-10-30 11:49:00 +000016896 // Check whether there are enough enumeration indices to add n elements.
16897 if (Shape::kIsEnumerable &&
Ben Murdochb8a8cc12014-11-26 15:28:44 +000016898 !PropertyDetails::IsValidIndex(dictionary->NextEnumerationIndex() + n)) {
Steve Blocka7e24c12009-10-30 11:49:00 +000016899 // If not, we generate new indices for the properties.
Ben Murdochb8a8cc12014-11-26 15:28:44 +000016900 GenerateNewEnumerationIndices(dictionary);
Steve Blocka7e24c12009-10-30 11:49:00 +000016901 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +000016902 return DerivedHashTable::EnsureCapacity(dictionary, n, key);
Steve Blocka7e24c12009-10-30 11:49:00 +000016903}
16904
16905
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000016906template <typename Derived, typename Shape, typename Key>
Ben Murdochb8a8cc12014-11-26 15:28:44 +000016907Handle<Object> Dictionary<Derived, Shape, Key>::DeleteProperty(
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000016908 Handle<Derived> dictionary, int entry) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000016909 Factory* factory = dictionary->GetIsolate()->factory();
16910 PropertyDetails details = dictionary->DetailsAt(entry);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000016911 if (!details.IsConfigurable()) return factory->false_value();
Ben Murdochb8a8cc12014-11-26 15:28:44 +000016912
16913 dictionary->SetEntry(
16914 entry, factory->the_hole_value(), factory->the_hole_value());
16915 dictionary->ElementRemoved();
16916 return factory->true_value();
Steve Blocka7e24c12009-10-30 11:49:00 +000016917}
16918
16919
Ben Murdochb8a8cc12014-11-26 15:28:44 +000016920template<typename Derived, typename Shape, typename Key>
16921Handle<Derived> Dictionary<Derived, Shape, Key>::AtPut(
16922 Handle<Derived> dictionary, Key key, Handle<Object> value) {
16923 int entry = dictionary->FindEntry(key);
Steve Blocka7e24c12009-10-30 11:49:00 +000016924
16925 // If the entry is present set the value;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000016926 if (entry != Dictionary::kNotFound) {
16927 dictionary->ValueAtPut(entry, *value);
16928 return dictionary;
Steve Blocka7e24c12009-10-30 11:49:00 +000016929 }
16930
16931 // Check whether the dictionary should be extended.
Ben Murdochb8a8cc12014-11-26 15:28:44 +000016932 dictionary = EnsureCapacity(dictionary, 1, key);
16933#ifdef DEBUG
16934 USE(Shape::AsHandle(dictionary->GetIsolate(), key));
16935#endif
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000016936 PropertyDetails details = PropertyDetails::Empty();
Steve Blocka7e24c12009-10-30 11:49:00 +000016937
Ben Murdochb8a8cc12014-11-26 15:28:44 +000016938 AddEntry(dictionary, key, value, details, dictionary->Hash(key));
16939 return dictionary;
Steve Blocka7e24c12009-10-30 11:49:00 +000016940}
16941
16942
Ben Murdochb8a8cc12014-11-26 15:28:44 +000016943template<typename Derived, typename Shape, typename Key>
16944Handle<Derived> Dictionary<Derived, Shape, Key>::Add(
16945 Handle<Derived> dictionary,
16946 Key key,
16947 Handle<Object> value,
16948 PropertyDetails details) {
Steve Blocka7e24c12009-10-30 11:49:00 +000016949 // Valdate key is absent.
Ben Murdochb8a8cc12014-11-26 15:28:44 +000016950 SLOW_DCHECK((dictionary->FindEntry(key) == Dictionary::kNotFound));
Steve Blocka7e24c12009-10-30 11:49:00 +000016951 // Check whether the dictionary should be extended.
Ben Murdochb8a8cc12014-11-26 15:28:44 +000016952 dictionary = EnsureCapacity(dictionary, 1, key);
Ben Murdochc7cc0282012-03-05 14:35:55 +000016953
Ben Murdochb8a8cc12014-11-26 15:28:44 +000016954 AddEntry(dictionary, key, value, details, dictionary->Hash(key));
16955 return dictionary;
Steve Blocka7e24c12009-10-30 11:49:00 +000016956}
16957
16958
16959// Add a key, value pair to the dictionary.
Ben Murdochb8a8cc12014-11-26 15:28:44 +000016960template<typename Derived, typename Shape, typename Key>
16961void Dictionary<Derived, Shape, Key>::AddEntry(
16962 Handle<Derived> dictionary,
16963 Key key,
16964 Handle<Object> value,
16965 PropertyDetails details,
16966 uint32_t hash) {
Steve Blocka7e24c12009-10-30 11:49:00 +000016967 // Compute the key object.
Ben Murdochb8a8cc12014-11-26 15:28:44 +000016968 Handle<Object> k = Shape::AsHandle(dictionary->GetIsolate(), key);
Steve Blocka7e24c12009-10-30 11:49:00 +000016969
Ben Murdochb8a8cc12014-11-26 15:28:44 +000016970 uint32_t entry = dictionary->FindInsertionEntry(hash);
Steve Blocka7e24c12009-10-30 11:49:00 +000016971 // Insert element at empty or deleted entry
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000016972 if (details.dictionary_index() == 0 && Shape::kIsEnumerable) {
Steve Blocka7e24c12009-10-30 11:49:00 +000016973 // Assign an enumeration index to the property and update
16974 // SetNextEnumerationIndex.
Ben Murdochb8a8cc12014-11-26 15:28:44 +000016975 int index = dictionary->NextEnumerationIndex();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000016976 details = details.set_index(index);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000016977 dictionary->SetNextEnumerationIndex(index + 1);
Steve Blocka7e24c12009-10-30 11:49:00 +000016978 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +000016979 dictionary->SetEntry(entry, k, value, details);
16980 DCHECK((dictionary->KeyAt(entry)->IsNumber() ||
16981 dictionary->KeyAt(entry)->IsName()));
16982 dictionary->ElementAdded();
Steve Blocka7e24c12009-10-30 11:49:00 +000016983}
16984
Ben Murdochda12d292016-06-02 14:46:10 +010016985bool SeededNumberDictionary::HasComplexElements() {
16986 if (!requires_slow_elements()) return false;
16987 int capacity = this->Capacity();
16988 for (int i = 0; i < capacity; i++) {
16989 Object* k = this->KeyAt(i);
16990 if (this->IsKey(k)) {
16991 DCHECK(!IsDeleted(i));
16992 PropertyDetails details = this->DetailsAt(i);
16993 if (details.type() == ACCESSOR_CONSTANT) return true;
16994 PropertyAttributes attr = details.attributes();
16995 if (attr & ALL_ATTRIBUTES_MASK) return true;
16996 }
16997 }
16998 return false;
16999}
Steve Blocka7e24c12009-10-30 11:49:00 +000017000
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000017001void SeededNumberDictionary::UpdateMaxNumberKey(uint32_t key,
17002 bool used_as_prototype) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000017003 DisallowHeapAllocation no_allocation;
Steve Blocka7e24c12009-10-30 11:49:00 +000017004 // If the dictionary requires slow elements an element has already
17005 // been added at a high index.
17006 if (requires_slow_elements()) return;
17007 // Check if this index is high enough that we should require slow
17008 // elements.
17009 if (key > kRequiresSlowElementsLimit) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000017010 if (used_as_prototype) {
17011 // TODO(verwaest): Remove this hack.
17012 TypeFeedbackVector::ClearAllKeyedStoreICs(GetIsolate());
17013 }
Steve Blocka7e24c12009-10-30 11:49:00 +000017014 set_requires_slow_elements();
17015 return;
17016 }
17017 // Update max key value.
17018 Object* max_index_object = get(kMaxNumberKeyIndex);
17019 if (!max_index_object->IsSmi() || max_number_key() < key) {
17020 FixedArray::set(kMaxNumberKeyIndex,
Leon Clarke4515c472010-02-03 11:58:03 +000017021 Smi::FromInt(key << kRequiresSlowElementsTagSize));
Steve Blocka7e24c12009-10-30 11:49:00 +000017022 }
17023}
17024
17025
Ben Murdochb8a8cc12014-11-26 15:28:44 +000017026Handle<SeededNumberDictionary> SeededNumberDictionary::AddNumberEntry(
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000017027 Handle<SeededNumberDictionary> dictionary, uint32_t key,
17028 Handle<Object> value, PropertyDetails details, bool used_as_prototype) {
17029 dictionary->UpdateMaxNumberKey(key, used_as_prototype);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000017030 SLOW_DCHECK(dictionary->FindEntry(key) == kNotFound);
17031 return Add(dictionary, key, value, details);
Steve Blocka7e24c12009-10-30 11:49:00 +000017032}
17033
17034
Ben Murdochb8a8cc12014-11-26 15:28:44 +000017035Handle<UnseededNumberDictionary> UnseededNumberDictionary::AddNumberEntry(
17036 Handle<UnseededNumberDictionary> dictionary,
17037 uint32_t key,
17038 Handle<Object> value) {
17039 SLOW_DCHECK(dictionary->FindEntry(key) == kNotFound);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000017040 return Add(dictionary, key, value, PropertyDetails::Empty());
Ben Murdochc7cc0282012-03-05 14:35:55 +000017041}
17042
17043
Ben Murdochb8a8cc12014-11-26 15:28:44 +000017044Handle<SeededNumberDictionary> SeededNumberDictionary::AtNumberPut(
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000017045 Handle<SeededNumberDictionary> dictionary, uint32_t key,
17046 Handle<Object> value, bool used_as_prototype) {
17047 dictionary->UpdateMaxNumberKey(key, used_as_prototype);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000017048 return AtPut(dictionary, key, value);
Steve Blocka7e24c12009-10-30 11:49:00 +000017049}
17050
17051
Ben Murdochb8a8cc12014-11-26 15:28:44 +000017052Handle<UnseededNumberDictionary> UnseededNumberDictionary::AtNumberPut(
17053 Handle<UnseededNumberDictionary> dictionary,
17054 uint32_t key,
17055 Handle<Object> value) {
17056 return AtPut(dictionary, key, value);
Ben Murdochc7cc0282012-03-05 14:35:55 +000017057}
17058
17059
Ben Murdoch3ef787d2012-04-12 10:51:47 +010017060Handle<SeededNumberDictionary> SeededNumberDictionary::Set(
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000017061 Handle<SeededNumberDictionary> dictionary, uint32_t key,
17062 Handle<Object> value, PropertyDetails details, bool used_as_prototype) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000017063 int entry = dictionary->FindEntry(key);
17064 if (entry == kNotFound) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000017065 return AddNumberEntry(dictionary, key, value, details, used_as_prototype);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000017066 }
17067 // Preserve enumeration index.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000017068 details = details.set_index(dictionary->DetailsAt(entry).dictionary_index());
Ben Murdochb8a8cc12014-11-26 15:28:44 +000017069 Handle<Object> object_key =
17070 SeededNumberDictionaryShape::AsHandle(dictionary->GetIsolate(), key);
17071 dictionary->SetEntry(entry, object_key, value, details);
17072 return dictionary;
Ben Murdoch3ef787d2012-04-12 10:51:47 +010017073}
17074
17075
17076Handle<UnseededNumberDictionary> UnseededNumberDictionary::Set(
17077 Handle<UnseededNumberDictionary> dictionary,
Ben Murdochb8a8cc12014-11-26 15:28:44 +000017078 uint32_t key,
Ben Murdoch3ef787d2012-04-12 10:51:47 +010017079 Handle<Object> value) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000017080 int entry = dictionary->FindEntry(key);
17081 if (entry == kNotFound) return AddNumberEntry(dictionary, key, value);
17082 Handle<Object> object_key =
17083 UnseededNumberDictionaryShape::AsHandle(dictionary->GetIsolate(), key);
17084 dictionary->SetEntry(entry, object_key, value);
17085 return dictionary;
Ben Murdochc7cc0282012-03-05 14:35:55 +000017086}
17087
17088
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000017089template <typename Derived, typename Shape, typename Key>
Ben Murdochb8a8cc12014-11-26 15:28:44 +000017090int Dictionary<Derived, Shape, Key>::NumberOfElementsFilterAttributes(
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000017091 PropertyFilter filter) {
17092 int capacity = this->Capacity();
Steve Blocka7e24c12009-10-30 11:49:00 +000017093 int result = 0;
17094 for (int i = 0; i < capacity; i++) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000017095 Object* k = this->KeyAt(i);
17096 if (this->IsKey(k) && !k->FilterKey(filter)) {
17097 if (this->IsDeleted(i)) continue;
17098 PropertyDetails details = this->DetailsAt(i);
Steve Blocka7e24c12009-10-30 11:49:00 +000017099 PropertyAttributes attr = details.attributes();
17100 if ((attr & filter) == 0) result++;
17101 }
17102 }
17103 return result;
17104}
17105
17106
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000017107template <typename Dictionary>
Ben Murdochb8a8cc12014-11-26 15:28:44 +000017108struct EnumIndexComparator {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000017109 explicit EnumIndexComparator(Dictionary* dict) : dict(dict) {}
Ben Murdochb8a8cc12014-11-26 15:28:44 +000017110 bool operator() (Smi* a, Smi* b) {
17111 PropertyDetails da(dict->DetailsAt(a->value()));
17112 PropertyDetails db(dict->DetailsAt(b->value()));
17113 return da.dictionary_index() < db.dictionary_index();
17114 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000017115 Dictionary* dict;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000017116};
17117
17118
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000017119template <typename Derived, typename Shape, typename Key>
17120void Dictionary<Derived, Shape, Key>::CopyEnumKeysTo(FixedArray* storage) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000017121 int length = storage->length();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000017122 int capacity = this->Capacity();
Ben Murdochb8a8cc12014-11-26 15:28:44 +000017123 int properties = 0;
Steve Blocka7e24c12009-10-30 11:49:00 +000017124 for (int i = 0; i < capacity; i++) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000017125 Object* k = this->KeyAt(i);
17126 if (this->IsKey(k) && !k->IsSymbol()) {
17127 PropertyDetails details = this->DetailsAt(i);
17128 if (details.IsDontEnum() || this->IsDeleted(i)) continue;
17129 storage->set(properties, Smi::FromInt(i));
17130 properties++;
17131 if (properties == length) break;
17132 }
Steve Blocka7e24c12009-10-30 11:49:00 +000017133 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +000017134 CHECK_EQ(length, properties);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000017135 EnumIndexComparator<Derived> cmp(static_cast<Derived*>(this));
Ben Murdochb8a8cc12014-11-26 15:28:44 +000017136 Smi** start = reinterpret_cast<Smi**>(storage->GetFirstElementAddress());
17137 std::sort(start, start + length, cmp);
17138 for (int i = 0; i < length; i++) {
17139 int index = Smi::cast(storage->get(i))->value();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000017140 storage->set(i, this->KeyAt(index));
Ben Murdochb8a8cc12014-11-26 15:28:44 +000017141 }
Steve Blocka7e24c12009-10-30 11:49:00 +000017142}
17143
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000017144template <typename Derived, typename Shape, typename Key>
17145void Dictionary<Derived, Shape, Key>::CollectKeysTo(
17146 Handle<Dictionary<Derived, Shape, Key> > dictionary, KeyAccumulator* keys,
17147 PropertyFilter filter) {
17148 int capacity = dictionary->Capacity();
17149 Handle<FixedArray> array =
17150 keys->isolate()->factory()->NewFixedArray(dictionary->NumberOfElements());
17151 int array_size = 0;
17152
17153 {
17154 DisallowHeapAllocation no_gc;
17155 Dictionary<Derived, Shape, Key>* raw_dict = *dictionary;
17156 for (int i = 0; i < capacity; i++) {
17157 Object* k = raw_dict->KeyAt(i);
17158 if (!raw_dict->IsKey(k) || k->FilterKey(filter)) continue;
17159 if (raw_dict->IsDeleted(i)) continue;
17160 PropertyDetails details = raw_dict->DetailsAt(i);
17161 if ((details.attributes() & filter) != 0) continue;
17162 if (filter & ONLY_ALL_CAN_READ) {
17163 if (details.kind() != kAccessor) continue;
17164 Object* accessors = raw_dict->ValueAt(i);
17165 if (accessors->IsPropertyCell()) {
17166 accessors = PropertyCell::cast(accessors)->value();
17167 }
17168 if (!accessors->IsAccessorInfo()) continue;
17169 if (!AccessorInfo::cast(accessors)->all_can_read()) continue;
17170 }
17171 array->set(array_size++, Smi::FromInt(i));
17172 }
17173
17174 EnumIndexComparator<Derived> cmp(static_cast<Derived*>(raw_dict));
17175 Smi** start = reinterpret_cast<Smi**>(array->GetFirstElementAddress());
17176 std::sort(start, start + array_size, cmp);
17177 }
17178
17179 for (int i = 0; i < array_size; i++) {
17180 int index = Smi::cast(array->get(i))->value();
Ben Murdoch097c5b22016-05-18 11:27:45 +010017181 keys->AddKey(dictionary->KeyAt(index), DO_NOT_CONVERT);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000017182 }
Steve Blocka7e24c12009-10-30 11:49:00 +000017183}
17184
17185
17186// Backwards lookup (slow).
Ben Murdochb8a8cc12014-11-26 15:28:44 +000017187template<typename Derived, typename Shape, typename Key>
17188Object* Dictionary<Derived, Shape, Key>::SlowReverseLookup(Object* value) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000017189 int capacity = this->Capacity();
Steve Blocka7e24c12009-10-30 11:49:00 +000017190 for (int i = 0; i < capacity; i++) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000017191 Object* k = this->KeyAt(i);
17192 if (this->IsKey(k)) {
17193 Object* e = this->ValueAt(i);
17194 // TODO(dcarney): this should be templatized.
Ben Murdochb8a8cc12014-11-26 15:28:44 +000017195 if (e->IsPropertyCell()) {
17196 e = PropertyCell::cast(e)->value();
Steve Blocka7e24c12009-10-30 11:49:00 +000017197 }
17198 if (e == value) return k;
17199 }
17200 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +000017201 Heap* heap = Dictionary::GetHeap();
Steve Block44f0eee2011-05-26 01:26:41 +010017202 return heap->undefined_value();
Steve Blocka7e24c12009-10-30 11:49:00 +000017203}
17204
17205
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000017206Object* ObjectHashTable::Lookup(Isolate* isolate, Handle<Object> key,
17207 int32_t hash) {
17208 DisallowHeapAllocation no_gc;
17209 DCHECK(IsKey(*key));
17210
17211 int entry = FindEntry(isolate, key, hash);
17212 if (entry == kNotFound) return isolate->heap()->the_hole_value();
17213 return get(EntryToIndex(entry) + 1);
17214}
17215
17216
Ben Murdochb8a8cc12014-11-26 15:28:44 +000017217Object* ObjectHashTable::Lookup(Handle<Object> key) {
17218 DisallowHeapAllocation no_gc;
17219 DCHECK(IsKey(*key));
Ben Murdoch3ef787d2012-04-12 10:51:47 +010017220
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000017221 Isolate* isolate = GetIsolate();
17222
Ben Murdoch69a99ed2011-11-30 16:03:39 +000017223 // If the object does not have an identity hash, it was never used as a key.
Ben Murdochb8a8cc12014-11-26 15:28:44 +000017224 Object* hash = key->GetHash();
17225 if (hash->IsUndefined()) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000017226 return isolate->heap()->the_hole_value();
Ben Murdoch3ef787d2012-04-12 10:51:47 +010017227 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000017228 return Lookup(isolate, key, Smi::cast(hash)->value());
17229}
17230
17231
17232Object* ObjectHashTable::Lookup(Handle<Object> key, int32_t hash) {
17233 return Lookup(GetIsolate(), key, hash);
Ben Murdoch69a99ed2011-11-30 16:03:39 +000017234}
17235
17236
Ben Murdochb8a8cc12014-11-26 15:28:44 +000017237Handle<ObjectHashTable> ObjectHashTable::Put(Handle<ObjectHashTable> table,
17238 Handle<Object> key,
17239 Handle<Object> value) {
17240 DCHECK(table->IsKey(*key));
17241 DCHECK(!value->IsTheHole());
17242
17243 Isolate* isolate = table->GetIsolate();
Ben Murdoch69a99ed2011-11-30 16:03:39 +000017244 // Make sure the key object has an identity hash code.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000017245 int32_t hash = Object::GetOrCreateHash(isolate, key)->value();
Ben Murdoch69a99ed2011-11-30 16:03:39 +000017246
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000017247 return Put(table, key, value, hash);
17248}
17249
17250
17251Handle<ObjectHashTable> ObjectHashTable::Put(Handle<ObjectHashTable> table,
17252 Handle<Object> key,
17253 Handle<Object> value,
17254 int32_t hash) {
17255 DCHECK(table->IsKey(*key));
17256 DCHECK(!value->IsTheHole());
17257
17258 Isolate* isolate = table->GetIsolate();
17259
17260 int entry = table->FindEntry(isolate, key, hash);
Ben Murdoch69a99ed2011-11-30 16:03:39 +000017261
17262 // Key is already in table, just overwrite value.
17263 if (entry != kNotFound) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000017264 table->set(EntryToIndex(entry) + 1, *value);
17265 return table;
Ben Murdoch69a99ed2011-11-30 16:03:39 +000017266 }
17267
Ben Murdochc5610432016-08-08 18:44:38 +010017268 // Rehash if more than 33% of the entries are deleted entries.
Ben Murdoch097c5b22016-05-18 11:27:45 +010017269 // TODO(jochen): Consider to shrink the fixed array in place.
17270 if ((table->NumberOfDeletedElements() << 1) > table->NumberOfElements()) {
17271 table->Rehash(isolate->factory()->undefined_value());
17272 }
17273
Ben Murdoch69a99ed2011-11-30 16:03:39 +000017274 // Check whether the hash table should be extended.
Ben Murdochb8a8cc12014-11-26 15:28:44 +000017275 table = EnsureCapacity(table, 1, key);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000017276 table->AddEntry(table->FindInsertionEntry(hash), *key, *value);
Ben Murdoch69a99ed2011-11-30 16:03:39 +000017277 return table;
17278}
17279
17280
Ben Murdochb8a8cc12014-11-26 15:28:44 +000017281Handle<ObjectHashTable> ObjectHashTable::Remove(Handle<ObjectHashTable> table,
17282 Handle<Object> key,
17283 bool* was_present) {
17284 DCHECK(table->IsKey(*key));
17285
17286 Object* hash = key->GetHash();
17287 if (hash->IsUndefined()) {
17288 *was_present = false;
17289 return table;
17290 }
17291
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000017292 return Remove(table, key, was_present, Smi::cast(hash)->value());
17293}
17294
17295
17296Handle<ObjectHashTable> ObjectHashTable::Remove(Handle<ObjectHashTable> table,
17297 Handle<Object> key,
17298 bool* was_present,
17299 int32_t hash) {
17300 DCHECK(table->IsKey(*key));
17301
17302 int entry = table->FindEntry(table->GetIsolate(), key, hash);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000017303 if (entry == kNotFound) {
17304 *was_present = false;
17305 return table;
17306 }
17307
17308 *was_present = true;
17309 table->RemoveEntry(entry);
17310 return Shrink(table, key);
17311}
17312
17313
Ben Murdoch3ef787d2012-04-12 10:51:47 +010017314void ObjectHashTable::AddEntry(int entry, Object* key, Object* value) {
Ben Murdoch69a99ed2011-11-30 16:03:39 +000017315 set(EntryToIndex(entry), key);
17316 set(EntryToIndex(entry) + 1, value);
17317 ElementAdded();
17318}
17319
17320
Ben Murdoch3ef787d2012-04-12 10:51:47 +010017321void ObjectHashTable::RemoveEntry(int entry) {
17322 set_the_hole(EntryToIndex(entry));
17323 set_the_hole(EntryToIndex(entry) + 1);
Ben Murdoch69a99ed2011-11-30 16:03:39 +000017324 ElementRemoved();
17325}
17326
17327
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000017328Object* WeakHashTable::Lookup(Handle<HeapObject> key) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000017329 DisallowHeapAllocation no_gc;
17330 DCHECK(IsKey(*key));
17331 int entry = FindEntry(key);
17332 if (entry == kNotFound) return GetHeap()->the_hole_value();
17333 return get(EntryToValueIndex(entry));
17334}
17335
17336
17337Handle<WeakHashTable> WeakHashTable::Put(Handle<WeakHashTable> table,
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000017338 Handle<HeapObject> key,
17339 Handle<HeapObject> value) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000017340 DCHECK(table->IsKey(*key));
17341 int entry = table->FindEntry(key);
17342 // Key is already in table, just overwrite value.
17343 if (entry != kNotFound) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000017344 table->set(EntryToValueIndex(entry), *value);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000017345 return table;
17346 }
17347
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000017348 Handle<WeakCell> key_cell = key->GetIsolate()->factory()->NewWeakCell(key);
17349
Ben Murdochb8a8cc12014-11-26 15:28:44 +000017350 // Check whether the hash table should be extended.
17351 table = EnsureCapacity(table, 1, key, TENURED);
17352
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000017353 table->AddEntry(table->FindInsertionEntry(table->Hash(key)), key_cell, value);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000017354 return table;
17355}
17356
17357
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000017358void WeakHashTable::AddEntry(int entry, Handle<WeakCell> key_cell,
17359 Handle<HeapObject> value) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000017360 DisallowHeapAllocation no_allocation;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000017361 set(EntryToIndex(entry), *key_cell);
17362 set(EntryToValueIndex(entry), *value);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000017363 ElementAdded();
17364}
17365
17366
17367template<class Derived, class Iterator, int entrysize>
17368Handle<Derived> OrderedHashTable<Derived, Iterator, entrysize>::Allocate(
17369 Isolate* isolate, int capacity, PretenureFlag pretenure) {
17370 // Capacity must be a power of two, since we depend on being able
17371 // to divide and multiple by 2 (kLoadFactor) to derive capacity
17372 // from number of buckets. If we decide to change kLoadFactor
17373 // to something other than 2, capacity should be stored as another
17374 // field of this object.
17375 capacity = base::bits::RoundUpToPowerOfTwo32(Max(kMinCapacity, capacity));
17376 if (capacity > kMaxCapacity) {
17377 v8::internal::Heap::FatalProcessOutOfMemory("invalid table size", true);
17378 }
17379 int num_buckets = capacity / kLoadFactor;
17380 Handle<FixedArray> backing_store = isolate->factory()->NewFixedArray(
17381 kHashTableStartIndex + num_buckets + (capacity * kEntrySize), pretenure);
17382 backing_store->set_map_no_write_barrier(
17383 isolate->heap()->ordered_hash_table_map());
17384 Handle<Derived> table = Handle<Derived>::cast(backing_store);
17385 for (int i = 0; i < num_buckets; ++i) {
17386 table->set(kHashTableStartIndex + i, Smi::FromInt(kNotFound));
17387 }
17388 table->SetNumberOfBuckets(num_buckets);
17389 table->SetNumberOfElements(0);
17390 table->SetNumberOfDeletedElements(0);
17391 return table;
17392}
17393
17394
17395template<class Derived, class Iterator, int entrysize>
17396Handle<Derived> OrderedHashTable<Derived, Iterator, entrysize>::EnsureGrowable(
17397 Handle<Derived> table) {
17398 DCHECK(!table->IsObsolete());
17399
17400 int nof = table->NumberOfElements();
17401 int nod = table->NumberOfDeletedElements();
17402 int capacity = table->Capacity();
17403 if ((nof + nod) < capacity) return table;
17404 // Don't need to grow if we can simply clear out deleted entries instead.
17405 // Note that we can't compact in place, though, so we always allocate
17406 // a new table.
17407 return Rehash(table, (nod < (capacity >> 1)) ? capacity << 1 : capacity);
17408}
17409
17410
17411template<class Derived, class Iterator, int entrysize>
17412Handle<Derived> OrderedHashTable<Derived, Iterator, entrysize>::Shrink(
17413 Handle<Derived> table) {
17414 DCHECK(!table->IsObsolete());
17415
17416 int nof = table->NumberOfElements();
17417 int capacity = table->Capacity();
17418 if (nof >= (capacity >> 2)) return table;
17419 return Rehash(table, capacity / 2);
17420}
17421
17422
17423template<class Derived, class Iterator, int entrysize>
17424Handle<Derived> OrderedHashTable<Derived, Iterator, entrysize>::Clear(
17425 Handle<Derived> table) {
17426 DCHECK(!table->IsObsolete());
17427
17428 Handle<Derived> new_table =
17429 Allocate(table->GetIsolate(),
17430 kMinCapacity,
17431 table->GetHeap()->InNewSpace(*table) ? NOT_TENURED : TENURED);
17432
17433 table->SetNextTable(*new_table);
Emily Bernierd0a1eb72015-03-24 16:35:39 -040017434 table->SetNumberOfDeletedElements(kClearedTableSentinel);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000017435
17436 return new_table;
17437}
17438
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000017439template <class Derived, class Iterator, int entrysize>
17440bool OrderedHashTable<Derived, Iterator, entrysize>::HasKey(
17441 Handle<Derived> table, Handle<Object> key) {
17442 int entry = table->KeyToFirstEntry(*key);
17443 // Walk the chain in the bucket to find the key.
17444 while (entry != kNotFound) {
17445 Object* candidate_key = table->KeyAt(entry);
17446 if (candidate_key->SameValueZero(*key)) return true;
17447 entry = table->NextChainEntry(entry);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000017448 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000017449 return false;
17450}
17451
17452
17453Handle<OrderedHashSet> OrderedHashSet::Add(Handle<OrderedHashSet> table,
17454 Handle<Object> key) {
17455 int hash = Object::GetOrCreateHash(table->GetIsolate(), key)->value();
17456 int entry = table->HashToEntry(hash);
17457 // Walk the chain of the bucket and try finding the key.
17458 while (entry != kNotFound) {
17459 Object* candidate_key = table->KeyAt(entry);
17460 // Do not add if we have the key already
17461 if (candidate_key->SameValueZero(*key)) return table;
17462 entry = table->NextChainEntry(entry);
17463 }
17464
17465 table = OrderedHashSet::EnsureGrowable(table);
17466 // Read the existing bucket values.
17467 int bucket = table->HashToBucket(hash);
17468 int previous_entry = table->HashToEntry(hash);
17469 int nof = table->NumberOfElements();
17470 // Insert a new entry at the end,
17471 int new_entry = nof + table->NumberOfDeletedElements();
17472 int new_index = table->EntryToIndex(new_entry);
17473 table->set(new_index, *key);
17474 table->set(new_index + kChainOffset, Smi::FromInt(previous_entry));
17475 // and point the bucket to the new entry.
17476 table->set(kHashTableStartIndex + bucket, Smi::FromInt(new_entry));
17477 table->SetNumberOfElements(nof + 1);
17478 return table;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000017479}
17480
17481
17482template<class Derived, class Iterator, int entrysize>
17483Handle<Derived> OrderedHashTable<Derived, Iterator, entrysize>::Rehash(
17484 Handle<Derived> table, int new_capacity) {
Ben Murdochc5610432016-08-08 18:44:38 +010017485 Isolate* isolate = table->GetIsolate();
17486 Heap* heap = isolate->heap();
Ben Murdochb8a8cc12014-11-26 15:28:44 +000017487 DCHECK(!table->IsObsolete());
17488
Ben Murdochc5610432016-08-08 18:44:38 +010017489 Handle<Derived> new_table = Allocate(
17490 isolate, new_capacity, heap->InNewSpace(*table) ? NOT_TENURED : TENURED);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000017491 int nof = table->NumberOfElements();
17492 int nod = table->NumberOfDeletedElements();
17493 int new_buckets = new_table->NumberOfBuckets();
17494 int new_entry = 0;
17495 int removed_holes_index = 0;
17496
Ben Murdochc5610432016-08-08 18:44:38 +010017497 DisallowHeapAllocation no_gc;
17498 Object* the_hole = heap->the_hole_value();
Ben Murdochb8a8cc12014-11-26 15:28:44 +000017499 for (int old_entry = 0; old_entry < (nof + nod); ++old_entry) {
17500 Object* key = table->KeyAt(old_entry);
Ben Murdochc5610432016-08-08 18:44:38 +010017501 if (key == the_hole) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000017502 table->SetRemovedIndexAt(removed_holes_index++, old_entry);
17503 continue;
17504 }
17505
17506 Object* hash = key->GetHash();
17507 int bucket = Smi::cast(hash)->value() & (new_buckets - 1);
17508 Object* chain_entry = new_table->get(kHashTableStartIndex + bucket);
17509 new_table->set(kHashTableStartIndex + bucket, Smi::FromInt(new_entry));
17510 int new_index = new_table->EntryToIndex(new_entry);
17511 int old_index = table->EntryToIndex(old_entry);
17512 for (int i = 0; i < entrysize; ++i) {
17513 Object* value = table->get(old_index + i);
17514 new_table->set(new_index + i, value);
17515 }
17516 new_table->set(new_index + kChainOffset, chain_entry);
17517 ++new_entry;
17518 }
17519
17520 DCHECK_EQ(nod, removed_holes_index);
17521
17522 new_table->SetNumberOfElements(nof);
17523 table->SetNextTable(*new_table);
17524
17525 return new_table;
17526}
17527
17528
Ben Murdochb8a8cc12014-11-26 15:28:44 +000017529template Handle<OrderedHashSet>
17530OrderedHashTable<OrderedHashSet, JSSetIterator, 1>::Allocate(
17531 Isolate* isolate, int capacity, PretenureFlag pretenure);
17532
17533template Handle<OrderedHashSet>
17534OrderedHashTable<OrderedHashSet, JSSetIterator, 1>::EnsureGrowable(
17535 Handle<OrderedHashSet> table);
17536
17537template Handle<OrderedHashSet>
17538OrderedHashTable<OrderedHashSet, JSSetIterator, 1>::Shrink(
17539 Handle<OrderedHashSet> table);
17540
17541template Handle<OrderedHashSet>
17542OrderedHashTable<OrderedHashSet, JSSetIterator, 1>::Clear(
17543 Handle<OrderedHashSet> table);
17544
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000017545template bool OrderedHashTable<OrderedHashSet, JSSetIterator, 1>::HasKey(
17546 Handle<OrderedHashSet> table, Handle<Object> key);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000017547
17548
17549template Handle<OrderedHashMap>
17550OrderedHashTable<OrderedHashMap, JSMapIterator, 2>::Allocate(
17551 Isolate* isolate, int capacity, PretenureFlag pretenure);
17552
17553template Handle<OrderedHashMap>
17554OrderedHashTable<OrderedHashMap, JSMapIterator, 2>::EnsureGrowable(
17555 Handle<OrderedHashMap> table);
17556
17557template Handle<OrderedHashMap>
17558OrderedHashTable<OrderedHashMap, JSMapIterator, 2>::Shrink(
17559 Handle<OrderedHashMap> table);
17560
17561template Handle<OrderedHashMap>
17562OrderedHashTable<OrderedHashMap, JSMapIterator, 2>::Clear(
17563 Handle<OrderedHashMap> table);
17564
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000017565template bool OrderedHashTable<OrderedHashMap, JSMapIterator, 2>::HasKey(
17566 Handle<OrderedHashMap> table, Handle<Object> key);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000017567
17568
17569template<class Derived, class TableType>
17570void OrderedHashTableIterator<Derived, TableType>::Transition() {
17571 DisallowHeapAllocation no_allocation;
17572 TableType* table = TableType::cast(this->table());
17573 if (!table->IsObsolete()) return;
17574
17575 int index = Smi::cast(this->index())->value();
17576 while (table->IsObsolete()) {
17577 TableType* next_table = table->NextTable();
17578
17579 if (index > 0) {
17580 int nod = table->NumberOfDeletedElements();
17581
Emily Bernierd0a1eb72015-03-24 16:35:39 -040017582 if (nod == TableType::kClearedTableSentinel) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000017583 index = 0;
17584 } else {
17585 int old_index = index;
17586 for (int i = 0; i < nod; ++i) {
17587 int removed_index = table->RemovedIndexAt(i);
17588 if (removed_index >= old_index) break;
17589 --index;
17590 }
17591 }
17592 }
17593
17594 table = next_table;
17595 }
17596
17597 set_table(table);
17598 set_index(Smi::FromInt(index));
17599}
17600
17601
17602template<class Derived, class TableType>
17603bool OrderedHashTableIterator<Derived, TableType>::HasMore() {
17604 DisallowHeapAllocation no_allocation;
17605 if (this->table()->IsUndefined()) return false;
17606
17607 Transition();
17608
17609 TableType* table = TableType::cast(this->table());
17610 int index = Smi::cast(this->index())->value();
17611 int used_capacity = table->UsedCapacity();
17612
17613 while (index < used_capacity && table->KeyAt(index)->IsTheHole()) {
17614 index++;
17615 }
17616
17617 set_index(Smi::FromInt(index));
17618
17619 if (index < used_capacity) return true;
17620
17621 set_table(GetHeap()->undefined_value());
17622 return false;
17623}
17624
17625
17626template<class Derived, class TableType>
17627Smi* OrderedHashTableIterator<Derived, TableType>::Next(JSArray* value_array) {
17628 DisallowHeapAllocation no_allocation;
17629 if (HasMore()) {
17630 FixedArray* array = FixedArray::cast(value_array->elements());
17631 static_cast<Derived*>(this)->PopulateValueArray(array);
17632 MoveNext();
17633 return Smi::cast(kind());
17634 }
17635 return Smi::FromInt(0);
17636}
17637
17638
17639template Smi*
17640OrderedHashTableIterator<JSSetIterator, OrderedHashSet>::Next(
17641 JSArray* value_array);
17642
17643template bool
17644OrderedHashTableIterator<JSSetIterator, OrderedHashSet>::HasMore();
17645
17646template void
17647OrderedHashTableIterator<JSSetIterator, OrderedHashSet>::MoveNext();
17648
17649template Object*
17650OrderedHashTableIterator<JSSetIterator, OrderedHashSet>::CurrentKey();
17651
17652template void
17653OrderedHashTableIterator<JSSetIterator, OrderedHashSet>::Transition();
17654
17655
17656template Smi*
17657OrderedHashTableIterator<JSMapIterator, OrderedHashMap>::Next(
17658 JSArray* value_array);
17659
17660template bool
17661OrderedHashTableIterator<JSMapIterator, OrderedHashMap>::HasMore();
17662
17663template void
17664OrderedHashTableIterator<JSMapIterator, OrderedHashMap>::MoveNext();
17665
17666template Object*
17667OrderedHashTableIterator<JSMapIterator, OrderedHashMap>::CurrentKey();
17668
17669template void
17670OrderedHashTableIterator<JSMapIterator, OrderedHashMap>::Transition();
17671
17672
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000017673void JSSet::Initialize(Handle<JSSet> set, Isolate* isolate) {
17674 Handle<OrderedHashSet> table = isolate->factory()->NewOrderedHashSet();
17675 set->set_table(*table);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000017676}
17677
17678
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000017679void JSSet::Clear(Handle<JSSet> set) {
17680 Handle<OrderedHashSet> table(OrderedHashSet::cast(set->table()));
17681 table = OrderedHashSet::Clear(table);
17682 set->set_table(*table);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000017683}
17684
17685
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000017686void JSMap::Initialize(Handle<JSMap> map, Isolate* isolate) {
17687 Handle<OrderedHashMap> table = isolate->factory()->NewOrderedHashMap();
17688 map->set_table(*table);
17689}
17690
17691
17692void JSMap::Clear(Handle<JSMap> map) {
17693 Handle<OrderedHashMap> table(OrderedHashMap::cast(map->table()));
17694 table = OrderedHashMap::Clear(table);
17695 map->set_table(*table);
17696}
17697
17698
17699void JSWeakCollection::Initialize(Handle<JSWeakCollection> weak_collection,
17700 Isolate* isolate) {
17701 Handle<ObjectHashTable> table = ObjectHashTable::New(isolate, 0);
17702 weak_collection->set_table(*table);
17703}
17704
17705
17706void JSWeakCollection::Set(Handle<JSWeakCollection> weak_collection,
17707 Handle<Object> key, Handle<Object> value,
17708 int32_t hash) {
17709 DCHECK(key->IsJSReceiver() || key->IsSymbol());
17710 Handle<ObjectHashTable> table(
17711 ObjectHashTable::cast(weak_collection->table()));
17712 DCHECK(table->IsKey(*key));
17713 Handle<ObjectHashTable> new_table =
17714 ObjectHashTable::Put(table, key, value, hash);
17715 weak_collection->set_table(*new_table);
17716 if (*table != *new_table) {
17717 // Zap the old table since we didn't record slots for its elements.
17718 table->FillWithHoles(0, table->length());
Ben Murdochb8a8cc12014-11-26 15:28:44 +000017719 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000017720}
17721
17722
17723bool JSWeakCollection::Delete(Handle<JSWeakCollection> weak_collection,
17724 Handle<Object> key, int32_t hash) {
17725 DCHECK(key->IsJSReceiver() || key->IsSymbol());
17726 Handle<ObjectHashTable> table(
17727 ObjectHashTable::cast(weak_collection->table()));
17728 DCHECK(table->IsKey(*key));
17729 bool was_present = false;
17730 Handle<ObjectHashTable> new_table =
17731 ObjectHashTable::Remove(table, key, &was_present, hash);
17732 weak_collection->set_table(*new_table);
17733 if (*table != *new_table) {
17734 // Zap the old table since we didn't record slots for its elements.
17735 table->FillWithHoles(0, table->length());
17736 }
17737 return was_present;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000017738}
17739
Ben Murdoch097c5b22016-05-18 11:27:45 +010017740// Check if there is a break point at this code offset.
17741bool DebugInfo::HasBreakPoint(int code_offset) {
17742 // Get the break point info object for this code offset.
17743 Object* break_point_info = GetBreakPointInfo(code_offset);
Steve Blocka7e24c12009-10-30 11:49:00 +000017744
17745 // If there is no break point info object or no break points in the break
Ben Murdoch097c5b22016-05-18 11:27:45 +010017746 // point info object there is no break point at this code offset.
Steve Blocka7e24c12009-10-30 11:49:00 +000017747 if (break_point_info->IsUndefined()) return false;
17748 return BreakPointInfo::cast(break_point_info)->GetBreakPointCount() > 0;
17749}
17750
Ben Murdoch097c5b22016-05-18 11:27:45 +010017751// Get the break point info object for this code offset.
17752Object* DebugInfo::GetBreakPointInfo(int code_offset) {
17753 // Find the index of the break point info object for this code offset.
17754 int index = GetBreakPointInfoIndex(code_offset);
Steve Blocka7e24c12009-10-30 11:49:00 +000017755
17756 // Return the break point info object if any.
Ben Murdoch8b112d22011-06-08 16:22:53 +010017757 if (index == kNoBreakPointInfo) return GetHeap()->undefined_value();
Steve Blocka7e24c12009-10-30 11:49:00 +000017758 return BreakPointInfo::cast(break_points()->get(index));
17759}
17760
Ben Murdoch097c5b22016-05-18 11:27:45 +010017761// Clear a break point at the specified code offset.
17762void DebugInfo::ClearBreakPoint(Handle<DebugInfo> debug_info, int code_offset,
Steve Blocka7e24c12009-10-30 11:49:00 +000017763 Handle<Object> break_point_object) {
Ben Murdoch097c5b22016-05-18 11:27:45 +010017764 Handle<Object> break_point_info(debug_info->GetBreakPointInfo(code_offset),
Ben Murdochb8a8cc12014-11-26 15:28:44 +000017765 debug_info->GetIsolate());
Steve Blocka7e24c12009-10-30 11:49:00 +000017766 if (break_point_info->IsUndefined()) return;
17767 BreakPointInfo::ClearBreakPoint(
17768 Handle<BreakPointInfo>::cast(break_point_info),
17769 break_point_object);
17770}
17771
Ben Murdoch097c5b22016-05-18 11:27:45 +010017772void DebugInfo::SetBreakPoint(Handle<DebugInfo> debug_info, int code_offset,
17773 int source_position, int statement_position,
Steve Blocka7e24c12009-10-30 11:49:00 +000017774 Handle<Object> break_point_object) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000017775 Isolate* isolate = debug_info->GetIsolate();
Ben Murdoch097c5b22016-05-18 11:27:45 +010017776 Handle<Object> break_point_info(debug_info->GetBreakPointInfo(code_offset),
Ben Murdochb8a8cc12014-11-26 15:28:44 +000017777 isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +000017778 if (!break_point_info->IsUndefined()) {
17779 BreakPointInfo::SetBreakPoint(
17780 Handle<BreakPointInfo>::cast(break_point_info),
17781 break_point_object);
17782 return;
17783 }
17784
Ben Murdoch097c5b22016-05-18 11:27:45 +010017785 // Adding a new break point for a code offset which did not have any
Steve Blocka7e24c12009-10-30 11:49:00 +000017786 // break points before. Try to find a free slot.
17787 int index = kNoBreakPointInfo;
17788 for (int i = 0; i < debug_info->break_points()->length(); i++) {
17789 if (debug_info->break_points()->get(i)->IsUndefined()) {
17790 index = i;
17791 break;
17792 }
17793 }
17794 if (index == kNoBreakPointInfo) {
17795 // No free slot - extend break point info array.
17796 Handle<FixedArray> old_break_points =
17797 Handle<FixedArray>(FixedArray::cast(debug_info->break_points()));
Steve Blocka7e24c12009-10-30 11:49:00 +000017798 Handle<FixedArray> new_break_points =
Steve Block44f0eee2011-05-26 01:26:41 +010017799 isolate->factory()->NewFixedArray(
17800 old_break_points->length() +
Ben Murdochb8a8cc12014-11-26 15:28:44 +000017801 DebugInfo::kEstimatedNofBreakPointsInFunction);
Kristian Monsen0d5e1162010-09-30 15:31:59 +010017802
17803 debug_info->set_break_points(*new_break_points);
Steve Blocka7e24c12009-10-30 11:49:00 +000017804 for (int i = 0; i < old_break_points->length(); i++) {
17805 new_break_points->set(i, old_break_points->get(i));
17806 }
17807 index = old_break_points->length();
17808 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +000017809 DCHECK(index != kNoBreakPointInfo);
Steve Blocka7e24c12009-10-30 11:49:00 +000017810
17811 // Allocate new BreakPointInfo object and set the break point.
Steve Block44f0eee2011-05-26 01:26:41 +010017812 Handle<BreakPointInfo> new_break_point_info = Handle<BreakPointInfo>::cast(
17813 isolate->factory()->NewStruct(BREAK_POINT_INFO_TYPE));
Ben Murdoch097c5b22016-05-18 11:27:45 +010017814 new_break_point_info->set_code_offset(code_offset);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000017815 new_break_point_info->set_source_position(source_position);
17816 new_break_point_info->set_statement_position(statement_position);
Steve Block44f0eee2011-05-26 01:26:41 +010017817 new_break_point_info->set_break_point_objects(
17818 isolate->heap()->undefined_value());
Steve Blocka7e24c12009-10-30 11:49:00 +000017819 BreakPointInfo::SetBreakPoint(new_break_point_info, break_point_object);
17820 debug_info->break_points()->set(index, *new_break_point_info);
17821}
17822
Ben Murdoch097c5b22016-05-18 11:27:45 +010017823// Get the break point objects for a code offset.
17824Handle<Object> DebugInfo::GetBreakPointObjects(int code_offset) {
17825 Object* break_point_info = GetBreakPointInfo(code_offset);
Steve Blocka7e24c12009-10-30 11:49:00 +000017826 if (break_point_info->IsUndefined()) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000017827 return GetIsolate()->factory()->undefined_value();
Steve Blocka7e24c12009-10-30 11:49:00 +000017828 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000017829 return Handle<Object>(
17830 BreakPointInfo::cast(break_point_info)->break_point_objects(),
17831 GetIsolate());
Steve Blocka7e24c12009-10-30 11:49:00 +000017832}
17833
17834
17835// Get the total number of break points.
17836int DebugInfo::GetBreakPointCount() {
17837 if (break_points()->IsUndefined()) return 0;
17838 int count = 0;
17839 for (int i = 0; i < break_points()->length(); i++) {
17840 if (!break_points()->get(i)->IsUndefined()) {
17841 BreakPointInfo* break_point_info =
17842 BreakPointInfo::cast(break_points()->get(i));
17843 count += break_point_info->GetBreakPointCount();
17844 }
17845 }
17846 return count;
17847}
17848
17849
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000017850Handle<Object> DebugInfo::FindBreakPointInfo(
17851 Handle<DebugInfo> debug_info, Handle<Object> break_point_object) {
17852 Isolate* isolate = debug_info->GetIsolate();
17853 if (!debug_info->break_points()->IsUndefined()) {
17854 for (int i = 0; i < debug_info->break_points()->length(); i++) {
17855 if (!debug_info->break_points()->get(i)->IsUndefined()) {
17856 Handle<BreakPointInfo> break_point_info = Handle<BreakPointInfo>(
17857 BreakPointInfo::cast(debug_info->break_points()->get(i)), isolate);
17858 if (BreakPointInfo::HasBreakPointObject(break_point_info,
17859 break_point_object)) {
17860 return break_point_info;
17861 }
Steve Blocka7e24c12009-10-30 11:49:00 +000017862 }
17863 }
17864 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000017865 return isolate->factory()->undefined_value();
Steve Blocka7e24c12009-10-30 11:49:00 +000017866}
17867
17868
17869// Find the index of the break point info object for the specified code
17870// position.
Ben Murdoch097c5b22016-05-18 11:27:45 +010017871int DebugInfo::GetBreakPointInfoIndex(int code_offset) {
Steve Blocka7e24c12009-10-30 11:49:00 +000017872 if (break_points()->IsUndefined()) return kNoBreakPointInfo;
17873 for (int i = 0; i < break_points()->length(); i++) {
17874 if (!break_points()->get(i)->IsUndefined()) {
17875 BreakPointInfo* break_point_info =
17876 BreakPointInfo::cast(break_points()->get(i));
Ben Murdoch097c5b22016-05-18 11:27:45 +010017877 if (break_point_info->code_offset() == code_offset) {
Steve Blocka7e24c12009-10-30 11:49:00 +000017878 return i;
17879 }
17880 }
17881 }
17882 return kNoBreakPointInfo;
17883}
17884
17885
17886// Remove the specified break point object.
17887void BreakPointInfo::ClearBreakPoint(Handle<BreakPointInfo> break_point_info,
17888 Handle<Object> break_point_object) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000017889 Isolate* isolate = break_point_info->GetIsolate();
Steve Blocka7e24c12009-10-30 11:49:00 +000017890 // If there are no break points just ignore.
17891 if (break_point_info->break_point_objects()->IsUndefined()) return;
17892 // If there is a single break point clear it if it is the same.
17893 if (!break_point_info->break_point_objects()->IsFixedArray()) {
17894 if (break_point_info->break_point_objects() == *break_point_object) {
Steve Block44f0eee2011-05-26 01:26:41 +010017895 break_point_info->set_break_point_objects(
17896 isolate->heap()->undefined_value());
Steve Blocka7e24c12009-10-30 11:49:00 +000017897 }
17898 return;
17899 }
17900 // If there are multiple break points shrink the array
Ben Murdochb8a8cc12014-11-26 15:28:44 +000017901 DCHECK(break_point_info->break_point_objects()->IsFixedArray());
Steve Blocka7e24c12009-10-30 11:49:00 +000017902 Handle<FixedArray> old_array =
17903 Handle<FixedArray>(
17904 FixedArray::cast(break_point_info->break_point_objects()));
17905 Handle<FixedArray> new_array =
Steve Block44f0eee2011-05-26 01:26:41 +010017906 isolate->factory()->NewFixedArray(old_array->length() - 1);
Steve Blocka7e24c12009-10-30 11:49:00 +000017907 int found_count = 0;
17908 for (int i = 0; i < old_array->length(); i++) {
17909 if (old_array->get(i) == *break_point_object) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000017910 DCHECK(found_count == 0);
Steve Blocka7e24c12009-10-30 11:49:00 +000017911 found_count++;
17912 } else {
17913 new_array->set(i - found_count, old_array->get(i));
17914 }
17915 }
17916 // If the break point was found in the list change it.
17917 if (found_count > 0) break_point_info->set_break_point_objects(*new_array);
17918}
17919
17920
17921// Add the specified break point object.
17922void BreakPointInfo::SetBreakPoint(Handle<BreakPointInfo> break_point_info,
17923 Handle<Object> break_point_object) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000017924 Isolate* isolate = break_point_info->GetIsolate();
17925
Steve Blocka7e24c12009-10-30 11:49:00 +000017926 // If there was no break point objects before just set it.
17927 if (break_point_info->break_point_objects()->IsUndefined()) {
17928 break_point_info->set_break_point_objects(*break_point_object);
17929 return;
17930 }
17931 // If the break point object is the same as before just ignore.
17932 if (break_point_info->break_point_objects() == *break_point_object) return;
17933 // If there was one break point object before replace with array.
17934 if (!break_point_info->break_point_objects()->IsFixedArray()) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000017935 Handle<FixedArray> array = isolate->factory()->NewFixedArray(2);
Steve Blocka7e24c12009-10-30 11:49:00 +000017936 array->set(0, break_point_info->break_point_objects());
17937 array->set(1, *break_point_object);
17938 break_point_info->set_break_point_objects(*array);
17939 return;
17940 }
17941 // If there was more than one break point before extend array.
17942 Handle<FixedArray> old_array =
17943 Handle<FixedArray>(
17944 FixedArray::cast(break_point_info->break_point_objects()));
17945 Handle<FixedArray> new_array =
Ben Murdochb8a8cc12014-11-26 15:28:44 +000017946 isolate->factory()->NewFixedArray(old_array->length() + 1);
Steve Blocka7e24c12009-10-30 11:49:00 +000017947 for (int i = 0; i < old_array->length(); i++) {
17948 // If the break point was there before just ignore.
17949 if (old_array->get(i) == *break_point_object) return;
17950 new_array->set(i, old_array->get(i));
17951 }
17952 // Add the new break point.
17953 new_array->set(old_array->length(), *break_point_object);
17954 break_point_info->set_break_point_objects(*new_array);
17955}
17956
17957
17958bool BreakPointInfo::HasBreakPointObject(
17959 Handle<BreakPointInfo> break_point_info,
17960 Handle<Object> break_point_object) {
17961 // No break point.
17962 if (break_point_info->break_point_objects()->IsUndefined()) return false;
Ben Murdoch69a99ed2011-11-30 16:03:39 +000017963 // Single break point.
Steve Blocka7e24c12009-10-30 11:49:00 +000017964 if (!break_point_info->break_point_objects()->IsFixedArray()) {
17965 return break_point_info->break_point_objects() == *break_point_object;
17966 }
17967 // Multiple break points.
17968 FixedArray* array = FixedArray::cast(break_point_info->break_point_objects());
17969 for (int i = 0; i < array->length(); i++) {
17970 if (array->get(i) == *break_point_object) {
17971 return true;
17972 }
17973 }
17974 return false;
17975}
17976
17977
17978// Get the number of break points.
17979int BreakPointInfo::GetBreakPointCount() {
17980 // No break point.
17981 if (break_point_objects()->IsUndefined()) return 0;
Ben Murdoch69a99ed2011-11-30 16:03:39 +000017982 // Single break point.
Steve Blocka7e24c12009-10-30 11:49:00 +000017983 if (!break_point_objects()->IsFixedArray()) return 1;
17984 // Multiple break points.
17985 return FixedArray::cast(break_point_objects())->length();
17986}
Steve Blocka7e24c12009-10-30 11:49:00 +000017987
17988
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000017989// static
17990MaybeHandle<JSDate> JSDate::New(Handle<JSFunction> constructor,
17991 Handle<JSReceiver> new_target, double tv) {
17992 Isolate* const isolate = constructor->GetIsolate();
17993 Handle<JSObject> result;
17994 ASSIGN_RETURN_ON_EXCEPTION(isolate, result,
17995 JSObject::New(constructor, new_target), JSDate);
17996 if (-DateCache::kMaxTimeInMs <= tv && tv <= DateCache::kMaxTimeInMs) {
17997 tv = DoubleToInteger(tv) + 0.0;
17998 } else {
17999 tv = std::numeric_limits<double>::quiet_NaN();
18000 }
18001 Handle<Object> value = isolate->factory()->NewNumber(tv);
18002 Handle<JSDate>::cast(result)->SetValue(*value, std::isnan(tv));
18003 return Handle<JSDate>::cast(result);
18004}
18005
18006
18007// static
18008double JSDate::CurrentTimeValue(Isolate* isolate) {
18009 if (FLAG_log_timer_events || FLAG_prof_cpp) LOG(isolate, CurrentTimeEvent());
18010
18011 // According to ECMA-262, section 15.9.1, page 117, the precision of
18012 // the number in a Date object representing a particular instant in
18013 // time is milliseconds. Therefore, we floor the result of getting
18014 // the OS time.
18015 return Floor(FLAG_verify_predictable
18016 ? isolate->heap()->MonotonicallyIncreasingTimeInMs()
18017 : base::OS::TimeCurrentMillis());
18018}
18019
18020
18021// static
Ben Murdochb8a8cc12014-11-26 15:28:44 +000018022Object* JSDate::GetField(Object* object, Smi* index) {
Ben Murdoch3ef787d2012-04-12 10:51:47 +010018023 return JSDate::cast(object)->DoGetField(
18024 static_cast<FieldIndex>(index->value()));
18025}
18026
18027
18028Object* JSDate::DoGetField(FieldIndex index) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000018029 DCHECK(index != kDateValue);
Ben Murdoch3ef787d2012-04-12 10:51:47 +010018030
18031 DateCache* date_cache = GetIsolate()->date_cache();
18032
18033 if (index < kFirstUncachedField) {
18034 Object* stamp = cache_stamp();
18035 if (stamp != date_cache->stamp() && stamp->IsSmi()) {
18036 // Since the stamp is not NaN, the value is also not NaN.
18037 int64_t local_time_ms =
18038 date_cache->ToLocal(static_cast<int64_t>(value()->Number()));
Ben Murdochb8a8cc12014-11-26 15:28:44 +000018039 SetCachedFields(local_time_ms, date_cache);
Ben Murdoch3ef787d2012-04-12 10:51:47 +010018040 }
18041 switch (index) {
18042 case kYear: return year();
18043 case kMonth: return month();
18044 case kDay: return day();
18045 case kWeekday: return weekday();
18046 case kHour: return hour();
18047 case kMinute: return min();
18048 case kSecond: return sec();
18049 default: UNREACHABLE();
18050 }
18051 }
18052
18053 if (index >= kFirstUTCField) {
18054 return GetUTCField(index, value()->Number(), date_cache);
18055 }
18056
18057 double time = value()->Number();
Ben Murdochb8a8cc12014-11-26 15:28:44 +000018058 if (std::isnan(time)) return GetIsolate()->heap()->nan_value();
Ben Murdoch3ef787d2012-04-12 10:51:47 +010018059
18060 int64_t local_time_ms = date_cache->ToLocal(static_cast<int64_t>(time));
18061 int days = DateCache::DaysFromTime(local_time_ms);
18062
18063 if (index == kDays) return Smi::FromInt(days);
18064
18065 int time_in_day_ms = DateCache::TimeInDay(local_time_ms, days);
18066 if (index == kMillisecond) return Smi::FromInt(time_in_day_ms % 1000);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000018067 DCHECK(index == kTimeInDay);
Ben Murdoch3ef787d2012-04-12 10:51:47 +010018068 return Smi::FromInt(time_in_day_ms);
18069}
18070
18071
18072Object* JSDate::GetUTCField(FieldIndex index,
18073 double value,
18074 DateCache* date_cache) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000018075 DCHECK(index >= kFirstUTCField);
Ben Murdoch3ef787d2012-04-12 10:51:47 +010018076
Ben Murdochb8a8cc12014-11-26 15:28:44 +000018077 if (std::isnan(value)) return GetIsolate()->heap()->nan_value();
Ben Murdoch3ef787d2012-04-12 10:51:47 +010018078
18079 int64_t time_ms = static_cast<int64_t>(value);
18080
18081 if (index == kTimezoneOffset) {
18082 return Smi::FromInt(date_cache->TimezoneOffset(time_ms));
18083 }
18084
18085 int days = DateCache::DaysFromTime(time_ms);
18086
18087 if (index == kWeekdayUTC) return Smi::FromInt(date_cache->Weekday(days));
18088
18089 if (index <= kDayUTC) {
18090 int year, month, day;
18091 date_cache->YearMonthDayFromDays(days, &year, &month, &day);
18092 if (index == kYearUTC) return Smi::FromInt(year);
18093 if (index == kMonthUTC) return Smi::FromInt(month);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000018094 DCHECK(index == kDayUTC);
Ben Murdoch3ef787d2012-04-12 10:51:47 +010018095 return Smi::FromInt(day);
18096 }
18097
18098 int time_in_day_ms = DateCache::TimeInDay(time_ms, days);
18099 switch (index) {
18100 case kHourUTC: return Smi::FromInt(time_in_day_ms / (60 * 60 * 1000));
18101 case kMinuteUTC: return Smi::FromInt((time_in_day_ms / (60 * 1000)) % 60);
18102 case kSecondUTC: return Smi::FromInt((time_in_day_ms / 1000) % 60);
18103 case kMillisecondUTC: return Smi::FromInt(time_in_day_ms % 1000);
18104 case kDaysUTC: return Smi::FromInt(days);
18105 case kTimeInDayUTC: return Smi::FromInt(time_in_day_ms);
18106 default: UNREACHABLE();
18107 }
18108
18109 UNREACHABLE();
18110 return NULL;
18111}
18112
18113
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000018114// static
18115Handle<Object> JSDate::SetValue(Handle<JSDate> date, double v) {
18116 Isolate* const isolate = date->GetIsolate();
18117 Handle<Object> value = isolate->factory()->NewNumber(v);
18118 bool value_is_nan = std::isnan(v);
18119 date->SetValue(*value, value_is_nan);
18120 return value;
18121}
18122
18123
Ben Murdoch3ef787d2012-04-12 10:51:47 +010018124void JSDate::SetValue(Object* value, bool is_value_nan) {
18125 set_value(value);
18126 if (is_value_nan) {
18127 HeapNumber* nan = GetIsolate()->heap()->nan_value();
18128 set_cache_stamp(nan, SKIP_WRITE_BARRIER);
18129 set_year(nan, SKIP_WRITE_BARRIER);
18130 set_month(nan, SKIP_WRITE_BARRIER);
18131 set_day(nan, SKIP_WRITE_BARRIER);
18132 set_hour(nan, SKIP_WRITE_BARRIER);
18133 set_min(nan, SKIP_WRITE_BARRIER);
18134 set_sec(nan, SKIP_WRITE_BARRIER);
18135 set_weekday(nan, SKIP_WRITE_BARRIER);
18136 } else {
18137 set_cache_stamp(Smi::FromInt(DateCache::kInvalidStamp), SKIP_WRITE_BARRIER);
18138 }
18139}
18140
18141
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000018142// static
18143MaybeHandle<Object> JSDate::ToPrimitive(Handle<JSReceiver> receiver,
18144 Handle<Object> hint) {
18145 Isolate* const isolate = receiver->GetIsolate();
18146 if (hint->IsString()) {
18147 Handle<String> hint_string = Handle<String>::cast(hint);
18148 if (hint_string->Equals(isolate->heap()->number_string())) {
18149 return JSReceiver::OrdinaryToPrimitive(receiver,
18150 OrdinaryToPrimitiveHint::kNumber);
18151 }
18152 if (hint_string->Equals(isolate->heap()->default_string()) ||
18153 hint_string->Equals(isolate->heap()->string_string())) {
18154 return JSReceiver::OrdinaryToPrimitive(receiver,
18155 OrdinaryToPrimitiveHint::kString);
18156 }
18157 }
18158 THROW_NEW_ERROR(isolate, NewTypeError(MessageTemplate::kInvalidHint, hint),
18159 Object);
18160}
18161
18162
Ben Murdochb8a8cc12014-11-26 15:28:44 +000018163void JSDate::SetCachedFields(int64_t local_time_ms, DateCache* date_cache) {
Ben Murdoch3ef787d2012-04-12 10:51:47 +010018164 int days = DateCache::DaysFromTime(local_time_ms);
18165 int time_in_day_ms = DateCache::TimeInDay(local_time_ms, days);
18166 int year, month, day;
18167 date_cache->YearMonthDayFromDays(days, &year, &month, &day);
18168 int weekday = date_cache->Weekday(days);
18169 int hour = time_in_day_ms / (60 * 60 * 1000);
18170 int min = (time_in_day_ms / (60 * 1000)) % 60;
18171 int sec = (time_in_day_ms / 1000) % 60;
18172 set_cache_stamp(date_cache->stamp());
18173 set_year(Smi::FromInt(year), SKIP_WRITE_BARRIER);
18174 set_month(Smi::FromInt(month), SKIP_WRITE_BARRIER);
18175 set_day(Smi::FromInt(day), SKIP_WRITE_BARRIER);
18176 set_weekday(Smi::FromInt(weekday), SKIP_WRITE_BARRIER);
18177 set_hour(Smi::FromInt(hour), SKIP_WRITE_BARRIER);
18178 set_min(Smi::FromInt(min), SKIP_WRITE_BARRIER);
18179 set_sec(Smi::FromInt(sec), SKIP_WRITE_BARRIER);
18180}
18181
Ben Murdochb8a8cc12014-11-26 15:28:44 +000018182
18183void JSArrayBuffer::Neuter() {
Emily Bernierd0a1eb72015-03-24 16:35:39 -040018184 CHECK(is_neuterable());
18185 CHECK(is_external());
Ben Murdochb8a8cc12014-11-26 15:28:44 +000018186 set_backing_store(NULL);
18187 set_byte_length(Smi::FromInt(0));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000018188 set_was_neutered(true);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000018189}
18190
18191
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000018192void JSArrayBuffer::Setup(Handle<JSArrayBuffer> array_buffer, Isolate* isolate,
18193 bool is_external, void* data, size_t allocated_length,
18194 SharedFlag shared) {
18195 DCHECK(array_buffer->GetInternalFieldCount() ==
18196 v8::ArrayBuffer::kInternalFieldCount);
18197 for (int i = 0; i < v8::ArrayBuffer::kInternalFieldCount; i++) {
18198 array_buffer->SetInternalField(i, Smi::FromInt(0));
Ben Murdochb8a8cc12014-11-26 15:28:44 +000018199 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000018200 array_buffer->set_bit_field(0);
18201 array_buffer->set_is_external(is_external);
18202 array_buffer->set_is_neuterable(shared == SharedFlag::kNotShared);
18203 array_buffer->set_is_shared(shared == SharedFlag::kShared);
18204
18205 Handle<Object> byte_length =
18206 isolate->factory()->NewNumberFromSize(allocated_length);
18207 CHECK(byte_length->IsSmi() || byte_length->IsHeapNumber());
18208 array_buffer->set_byte_length(*byte_length);
18209 // Initialize backing store at last to avoid handling of |JSArrayBuffers| that
18210 // are currently being constructed in the |ArrayBufferTracker|. The
18211 // registration method below handles the case of registering a buffer that has
18212 // already been promoted.
18213 array_buffer->set_backing_store(data);
18214
18215 if (data && !is_external) {
18216 isolate->heap()->RegisterNewArrayBuffer(*array_buffer);
18217 }
18218}
18219
18220
18221bool JSArrayBuffer::SetupAllocatingData(Handle<JSArrayBuffer> array_buffer,
18222 Isolate* isolate,
18223 size_t allocated_length,
18224 bool initialize, SharedFlag shared) {
18225 void* data;
18226 CHECK(isolate->array_buffer_allocator() != NULL);
18227 // Prevent creating array buffers when serializing.
18228 DCHECK(!isolate->serializer_enabled());
18229 if (allocated_length != 0) {
18230 if (initialize) {
18231 data = isolate->array_buffer_allocator()->Allocate(allocated_length);
18232 } else {
18233 data = isolate->array_buffer_allocator()->AllocateUninitialized(
18234 allocated_length);
18235 }
18236 if (data == NULL) return false;
18237 } else {
18238 data = NULL;
18239 }
18240
18241 JSArrayBuffer::Setup(array_buffer, isolate, false, data, allocated_length,
18242 shared);
18243 return true;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000018244}
18245
18246
18247Handle<JSArrayBuffer> JSTypedArray::MaterializeArrayBuffer(
18248 Handle<JSTypedArray> typed_array) {
18249
18250 Handle<Map> map(typed_array->map());
18251 Isolate* isolate = typed_array->GetIsolate();
18252
18253 DCHECK(IsFixedTypedArrayElementsKind(map->elements_kind()));
18254
Ben Murdochb8a8cc12014-11-26 15:28:44 +000018255 Handle<FixedTypedArrayBase> fixed_typed_array(
18256 FixedTypedArrayBase::cast(typed_array->elements()));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000018257
18258 Handle<JSArrayBuffer> buffer(JSArrayBuffer::cast(typed_array->buffer()),
18259 isolate);
18260 void* backing_store =
18261 isolate->array_buffer_allocator()->AllocateUninitialized(
18262 fixed_typed_array->DataSize());
18263 buffer->set_is_external(false);
18264 DCHECK(buffer->byte_length()->IsSmi() ||
18265 buffer->byte_length()->IsHeapNumber());
18266 DCHECK(NumberToInt32(buffer->byte_length()) == fixed_typed_array->DataSize());
18267 // Initialize backing store at last to avoid handling of |JSArrayBuffers| that
18268 // are currently being constructed in the |ArrayBufferTracker|. The
18269 // registration method below handles the case of registering a buffer that has
18270 // already been promoted.
18271 buffer->set_backing_store(backing_store);
18272 isolate->heap()->RegisterNewArrayBuffer(*buffer);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000018273 memcpy(buffer->backing_store(),
18274 fixed_typed_array->DataPtr(),
18275 fixed_typed_array->DataSize());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000018276 Handle<FixedTypedArrayBase> new_elements =
18277 isolate->factory()->NewFixedTypedArrayWithExternalPointer(
Ben Murdochb8a8cc12014-11-26 15:28:44 +000018278 fixed_typed_array->length(), typed_array->type(),
18279 static_cast<uint8_t*>(buffer->backing_store()));
18280
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000018281 typed_array->set_elements(*new_elements);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000018282
18283 return buffer;
18284}
18285
18286
18287Handle<JSArrayBuffer> JSTypedArray::GetBuffer() {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000018288 Handle<JSArrayBuffer> array_buffer(JSArrayBuffer::cast(buffer()),
18289 GetIsolate());
18290 if (array_buffer->was_neutered() ||
18291 array_buffer->backing_store() != nullptr) {
18292 return array_buffer;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000018293 }
18294 Handle<JSTypedArray> self(this);
18295 return MaterializeArrayBuffer(self);
18296}
18297
18298
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000018299Handle<PropertyCell> PropertyCell::InvalidateEntry(
18300 Handle<GlobalDictionary> dictionary, int entry) {
18301 Isolate* isolate = dictionary->GetIsolate();
18302 // Swap with a copy.
18303 DCHECK(dictionary->ValueAt(entry)->IsPropertyCell());
18304 Handle<PropertyCell> cell(PropertyCell::cast(dictionary->ValueAt(entry)));
18305 auto new_cell = isolate->factory()->NewPropertyCell();
18306 new_cell->set_value(cell->value());
18307 dictionary->ValueAtPut(entry, *new_cell);
18308 bool is_the_hole = cell->value()->IsTheHole();
18309 // Cell is officially mutable henceforth.
18310 PropertyDetails details = cell->property_details();
18311 details = details.set_cell_type(is_the_hole ? PropertyCellType::kInvalidated
18312 : PropertyCellType::kMutable);
18313 new_cell->set_property_details(details);
18314 // Old cell is ready for invalidation.
18315 if (is_the_hole) {
18316 cell->set_value(isolate->heap()->undefined_value());
18317 } else {
18318 cell->set_value(isolate->heap()->the_hole_value());
18319 }
18320 details = details.set_cell_type(PropertyCellType::kInvalidated);
18321 cell->set_property_details(details);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000018322 cell->dependent_code()->DeoptimizeDependentCodeGroup(
18323 isolate, DependentCode::kPropertyCellChangedGroup);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000018324 return new_cell;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000018325}
18326
18327
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000018328PropertyCellConstantType PropertyCell::GetConstantType() {
18329 if (value()->IsSmi()) return PropertyCellConstantType::kSmi;
18330 return PropertyCellConstantType::kStableMap;
18331}
18332
18333
18334static bool RemainsConstantType(Handle<PropertyCell> cell,
18335 Handle<Object> value) {
18336 // TODO(dcarney): double->smi and smi->double transition from kConstant
18337 if (cell->value()->IsSmi() && value->IsSmi()) {
18338 return true;
18339 } else if (cell->value()->IsHeapObject() && value->IsHeapObject()) {
18340 return HeapObject::cast(cell->value())->map() ==
18341 HeapObject::cast(*value)->map() &&
18342 HeapObject::cast(*value)->map()->is_stable();
Emily Bernierd0a1eb72015-03-24 16:35:39 -040018343 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000018344 return false;
18345}
18346
18347
18348PropertyCellType PropertyCell::UpdatedType(Handle<PropertyCell> cell,
18349 Handle<Object> value,
18350 PropertyDetails details) {
18351 PropertyCellType type = details.cell_type();
18352 DCHECK(!value->IsTheHole());
18353 if (cell->value()->IsTheHole()) {
18354 switch (type) {
18355 // Only allow a cell to transition once into constant state.
18356 case PropertyCellType::kUninitialized:
18357 if (value->IsUndefined()) return PropertyCellType::kUndefined;
18358 return PropertyCellType::kConstant;
18359 case PropertyCellType::kInvalidated:
18360 return PropertyCellType::kMutable;
18361 default:
18362 UNREACHABLE();
18363 return PropertyCellType::kMutable;
18364 }
18365 }
18366 switch (type) {
18367 case PropertyCellType::kUndefined:
18368 return PropertyCellType::kConstant;
18369 case PropertyCellType::kConstant:
18370 if (*value == cell->value()) return PropertyCellType::kConstant;
18371 // Fall through.
18372 case PropertyCellType::kConstantType:
18373 if (RemainsConstantType(cell, value)) {
18374 return PropertyCellType::kConstantType;
18375 }
18376 // Fall through.
18377 case PropertyCellType::kMutable:
18378 return PropertyCellType::kMutable;
18379 }
18380 UNREACHABLE();
18381 return PropertyCellType::kMutable;
18382}
18383
18384
18385void PropertyCell::UpdateCell(Handle<GlobalDictionary> dictionary, int entry,
18386 Handle<Object> value, PropertyDetails details) {
18387 DCHECK(!value->IsTheHole());
18388 DCHECK(dictionary->ValueAt(entry)->IsPropertyCell());
18389 Handle<PropertyCell> cell(PropertyCell::cast(dictionary->ValueAt(entry)));
18390 const PropertyDetails original_details = cell->property_details();
18391 // Data accesses could be cached in ics or optimized code.
18392 bool invalidate =
18393 original_details.kind() == kData && details.kind() == kAccessor;
18394 int index = original_details.dictionary_index();
18395 PropertyCellType old_type = original_details.cell_type();
18396 // Preserve the enumeration index unless the property was deleted or never
18397 // initialized.
18398 if (cell->value()->IsTheHole()) {
18399 index = dictionary->NextEnumerationIndex();
18400 dictionary->SetNextEnumerationIndex(index + 1);
18401 // Negative lookup cells must be invalidated.
18402 invalidate = true;
18403 }
18404 DCHECK(index > 0);
18405 details = details.set_index(index);
18406
18407 PropertyCellType new_type = UpdatedType(cell, value, original_details);
18408 if (invalidate) cell = PropertyCell::InvalidateEntry(dictionary, entry);
18409
18410 // Install new property details and cell value.
18411 details = details.set_cell_type(new_type);
18412 cell->set_property_details(details);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000018413 cell->set_value(*value);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000018414
18415 // Deopt when transitioning from a constant type.
18416 if (!invalidate && (old_type != new_type ||
18417 original_details.IsReadOnly() != details.IsReadOnly())) {
18418 Isolate* isolate = dictionary->GetIsolate();
18419 cell->dependent_code()->DeoptimizeDependentCodeGroup(
18420 isolate, DependentCode::kPropertyCellChangedGroup);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000018421 }
18422}
18423
18424
18425// static
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000018426void PropertyCell::SetValueWithInvalidation(Handle<PropertyCell> cell,
18427 Handle<Object> new_value) {
18428 if (cell->value() != *new_value) {
18429 cell->set_value(*new_value);
18430 Isolate* isolate = cell->GetIsolate();
18431 cell->dependent_code()->DeoptimizeDependentCodeGroup(
18432 isolate, DependentCode::kPropertyCellChangedGroup);
18433 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +000018434}
18435
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000018436} // namespace internal
18437} // namespace v8