summaryrefslogtreecommitdiff
path: root/deps/v8/src/objects.cc
diff options
context:
space:
mode:
Diffstat (limited to 'deps/v8/src/objects.cc')
-rw-r--r--deps/v8/src/objects.cc1698
1 files changed, 1374 insertions, 324 deletions
diff --git a/deps/v8/src/objects.cc b/deps/v8/src/objects.cc
index 65d5d5f528..08383030d8 100644
--- a/deps/v8/src/objects.cc
+++ b/deps/v8/src/objects.cc
@@ -2,11 +2,12 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
+#include "src/objects.h"
+
+#include <cmath>
#include <iomanip>
#include <sstream>
-#include "src/v8.h"
-
#include "src/accessors.h"
#include "src/allocation-site-scopes.h"
#include "src/api.h"
@@ -18,7 +19,6 @@
#include "src/codegen.h"
#include "src/compilation-dependencies.h"
#include "src/compiler.h"
-#include "src/cpu-profiler.h"
#include "src/date.h"
#include "src/debug/debug.h"
#include "src/deoptimizer.h"
@@ -30,13 +30,16 @@
#include "src/hydrogen.h"
#include "src/ic/ic.h"
#include "src/interpreter/bytecodes.h"
+#include "src/isolate-inl.h"
#include "src/log.h"
#include "src/lookup.h"
#include "src/macro-assembler.h"
#include "src/messages.h"
#include "src/objects-inl.h"
+#include "src/profiler/cpu-profiler.h"
#include "src/prototype.h"
#include "src/safepoint-table.h"
+#include "src/string-builder.h"
#include "src/string-search.h"
#include "src/string-stream.h"
#include "src/utils.h"
@@ -90,6 +93,106 @@ MaybeHandle<JSReceiver> Object::ToObject(Isolate* isolate,
}
+// static
+MaybeHandle<Name> Object::ToName(Isolate* isolate, Handle<Object> input) {
+ ASSIGN_RETURN_ON_EXCEPTION(
+ isolate, input, Object::ToPrimitive(input, ToPrimitiveHint::kString),
+ Name);
+ if (input->IsName()) return Handle<Name>::cast(input);
+ return ToString(isolate, input);
+}
+
+
+// static
+MaybeHandle<Object> Object::ToNumber(Handle<Object> input) {
+ while (true) {
+ if (input->IsNumber()) {
+ return input;
+ }
+ if (input->IsString()) {
+ return String::ToNumber(Handle<String>::cast(input));
+ }
+ if (input->IsOddball()) {
+ return Oddball::ToNumber(Handle<Oddball>::cast(input));
+ }
+ Isolate* const isolate = Handle<HeapObject>::cast(input)->GetIsolate();
+ if (input->IsSymbol()) {
+ THROW_NEW_ERROR(isolate, NewTypeError(MessageTemplate::kSymbolToNumber),
+ Object);
+ }
+ if (input->IsSimd128Value()) {
+ THROW_NEW_ERROR(isolate, NewTypeError(MessageTemplate::kSimdToNumber),
+ Object);
+ }
+ ASSIGN_RETURN_ON_EXCEPTION(
+ isolate, input, JSReceiver::ToPrimitive(Handle<JSReceiver>::cast(input),
+ ToPrimitiveHint::kNumber),
+ Object);
+ }
+}
+
+
+// static
+MaybeHandle<Object> Object::ToInteger(Isolate* isolate, Handle<Object> input) {
+ ASSIGN_RETURN_ON_EXCEPTION(isolate, input, ToNumber(input), Object);
+ return isolate->factory()->NewNumber(DoubleToInteger(input->Number()));
+}
+
+
+// static
+MaybeHandle<Object> Object::ToInt32(Isolate* isolate, Handle<Object> input) {
+ ASSIGN_RETURN_ON_EXCEPTION(isolate, input, ToNumber(input), Object);
+ return isolate->factory()->NewNumberFromInt(DoubleToInt32(input->Number()));
+}
+
+
+// static
+MaybeHandle<Object> Object::ToUint32(Isolate* isolate, Handle<Object> input) {
+ ASSIGN_RETURN_ON_EXCEPTION(isolate, input, ToNumber(input), Object);
+ return isolate->factory()->NewNumberFromUint(DoubleToUint32(input->Number()));
+}
+
+
+// static
+MaybeHandle<String> Object::ToString(Isolate* isolate, Handle<Object> input) {
+ while (true) {
+ if (input->IsString()) {
+ return Handle<String>::cast(input);
+ }
+ if (input->IsOddball()) {
+ return handle(Handle<Oddball>::cast(input)->to_string(), isolate);
+ }
+ if (input->IsNumber()) {
+ return isolate->factory()->NumberToString(input);
+ }
+ if (input->IsSymbol()) {
+ THROW_NEW_ERROR(isolate, NewTypeError(MessageTemplate::kSymbolToString),
+ String);
+ }
+ if (input->IsSimd128Value()) {
+ return Simd128Value::ToString(Handle<Simd128Value>::cast(input));
+ }
+ ASSIGN_RETURN_ON_EXCEPTION(
+ isolate, input, JSReceiver::ToPrimitive(Handle<JSReceiver>::cast(input),
+ ToPrimitiveHint::kString),
+ String);
+ }
+}
+
+
+// static
+MaybeHandle<Object> Object::ToLength(Isolate* isolate, Handle<Object> input) {
+ ASSIGN_RETURN_ON_EXCEPTION(isolate, input, ToNumber(input), Object);
+ double len = DoubleToInteger(input->Number());
+ if (len <= 0.0) {
+ len = 0.0;
+ } else if (len >= kMaxSafeInteger) {
+ len = kMaxSafeInteger;
+ }
+ return isolate->factory()->NewNumber(len);
+}
+
+
bool Object::BooleanValue() {
if (IsBoolean()) return IsTrue();
if (IsSmi()) return Smi::cast(this)->value() != 0;
@@ -97,18 +200,169 @@ bool Object::BooleanValue() {
if (IsUndetectableObject()) return false; // Undetectable object is false.
if (IsString()) return String::cast(this)->length() != 0;
if (IsHeapNumber()) return HeapNumber::cast(this)->HeapNumberBooleanValue();
- if (IsSimd128Value()) return true; // Simd value types evaluate to true.
return true;
}
+namespace {
+
+// TODO(bmeurer): Maybe we should introduce a marker interface Number,
+// where we put all these methods at some point?
+ComparisonResult NumberCompare(double x, double y) {
+ if (std::isnan(x) || std::isnan(y)) {
+ return ComparisonResult::kUndefined;
+ } else if (x < y) {
+ return ComparisonResult::kLessThan;
+ } else if (x > y) {
+ return ComparisonResult::kGreaterThan;
+ } else {
+ return ComparisonResult::kEqual;
+ }
+}
+
+
+bool NumberEquals(double x, double y) {
+ // Must check explicitly for NaN's on Windows, but -0 works fine.
+ if (std::isnan(x)) return false;
+ if (std::isnan(y)) return false;
+ return x == y;
+}
+
+
+bool NumberEquals(const Object* x, const Object* y) {
+ return NumberEquals(x->Number(), y->Number());
+}
+
+
+bool NumberEquals(Handle<Object> x, Handle<Object> y) {
+ return NumberEquals(*x, *y);
+}
+
+} // namespace
+
+
+// static
+Maybe<ComparisonResult> Object::Compare(Handle<Object> x, Handle<Object> y,
+ Strength strength) {
+ if (!is_strong(strength)) {
+ // ES6 section 7.2.11 Abstract Relational Comparison step 3 and 4.
+ if (!Object::ToPrimitive(x, ToPrimitiveHint::kNumber).ToHandle(&x) ||
+ !Object::ToPrimitive(y, ToPrimitiveHint::kNumber).ToHandle(&y)) {
+ return Nothing<ComparisonResult>();
+ }
+ }
+ if (x->IsString() && y->IsString()) {
+ // ES6 section 7.2.11 Abstract Relational Comparison step 5.
+ return Just(
+ String::Compare(Handle<String>::cast(x), Handle<String>::cast(y)));
+ }
+ // ES6 section 7.2.11 Abstract Relational Comparison step 6.
+ if (!is_strong(strength)) {
+ if (!Object::ToNumber(x).ToHandle(&x) ||
+ !Object::ToNumber(y).ToHandle(&y)) {
+ return Nothing<ComparisonResult>();
+ }
+ } else {
+ if (!x->IsNumber()) {
+ Isolate* const isolate = Handle<HeapObject>::cast(x)->GetIsolate();
+ isolate->Throw(*isolate->factory()->NewTypeError(
+ MessageTemplate::kStrongImplicitConversion));
+ return Nothing<ComparisonResult>();
+ } else if (!y->IsNumber()) {
+ Isolate* const isolate = Handle<HeapObject>::cast(y)->GetIsolate();
+ isolate->Throw(*isolate->factory()->NewTypeError(
+ MessageTemplate::kStrongImplicitConversion));
+ return Nothing<ComparisonResult>();
+ }
+ }
+ return Just(NumberCompare(x->Number(), y->Number()));
+}
+
+
+// static
+Maybe<bool> Object::Equals(Handle<Object> x, Handle<Object> y) {
+ while (true) {
+ if (x->IsNumber()) {
+ if (y->IsNumber()) {
+ return Just(NumberEquals(x, y));
+ } else if (y->IsBoolean()) {
+ return Just(NumberEquals(*x, Handle<Oddball>::cast(y)->to_number()));
+ } else if (y->IsString()) {
+ return Just(NumberEquals(x, String::ToNumber(Handle<String>::cast(y))));
+ } else if (y->IsJSReceiver() && !y->IsUndetectableObject()) {
+ if (!JSReceiver::ToPrimitive(Handle<JSReceiver>::cast(y))
+ .ToHandle(&y)) {
+ return Nothing<bool>();
+ }
+ } else {
+ return Just(false);
+ }
+ } else if (x->IsString()) {
+ if (y->IsString()) {
+ return Just(
+ String::Equals(Handle<String>::cast(x), Handle<String>::cast(y)));
+ } else if (y->IsNumber()) {
+ x = String::ToNumber(Handle<String>::cast(x));
+ return Just(NumberEquals(x, y));
+ } else if (y->IsBoolean()) {
+ x = String::ToNumber(Handle<String>::cast(x));
+ return Just(NumberEquals(*x, Handle<Oddball>::cast(y)->to_number()));
+ } else if (y->IsJSReceiver() && !y->IsUndetectableObject()) {
+ if (!JSReceiver::ToPrimitive(Handle<JSReceiver>::cast(y))
+ .ToHandle(&y)) {
+ return Nothing<bool>();
+ }
+ } else {
+ return Just(false);
+ }
+ } else if (x->IsBoolean()) {
+ if (y->IsOddball()) {
+ return Just(x.is_identical_to(y));
+ } else if (y->IsNumber()) {
+ return Just(NumberEquals(Handle<Oddball>::cast(x)->to_number(), *y));
+ } else if (y->IsString()) {
+ y = String::ToNumber(Handle<String>::cast(y));
+ return Just(NumberEquals(Handle<Oddball>::cast(x)->to_number(), *y));
+ } else if (y->IsJSReceiver() && !y->IsUndetectableObject()) {
+ if (!JSReceiver::ToPrimitive(Handle<JSReceiver>::cast(y))
+ .ToHandle(&y)) {
+ return Nothing<bool>();
+ }
+ x = Oddball::ToNumber(Handle<Oddball>::cast(x));
+ } else {
+ return Just(false);
+ }
+ } else if (x->IsSymbol()) {
+ return Just(x.is_identical_to(y));
+ } else if (x->IsSimd128Value()) {
+ if (!y->IsSimd128Value()) return Just(false);
+ return Just(Simd128Value::Equals(Handle<Simd128Value>::cast(x),
+ Handle<Simd128Value>::cast(y)));
+ } else if (x->IsJSReceiver() && !x->IsUndetectableObject()) {
+ if (y->IsJSReceiver()) {
+ return Just(x.is_identical_to(y));
+ } else if (y->IsNull() || y->IsSimd128Value() || y->IsSymbol() ||
+ y->IsUndefined()) {
+ return Just(false);
+ } else if (y->IsBoolean()) {
+ y = Oddball::ToNumber(Handle<Oddball>::cast(y));
+ }
+ if (!JSReceiver::ToPrimitive(Handle<JSReceiver>::cast(x)).ToHandle(&x)) {
+ return Nothing<bool>();
+ }
+ } else {
+ return Just(
+ (x->IsNull() || x->IsUndefined() || x->IsUndetectableObject()) &&
+ (y->IsNull() || y->IsUndefined() || y->IsUndetectableObject()));
+ }
+ }
+}
+
+
bool Object::StrictEquals(Object* that) {
if (this->IsNumber()) {
if (!that->IsNumber()) return false;
- double const x = this->Number();
- double const y = that->Number();
- // Must check explicitly for NaN:s on Windows, but -0 works fine.
- return x == y && !std::isnan(x) && !std::isnan(y);
+ return NumberEquals(this, that);
} else if (this->IsString()) {
if (!that->IsString()) return false;
return String::cast(this)->Equals(String::cast(that));
@@ -120,14 +374,217 @@ bool Object::StrictEquals(Object* that) {
}
-bool Object::IsCallable() const {
- const Object* fun = this;
- while (fun->IsJSFunctionProxy()) {
- fun = JSFunctionProxy::cast(fun)->call_trap();
+// static
+Handle<String> Object::TypeOf(Isolate* isolate, Handle<Object> object) {
+ if (object->IsNumber()) return isolate->factory()->number_string();
+ if (object->IsUndefined() || object->IsUndetectableObject()) {
+ return isolate->factory()->undefined_string();
+ }
+ if (object->IsBoolean()) return isolate->factory()->boolean_string();
+ if (object->IsSymbol()) return isolate->factory()->symbol_string();
+#define SIMD128_TYPE(TYPE, Type, type, lane_count, lane_type) \
+ if (object->Is##Type()) return isolate->factory()->type##_string();
+ SIMD128_TYPES(SIMD128_TYPE)
+#undef SIMD128_TYPE
+ if (object->IsCallable()) return isolate->factory()->function_string();
+ return isolate->factory()->object_string();
+}
+
+
+// static
+MaybeHandle<Object> Object::Multiply(Isolate* isolate, Handle<Object> lhs,
+ Handle<Object> rhs, Strength strength) {
+ if (!lhs->IsNumber() || !rhs->IsNumber()) {
+ if (is_strong(strength)) {
+ THROW_NEW_ERROR(isolate,
+ NewTypeError(MessageTemplate::kStrongImplicitConversion),
+ Object);
+ }
+ ASSIGN_RETURN_ON_EXCEPTION(isolate, lhs, Object::ToNumber(lhs), Object);
+ ASSIGN_RETURN_ON_EXCEPTION(isolate, rhs, Object::ToNumber(rhs), Object);
+ }
+ return isolate->factory()->NewNumber(lhs->Number() * rhs->Number());
+}
+
+
+// static
+MaybeHandle<Object> Object::Divide(Isolate* isolate, Handle<Object> lhs,
+ Handle<Object> rhs, Strength strength) {
+ if (!lhs->IsNumber() || !rhs->IsNumber()) {
+ if (is_strong(strength)) {
+ THROW_NEW_ERROR(isolate,
+ NewTypeError(MessageTemplate::kStrongImplicitConversion),
+ Object);
+ }
+ ASSIGN_RETURN_ON_EXCEPTION(isolate, lhs, Object::ToNumber(lhs), Object);
+ ASSIGN_RETURN_ON_EXCEPTION(isolate, rhs, Object::ToNumber(rhs), Object);
+ }
+ return isolate->factory()->NewNumber(lhs->Number() / rhs->Number());
+}
+
+
+// static
+MaybeHandle<Object> Object::Modulus(Isolate* isolate, Handle<Object> lhs,
+ Handle<Object> rhs, Strength strength) {
+ if (!lhs->IsNumber() || !rhs->IsNumber()) {
+ if (is_strong(strength)) {
+ THROW_NEW_ERROR(isolate,
+ NewTypeError(MessageTemplate::kStrongImplicitConversion),
+ Object);
+ }
+ ASSIGN_RETURN_ON_EXCEPTION(isolate, lhs, Object::ToNumber(lhs), Object);
+ ASSIGN_RETURN_ON_EXCEPTION(isolate, rhs, Object::ToNumber(rhs), Object);
+ }
+ return isolate->factory()->NewNumber(modulo(lhs->Number(), rhs->Number()));
+}
+
+
+// static
+MaybeHandle<Object> Object::Add(Isolate* isolate, Handle<Object> lhs,
+ Handle<Object> rhs, Strength strength) {
+ if (lhs->IsNumber() && rhs->IsNumber()) {
+ return isolate->factory()->NewNumber(lhs->Number() + rhs->Number());
+ } else if (lhs->IsString() && rhs->IsString()) {
+ return isolate->factory()->NewConsString(Handle<String>::cast(lhs),
+ Handle<String>::cast(rhs));
+ } else if (is_strong(strength)) {
+ THROW_NEW_ERROR(isolate,
+ NewTypeError(MessageTemplate::kStrongImplicitConversion),
+ Object);
+ }
+ ASSIGN_RETURN_ON_EXCEPTION(isolate, lhs, Object::ToPrimitive(lhs), Object);
+ ASSIGN_RETURN_ON_EXCEPTION(isolate, rhs, Object::ToPrimitive(rhs), Object);
+ if (lhs->IsString() || rhs->IsString()) {
+ ASSIGN_RETURN_ON_EXCEPTION(isolate, rhs, Object::ToString(isolate, rhs),
+ Object);
+ ASSIGN_RETURN_ON_EXCEPTION(isolate, lhs, Object::ToString(isolate, lhs),
+ Object);
+ return isolate->factory()->NewConsString(Handle<String>::cast(lhs),
+ Handle<String>::cast(rhs));
+ }
+ ASSIGN_RETURN_ON_EXCEPTION(isolate, rhs, Object::ToNumber(rhs), Object);
+ ASSIGN_RETURN_ON_EXCEPTION(isolate, lhs, Object::ToNumber(lhs), Object);
+ return isolate->factory()->NewNumber(lhs->Number() + rhs->Number());
+}
+
+
+// static
+MaybeHandle<Object> Object::Subtract(Isolate* isolate, Handle<Object> lhs,
+ Handle<Object> rhs, Strength strength) {
+ if (!lhs->IsNumber() || !rhs->IsNumber()) {
+ if (is_strong(strength)) {
+ THROW_NEW_ERROR(isolate,
+ NewTypeError(MessageTemplate::kStrongImplicitConversion),
+ Object);
+ }
+ ASSIGN_RETURN_ON_EXCEPTION(isolate, lhs, Object::ToNumber(lhs), Object);
+ ASSIGN_RETURN_ON_EXCEPTION(isolate, rhs, Object::ToNumber(rhs), Object);
+ }
+ return isolate->factory()->NewNumber(lhs->Number() - rhs->Number());
+}
+
+
+// static
+MaybeHandle<Object> Object::ShiftLeft(Isolate* isolate, Handle<Object> lhs,
+ Handle<Object> rhs, Strength strength) {
+ if (!lhs->IsNumber() || !rhs->IsNumber()) {
+ if (is_strong(strength)) {
+ THROW_NEW_ERROR(isolate,
+ NewTypeError(MessageTemplate::kStrongImplicitConversion),
+ Object);
+ }
+ ASSIGN_RETURN_ON_EXCEPTION(isolate, lhs, Object::ToNumber(lhs), Object);
+ ASSIGN_RETURN_ON_EXCEPTION(isolate, rhs, Object::ToNumber(rhs), Object);
+ }
+ return isolate->factory()->NewNumberFromInt(NumberToInt32(*lhs)
+ << (NumberToUint32(*rhs) & 0x1F));
+}
+
+
+// static
+MaybeHandle<Object> Object::ShiftRight(Isolate* isolate, Handle<Object> lhs,
+ Handle<Object> rhs, Strength strength) {
+ if (!lhs->IsNumber() || !rhs->IsNumber()) {
+ if (is_strong(strength)) {
+ THROW_NEW_ERROR(isolate,
+ NewTypeError(MessageTemplate::kStrongImplicitConversion),
+ Object);
+ }
+ ASSIGN_RETURN_ON_EXCEPTION(isolate, lhs, Object::ToNumber(lhs), Object);
+ ASSIGN_RETURN_ON_EXCEPTION(isolate, rhs, Object::ToNumber(rhs), Object);
+ }
+ return isolate->factory()->NewNumberFromInt(NumberToInt32(*lhs) >>
+ (NumberToUint32(*rhs) & 0x1F));
+}
+
+
+// static
+MaybeHandle<Object> Object::ShiftRightLogical(Isolate* isolate,
+ Handle<Object> lhs,
+ Handle<Object> rhs,
+ Strength strength) {
+ if (!lhs->IsNumber() || !rhs->IsNumber()) {
+ if (is_strong(strength)) {
+ THROW_NEW_ERROR(isolate,
+ NewTypeError(MessageTemplate::kStrongImplicitConversion),
+ Object);
+ }
+ ASSIGN_RETURN_ON_EXCEPTION(isolate, lhs, Object::ToNumber(lhs), Object);
+ ASSIGN_RETURN_ON_EXCEPTION(isolate, rhs, Object::ToNumber(rhs), Object);
+ }
+ return isolate->factory()->NewNumberFromUint(NumberToUint32(*lhs) >>
+ (NumberToUint32(*rhs) & 0x1F));
+}
+
+
+// static
+MaybeHandle<Object> Object::BitwiseAnd(Isolate* isolate, Handle<Object> lhs,
+ Handle<Object> rhs, Strength strength) {
+ if (!lhs->IsNumber() || !rhs->IsNumber()) {
+ if (is_strong(strength)) {
+ THROW_NEW_ERROR(isolate,
+ NewTypeError(MessageTemplate::kStrongImplicitConversion),
+ Object);
+ }
+ ASSIGN_RETURN_ON_EXCEPTION(isolate, lhs, Object::ToNumber(lhs), Object);
+ ASSIGN_RETURN_ON_EXCEPTION(isolate, rhs, Object::ToNumber(rhs), Object);
}
- return fun->IsJSFunction() ||
- (fun->IsHeapObject() &&
- HeapObject::cast(fun)->map()->has_instance_call_handler());
+ return isolate->factory()->NewNumberFromInt(NumberToInt32(*lhs) &
+ NumberToInt32(*rhs));
+}
+
+
+// static
+MaybeHandle<Object> Object::BitwiseOr(Isolate* isolate, Handle<Object> lhs,
+ Handle<Object> rhs, Strength strength) {
+ if (!lhs->IsNumber() || !rhs->IsNumber()) {
+ if (is_strong(strength)) {
+ THROW_NEW_ERROR(isolate,
+ NewTypeError(MessageTemplate::kStrongImplicitConversion),
+ Object);
+ }
+ ASSIGN_RETURN_ON_EXCEPTION(isolate, lhs, Object::ToNumber(lhs), Object);
+ ASSIGN_RETURN_ON_EXCEPTION(isolate, rhs, Object::ToNumber(rhs), Object);
+ }
+ return isolate->factory()->NewNumberFromInt(NumberToInt32(*lhs) |
+ NumberToInt32(*rhs));
+}
+
+
+// static
+MaybeHandle<Object> Object::BitwiseXor(Isolate* isolate, Handle<Object> lhs,
+ Handle<Object> rhs, Strength strength) {
+ if (!lhs->IsNumber() || !rhs->IsNumber()) {
+ if (is_strong(strength)) {
+ THROW_NEW_ERROR(isolate,
+ NewTypeError(MessageTemplate::kStrongImplicitConversion),
+ Object);
+ }
+ ASSIGN_RETURN_ON_EXCEPTION(isolate, lhs, Object::ToNumber(lhs), Object);
+ ASSIGN_RETURN_ON_EXCEPTION(isolate, rhs, Object::ToNumber(rhs), Object);
+ }
+ return isolate->factory()->NewNumberFromInt(NumberToInt32(*lhs) ^
+ NumberToInt32(*rhs));
}
@@ -139,12 +596,32 @@ bool Object::IsPromise(Handle<Object> object) {
auto isolate = js_object->GetIsolate();
// TODO(dcarney): this should just be read from the symbol registry so as not
// to be context dependent.
- auto key = isolate->promise_status();
+ auto key = isolate->factory()->promise_status_symbol();
// Shouldn't be possible to throw here.
return JSObject::HasRealNamedProperty(js_object, key).FromJust();
}
+// static
+MaybeHandle<Object> Object::GetMethod(Handle<JSReceiver> receiver,
+ Handle<Name> name) {
+ Handle<Object> func;
+ Isolate* isolate = receiver->GetIsolate();
+ ASSIGN_RETURN_ON_EXCEPTION(isolate, func,
+ JSReceiver::GetProperty(receiver, name), Object);
+ if (func->IsNull() || func->IsUndefined()) {
+ return isolate->factory()->undefined_value();
+ }
+ if (!func->IsCallable()) {
+ // TODO(bmeurer): Better error message here?
+ THROW_NEW_ERROR(isolate,
+ NewTypeError(MessageTemplate::kCalledNonCallable, func),
+ Object);
+ }
+ return func;
+}
+
+
MaybeHandle<Object> Object::GetProperty(LookupIterator* it,
LanguageMode language_mode) {
for (; it->IsFound(); it->Next()) {
@@ -365,7 +842,7 @@ MaybeHandle<Object> Object::GetPropertyWithAccessor(
// Regular accessor.
Handle<Object> getter(AccessorPair::cast(*structure)->getter(), isolate);
- if (getter->IsSpecFunction()) {
+ if (getter->IsCallable()) {
// TODO(rossberg): nicer would be to cast to some JSCallable here...
return Object::GetPropertyWithDefinedGetter(
receiver, Handle<JSReceiver>::cast(getter));
@@ -421,7 +898,7 @@ MaybeHandle<Object> Object::SetPropertyWithAccessor(
// Regular accessor.
Handle<Object> setter(AccessorPair::cast(*structure)->setter(), isolate);
- if (setter->IsSpecFunction()) {
+ if (setter->IsCallable()) {
// TODO(rossberg): nicer would be to cast to some JSCallable here...
return SetPropertyWithDefinedSetter(
receiver, Handle<JSReceiver>::cast(setter), value);
@@ -460,7 +937,7 @@ MaybeHandle<Object> Object::GetPropertyWithDefinedGetter(
// TODO(rossberg): should this apply to getters that are function proxies?
if (debug->is_active()) debug->HandleStepIn(getter, false);
- return Execution::Call(isolate, getter, receiver, 0, NULL, true);
+ return Execution::Call(isolate, getter, receiver, 0, NULL);
}
@@ -477,7 +954,7 @@ MaybeHandle<Object> Object::SetPropertyWithDefinedSetter(
Handle<Object> argv[] = { value };
RETURN_ON_EXCEPTION(isolate, Execution::Call(isolate, setter, receiver,
- arraysize(argv), argv, true),
+ arraysize(argv), argv),
Object);
return value;
}
@@ -1473,6 +1950,73 @@ void HeapNumber::HeapNumberPrint(std::ostream& os) { // NOLINT
(*reinterpret_cast<const byte*>(FIELD_ADDR_CONST(p, offset)))
+// static
+Handle<String> Simd128Value::ToString(Handle<Simd128Value> input) {
+#define SIMD128_TYPE(TYPE, Type, type, lane_count, lane_type) \
+ if (input->Is##Type()) return Type::ToString(Handle<Type>::cast(input));
+ SIMD128_TYPES(SIMD128_TYPE)
+#undef SIMD128_TYPE
+ UNREACHABLE();
+ return Handle<String>::null();
+}
+
+
+// static
+Handle<String> Float32x4::ToString(Handle<Float32x4> input) {
+ Isolate* const isolate = input->GetIsolate();
+ char arr[100];
+ Vector<char> buffer(arr, arraysize(arr));
+ std::ostringstream os;
+ os << "SIMD.Float32x4("
+ << std::string(DoubleToCString(input->get_lane(0), buffer)) << ", "
+ << std::string(DoubleToCString(input->get_lane(1), buffer)) << ", "
+ << std::string(DoubleToCString(input->get_lane(2), buffer)) << ", "
+ << std::string(DoubleToCString(input->get_lane(3), buffer)) << ")";
+ return isolate->factory()->NewStringFromAsciiChecked(os.str().c_str());
+}
+
+
+#define SIMD128_BOOL_TO_STRING(Type, lane_count) \
+ Handle<String> Type::ToString(Handle<Type> input) { \
+ Isolate* const isolate = input->GetIsolate(); \
+ std::ostringstream os; \
+ os << "SIMD." #Type "("; \
+ os << (input->get_lane(0) ? "true" : "false"); \
+ for (int i = 1; i < lane_count; i++) { \
+ os << ", " << (input->get_lane(i) ? "true" : "false"); \
+ } \
+ os << ")"; \
+ return isolate->factory()->NewStringFromAsciiChecked(os.str().c_str()); \
+ }
+SIMD128_BOOL_TO_STRING(Bool32x4, 4)
+SIMD128_BOOL_TO_STRING(Bool16x8, 8)
+SIMD128_BOOL_TO_STRING(Bool8x16, 16)
+#undef SIMD128_BOOL_TO_STRING
+
+
+#define SIMD128_INT_TO_STRING(Type, lane_count) \
+ Handle<String> Type::ToString(Handle<Type> input) { \
+ Isolate* const isolate = input->GetIsolate(); \
+ char arr[100]; \
+ Vector<char> buffer(arr, arraysize(arr)); \
+ std::ostringstream os; \
+ os << "SIMD." #Type "("; \
+ os << IntToCString(input->get_lane(0), buffer); \
+ for (int i = 1; i < lane_count; i++) { \
+ os << ", " << IntToCString(input->get_lane(i), buffer); \
+ } \
+ os << ")"; \
+ return isolate->factory()->NewStringFromAsciiChecked(os.str().c_str()); \
+ }
+SIMD128_INT_TO_STRING(Int32x4, 4)
+SIMD128_INT_TO_STRING(Uint32x4, 4)
+SIMD128_INT_TO_STRING(Int16x8, 8)
+SIMD128_INT_TO_STRING(Uint16x8, 8)
+SIMD128_INT_TO_STRING(Int8x16, 16)
+SIMD128_INT_TO_STRING(Uint8x16, 16)
+#undef SIMD128_INT_TO_STRING
+
+
bool Simd128Value::BitwiseEquals(const Simd128Value* other) const {
return READ_INT64_FIELD(this, kValueOffset) ==
READ_INT64_FIELD(other, kValueOffset) &&
@@ -1776,6 +2320,8 @@ void JSObject::MigrateToMap(Handle<JSObject> object, Handle<Map> new_map,
if (!new_map->is_dictionary_map()) {
MigrateFastToFast(object, new_map);
if (old_map->is_prototype_map()) {
+ DCHECK(!old_map->is_stable());
+ DCHECK(new_map->is_stable());
// Clear out the old descriptor array to avoid problems to sharing
// the descriptor array without using an explicit.
old_map->InitializeDescriptors(
@@ -3280,8 +3826,7 @@ MaybeHandle<Object> Object::SetDataProperty(LookupIterator* it,
if (it->IsElement() && receiver->HasFixedTypedArrayElements()) {
if (!value->IsNumber() && !value->IsUndefined()) {
ASSIGN_RETURN_ON_EXCEPTION(it->isolate(), to_assign,
- Execution::ToNumber(it->isolate(), value),
- Object);
+ Object::ToNumber(value), Object);
// ToNumber above might modify the receiver, causing the cached
// holder_map to mismatch the actual holder->map() after this point.
// Reload the map to be in consistent state. Other cached state cannot
@@ -3723,6 +4268,7 @@ Handle<Map> Map::TransitionElementsTo(Handle<Map> map,
Object* maybe_array_maps = map->is_strong()
? native_context->js_array_strong_maps()
: native_context->js_array_maps();
+ // Reuse map transitions for JSArrays.
if (maybe_array_maps->IsFixedArray()) {
DisallowHeapAllocation no_gc;
FixedArray* array_maps = FixedArray::cast(maybe_array_maps);
@@ -3736,6 +4282,14 @@ Handle<Map> Map::TransitionElementsTo(Handle<Map> map,
}
DCHECK(!map->IsUndefined());
+ // Check if we can go back in the elements kind transition chain.
+ if (IsHoleyElementsKind(from_kind) &&
+ to_kind == GetPackedElementsKind(from_kind) &&
+ map->GetBackPointer()->IsMap() &&
+ Map::cast(map->GetBackPointer())->elements_kind() == to_kind) {
+ return handle(Map::cast(map->GetBackPointer()));
+ }
+
bool allow_store_transition = IsTransitionElementsKind(from_kind);
// Only store fast element maps in ascending generality.
if (IsFastElementsKind(to_kind)) {
@@ -4064,9 +4618,8 @@ void JSObject::AllocateStorageForMap(Handle<JSObject> object, Handle<Map> map) {
ElementsKind obj_kind = object->map()->elements_kind();
ElementsKind map_kind = map->elements_kind();
if (map_kind != obj_kind) {
- ElementsKind to_kind = map_kind;
- if (IsMoreGeneralElementsKindTransition(map_kind, obj_kind) ||
- IsDictionaryElementsKind(obj_kind)) {
+ ElementsKind to_kind = GetMoreGeneralElementsKind(map_kind, obj_kind);
+ if (IsDictionaryElementsKind(obj_kind)) {
to_kind = obj_kind;
}
if (IsDictionaryElementsKind(to_kind)) {
@@ -4687,16 +5240,12 @@ void JSObject::MigrateSlowToFast(Handle<JSObject> object,
int index = Smi::cast(iteration_order->get(i))->value();
Object* k = dictionary->KeyAt(index);
DCHECK(dictionary->IsKey(k));
+ // Dictionary keys are internalized upon insertion.
+ // TODO(jkummerow): Turn this into a DCHECK if it's not hit in the wild.
+ CHECK(k->IsUniqueName());
+ Handle<Name> key(Name::cast(k), isolate);
Object* value = dictionary->ValueAt(index);
- Handle<Name> key;
- if (k->IsSymbol()) {
- key = handle(Symbol::cast(k));
- } else {
- // Ensure the key is a unique name before writing into the
- // instance descriptor.
- key = factory->InternalizeString(handle(String::cast(k)));
- }
PropertyDetails details = dictionary->DetailsAt(index);
int enumeration_index = details.dictionary_index();
@@ -4796,7 +5345,7 @@ void JSObject::RequireSlowElements(SeededNumberDictionary* dictionary) {
dictionary->set_requires_slow_elements();
// TODO(verwaest): Remove this hack.
if (map()->is_prototype_map()) {
- GetHeap()->ClearAllICsByKind(Code::KEYED_STORE_IC);
+ GetHeap()->ClearAllKeyedStoreICs();
}
}
@@ -4959,7 +5508,7 @@ Object* JSObject::GetHiddenProperty(Handle<Name> key) {
// If the proxy is detached, return undefined.
if (iter.IsAtEnd()) return GetHeap()->the_hole_value();
DCHECK(iter.GetCurrent()->IsJSGlobalObject());
- return JSObject::cast(iter.GetCurrent())->GetHiddenProperty(key);
+ return iter.GetCurrent<JSObject>()->GetHiddenProperty(key);
}
DCHECK(!IsJSGlobalProxy());
Object* inline_value = GetHiddenPropertiesHashTable();
@@ -4984,9 +5533,8 @@ Handle<Object> JSObject::SetHiddenProperty(Handle<JSObject> object,
// If the proxy is detached, return undefined.
if (iter.IsAtEnd()) return isolate->factory()->undefined_value();
DCHECK(PrototypeIterator::GetCurrent(iter)->IsJSGlobalObject());
- return SetHiddenProperty(
- Handle<JSObject>::cast(PrototypeIterator::GetCurrent(iter)), key,
- value);
+ return SetHiddenProperty(PrototypeIterator::GetCurrent<JSObject>(iter), key,
+ value);
}
DCHECK(!object->IsJSGlobalProxy());
@@ -5017,8 +5565,8 @@ void JSObject::DeleteHiddenProperty(Handle<JSObject> object, Handle<Name> key) {
PrototypeIterator iter(isolate, object);
if (iter.IsAtEnd()) return;
DCHECK(PrototypeIterator::GetCurrent(iter)->IsJSGlobalObject());
- return DeleteHiddenProperty(
- Handle<JSObject>::cast(PrototypeIterator::GetCurrent(iter)), key);
+ return DeleteHiddenProperty(PrototypeIterator::GetCurrent<JSObject>(iter),
+ key);
}
Object* inline_value = object->GetHiddenPropertiesHashTable();
@@ -5397,13 +5945,13 @@ bool JSObject::ReferencesObject(Object* obj) {
// Check the context extension (if any) if it can have references.
if (context->has_extension() && !context->IsCatchContext()) {
- // With harmony scoping, a JSFunction may have a global context.
+ // With harmony scoping, a JSFunction may have a script context.
// TODO(mvstanton): walk into the ScopeInfo.
if (context->IsScriptContext()) {
return false;
}
- return JSObject::cast(context->extension())->ReferencesObject(obj);
+ return context->extension_object()->ReferencesObject(obj);
}
}
@@ -5431,8 +5979,7 @@ MaybeHandle<Object> JSObject::PreventExtensions(Handle<JSObject> object) {
PrototypeIterator iter(isolate, object);
if (iter.IsAtEnd()) return object;
DCHECK(PrototypeIterator::GetCurrent(iter)->IsJSGlobalObject());
- return PreventExtensions(
- Handle<JSObject>::cast(PrototypeIterator::GetCurrent(iter)));
+ return PreventExtensions(PrototypeIterator::GetCurrent<JSObject>(iter));
}
// It's not possible to seal objects with external array elements
@@ -5474,7 +6021,7 @@ bool JSObject::IsExtensible() {
PrototypeIterator iter(GetIsolate(), this);
if (iter.IsAtEnd()) return false;
DCHECK(iter.GetCurrent()->IsJSGlobalObject());
- return JSObject::cast(iter.GetCurrent())->map()->is_extensible();
+ return iter.GetCurrent<JSObject>()->map()->is_extensible();
}
return map()->is_extensible();
}
@@ -5525,7 +6072,7 @@ MaybeHandle<Object> JSObject::PreventExtensionsWithTransition(
if (iter.IsAtEnd()) return object;
DCHECK(PrototypeIterator::GetCurrent(iter)->IsJSGlobalObject());
return PreventExtensionsWithTransition<attrs>(
- Handle<JSObject>::cast(PrototypeIterator::GetCurrent(iter)));
+ PrototypeIterator::GetCurrent<JSObject>(iter));
}
// It's not possible to seal or freeze objects with external array elements
@@ -5900,6 +6447,76 @@ MaybeHandle<JSObject> JSObject::DeepCopy(
}
+// static
+MaybeHandle<Object> JSReceiver::ToPrimitive(Handle<JSReceiver> receiver,
+ ToPrimitiveHint hint) {
+ Isolate* const isolate = receiver->GetIsolate();
+ Handle<Object> exotic_to_prim;
+ ASSIGN_RETURN_ON_EXCEPTION(
+ isolate, exotic_to_prim,
+ GetMethod(receiver, isolate->factory()->to_primitive_symbol()), Object);
+ if (!exotic_to_prim->IsUndefined()) {
+ Handle<Object> hint_string;
+ switch (hint) {
+ case ToPrimitiveHint::kDefault:
+ hint_string = isolate->factory()->default_string();
+ break;
+ case ToPrimitiveHint::kNumber:
+ hint_string = isolate->factory()->number_string();
+ break;
+ case ToPrimitiveHint::kString:
+ hint_string = isolate->factory()->string_string();
+ break;
+ }
+ Handle<Object> result;
+ ASSIGN_RETURN_ON_EXCEPTION(
+ isolate, result,
+ Execution::Call(isolate, exotic_to_prim, receiver, 1, &hint_string),
+ Object);
+ if (result->IsPrimitive()) return result;
+ THROW_NEW_ERROR(isolate,
+ NewTypeError(MessageTemplate::kCannotConvertToPrimitive),
+ Object);
+ }
+ return OrdinaryToPrimitive(receiver, (hint == ToPrimitiveHint::kString)
+ ? OrdinaryToPrimitiveHint::kString
+ : OrdinaryToPrimitiveHint::kNumber);
+}
+
+
+// static
+MaybeHandle<Object> JSReceiver::OrdinaryToPrimitive(
+ Handle<JSReceiver> receiver, OrdinaryToPrimitiveHint hint) {
+ Isolate* const isolate = receiver->GetIsolate();
+ Handle<String> method_names[2];
+ switch (hint) {
+ case OrdinaryToPrimitiveHint::kNumber:
+ method_names[0] = isolate->factory()->valueOf_string();
+ method_names[1] = isolate->factory()->toString_string();
+ break;
+ case OrdinaryToPrimitiveHint::kString:
+ method_names[0] = isolate->factory()->toString_string();
+ method_names[1] = isolate->factory()->valueOf_string();
+ break;
+ }
+ for (Handle<String> name : method_names) {
+ Handle<Object> method;
+ ASSIGN_RETURN_ON_EXCEPTION(isolate, method,
+ JSReceiver::GetProperty(receiver, name), Object);
+ if (method->IsCallable()) {
+ Handle<Object> result;
+ ASSIGN_RETURN_ON_EXCEPTION(
+ isolate, result, Execution::Call(isolate, method, receiver, 0, NULL),
+ Object);
+ if (result->IsPrimitive()) return result;
+ }
+ }
+ THROW_NEW_ERROR(isolate,
+ NewTypeError(MessageTemplate::kCannotConvertToPrimitive),
+ Object);
+}
+
+
// Tests for the fast common case for property enumeration:
// - This object and all prototypes has an enum cache (which means that
// it is no proxy, has no interceptors and needs no access checks).
@@ -5910,14 +6527,14 @@ bool JSReceiver::IsSimpleEnum() {
PrototypeIterator::START_AT_RECEIVER);
!iter.IsAtEnd(); iter.Advance()) {
if (!iter.GetCurrent()->IsJSObject()) return false;
- JSObject* curr = JSObject::cast(iter.GetCurrent());
- int enum_length = curr->map()->EnumLength();
+ JSObject* current = iter.GetCurrent<JSObject>();
+ int enum_length = current->map()->EnumLength();
if (enum_length == kInvalidEnumCacheSentinel) return false;
- if (curr->IsAccessCheckNeeded()) return false;
- DCHECK(!curr->HasNamedInterceptor());
- DCHECK(!curr->HasIndexedInterceptor());
- if (curr->NumberOfEnumElements() > 0) return false;
- if (curr != this && enum_length != 0) return false;
+ if (current->IsAccessCheckNeeded()) return false;
+ DCHECK(!current->HasNamedInterceptor());
+ DCHECK(!current->HasIndexedInterceptor());
+ if (current->NumberOfEnumElements() > 0) return false;
+ if (current != this && enum_length != 0) return false;
}
return true;
}
@@ -6102,11 +6719,123 @@ Handle<FixedArray> JSObject::GetEnumPropertyKeys(Handle<JSObject> object,
}
+Handle<FixedArray> KeyAccumulator::GetKeys() {
+ if (length_ == 0) {
+ return isolate_->factory()->empty_fixed_array();
+ }
+ if (set_.is_null()) {
+ keys_->Shrink(length_);
+ return keys_;
+ }
+ // copy over results from set_
+ Handle<FixedArray> result = isolate_->factory()->NewFixedArray(length_);
+ for (int i = 0; i < length_; i++) {
+ result->set(i, set_->KeyAt(i));
+ }
+ return result;
+}
+
+
+void KeyAccumulator::AddKey(Handle<Object> key, int check_limit) {
+#ifdef ENABLE_SLOW_DCHECKS
+ if (FLAG_enable_slow_asserts) {
+ DCHECK(key->IsNumber() || key->IsName());
+ }
+#endif
+ if (!set_.is_null()) {
+ set_ = OrderedHashSet::Add(set_, key);
+ length_ = set_->NumberOfElements();
+ return;
+ }
+ // check if we already have the key in the case we are still using
+ // the keys_ FixedArray
+ check_limit = Min(check_limit, length_);
+ for (int i = 0; i < check_limit; i++) {
+ Object* current = keys_->get(i);
+ if (current->KeyEquals(*key)) return;
+ }
+ EnsureCapacity(length_);
+ keys_->set(length_, *key);
+ length_++;
+}
+
+
+void KeyAccumulator::AddKeys(Handle<FixedArray> array,
+ FixedArray::KeyFilter filter) {
+ int add_length = array->length();
+ if (add_length == 0) return;
+ if (keys_.is_null() && filter == FixedArray::ALL_KEYS) {
+ keys_ = array;
+ length_ = keys_->length();
+ return;
+ }
+ PrepareForComparisons(add_length);
+ int previous_key_count = length_;
+ for (int i = 0; i < add_length; i++) {
+ Handle<Object> current(array->get(i), isolate_);
+ if (filter == FixedArray::NON_SYMBOL_KEYS && current->IsSymbol()) continue;
+ AddKey(current, previous_key_count);
+ }
+}
+
+
+void KeyAccumulator::AddKeys(Handle<JSObject> array_like,
+ FixedArray::KeyFilter filter) {
+ DCHECK(array_like->IsJSArray() || array_like->HasSloppyArgumentsElements());
+ ElementsAccessor* accessor = array_like->GetElementsAccessor();
+ accessor->AddElementsToKeyAccumulator(array_like, this, filter);
+}
+
+
+void KeyAccumulator::PrepareForComparisons(int count) {
+ // Depending on how many comparisons we do we should switch to the
+ // hash-table-based checks which have a one-time overhead for
+ // initializing but O(1) for HasKey checks.
+ if (!set_.is_null()) return;
+ // This limit was obtained through evaluation of a microbench.
+ if (length_ * count < 50) return;
+ set_ = OrderedHashSet::Allocate(isolate_, length_);
+ for (int i = 0; i < length_; i++) {
+ Handle<Object> value(keys_->get(i), isolate_);
+ set_ = OrderedHashSet::Add(set_, value);
+ }
+}
+
+
+void KeyAccumulator::EnsureCapacity(int capacity) {
+ if (keys_.is_null() || keys_->length() <= capacity) {
+ Grow();
+ }
+}
+
+
+void KeyAccumulator::Grow() {
+ // The OrderedHashSet handles growing by itself.
+ if (!set_.is_null()) return;
+ // Otherwise, grow the internal keys_ FixedArray
+ int capacity = keys_.is_null() ? 16 : keys_->length() * 2 + 16;
+ Handle<FixedArray> new_keys = isolate_->factory()->NewFixedArray(capacity);
+ if (keys_.is_null()) {
+ keys_ = new_keys;
+ return;
+ }
+ int buffer_length = keys_->length();
+ {
+ DisallowHeapAllocation no_gc;
+ WriteBarrierMode mode = new_keys->GetWriteBarrierMode(no_gc);
+ for (int i = 0; i < buffer_length; i++) {
+ new_keys->set(i, keys_->get(i), mode);
+ }
+ }
+ keys_ = new_keys;
+}
+
+
MaybeHandle<FixedArray> JSReceiver::GetKeys(Handle<JSReceiver> object,
KeyCollectionType type) {
USE(ContainsOnlyValidKeys);
Isolate* isolate = object->GetIsolate();
- Handle<FixedArray> content = isolate->factory()->empty_fixed_array();
+ KeyAccumulator accumulator(isolate);
Handle<JSFunction> arguments_function(
JSFunction::cast(isolate->sloppy_arguments_map()->GetConstructor()));
@@ -6118,8 +6847,7 @@ MaybeHandle<FixedArray> JSReceiver::GetKeys(Handle<JSReceiver> object,
PrototypeIterator::START_AT_RECEIVER);
!iter.IsAtEnd(end); iter.Advance()) {
if (PrototypeIterator::GetCurrent(iter)->IsJSProxy()) {
- Handle<JSProxy> proxy(JSProxy::cast(*PrototypeIterator::GetCurrent(iter)),
- isolate);
+ Handle<JSProxy> proxy = PrototypeIterator::GetCurrent<JSProxy>(iter);
Handle<Object> args[] = { proxy };
Handle<Object> names;
ASSIGN_RETURN_ON_EXCEPTION(
@@ -6130,16 +6858,11 @@ MaybeHandle<FixedArray> JSReceiver::GetKeys(Handle<JSReceiver> object,
arraysize(args),
args),
FixedArray);
- ASSIGN_RETURN_ON_EXCEPTION(
- isolate, content,
- FixedArray::AddKeysFromArrayLike(
- content, Handle<JSObject>::cast(names)),
- FixedArray);
+ accumulator.AddKeys(Handle<JSObject>::cast(names), FixedArray::ALL_KEYS);
break;
}
- Handle<JSObject> current =
- Handle<JSObject>::cast(PrototypeIterator::GetCurrent(iter));
+ Handle<JSObject> current = PrototypeIterator::GetCurrent<JSObject>(iter);
// Check access rights if required.
if (current->IsAccessCheckNeeded() && !isolate->MayAccess(current)) {
@@ -6154,23 +6877,17 @@ MaybeHandle<FixedArray> JSReceiver::GetKeys(Handle<JSReceiver> object,
Handle<FixedArray> element_keys =
isolate->factory()->NewFixedArray(current->NumberOfEnumElements());
current->GetEnumElementKeys(*element_keys);
- ASSIGN_RETURN_ON_EXCEPTION(
- isolate, content,
- FixedArray::UnionOfKeys(content, element_keys),
- FixedArray);
- DCHECK(ContainsOnlyValidKeys(content));
+ accumulator.AddKeys(element_keys, FixedArray::ALL_KEYS);
+ DCHECK(ContainsOnlyValidKeys(accumulator.GetKeys()));
// Add the element keys from the interceptor.
if (current->HasIndexedInterceptor()) {
Handle<JSObject> result;
if (JSObject::GetKeysForIndexedInterceptor(
current, object).ToHandle(&result)) {
- ASSIGN_RETURN_ON_EXCEPTION(
- isolate, content,
- FixedArray::AddKeysFromArrayLike(content, result),
- FixedArray);
+ accumulator.AddKeys(result, FixedArray::ALL_KEYS);
}
- DCHECK(ContainsOnlyValidKeys(content));
+ DCHECK(ContainsOnlyValidKeys(accumulator.GetKeys()));
}
// We can cache the computed property keys if access checks are
@@ -6188,27 +6905,26 @@ MaybeHandle<FixedArray> JSReceiver::GetKeys(Handle<JSReceiver> object,
!current->IsJSValue() && !current->IsAccessCheckNeeded() &&
!current->HasNamedInterceptor() && !current->HasIndexedInterceptor());
// Compute the property keys and cache them if possible.
- ASSIGN_RETURN_ON_EXCEPTION(
- isolate, content,
- FixedArray::UnionOfKeys(
- content, JSObject::GetEnumPropertyKeys(current, cache_enum_keys)),
- FixedArray);
- DCHECK(ContainsOnlyValidKeys(content));
+
+ Handle<FixedArray> enum_keys =
+ JSObject::GetEnumPropertyKeys(current, cache_enum_keys);
+ accumulator.AddKeys(enum_keys, FixedArray::ALL_KEYS);
+ DCHECK(ContainsOnlyValidKeys(accumulator.GetKeys()));
// Add the non-symbol property keys from the interceptor.
if (current->HasNamedInterceptor()) {
Handle<JSObject> result;
if (JSObject::GetKeysForNamedInterceptor(
current, object).ToHandle(&result)) {
- ASSIGN_RETURN_ON_EXCEPTION(
- isolate, content, FixedArray::AddKeysFromArrayLike(
- content, result, FixedArray::NON_SYMBOL_KEYS),
- FixedArray);
+ accumulator.AddKeys(result, FixedArray::NON_SYMBOL_KEYS);
}
- DCHECK(ContainsOnlyValidKeys(content));
+ DCHECK(ContainsOnlyValidKeys(accumulator.GetKeys()));
}
}
- return content;
+
+ Handle<FixedArray> keys = accumulator.GetKeys();
+ DCHECK(ContainsOnlyValidKeys(keys));
+ return keys;
}
@@ -6222,7 +6938,7 @@ bool Map::DictionaryElementsInPrototypeChainOnly() {
if (iter.GetCurrent()->IsJSProxy()) return true;
// String wrappers have non-configurable, non-writable elements.
if (iter.GetCurrent()->IsStringWrapper()) return true;
- JSObject* current = JSObject::cast(iter.GetCurrent());
+ JSObject* current = iter.GetCurrent<JSObject>();
if (current->HasDictionaryElements() &&
current->element_dictionary()->requires_slow_elements()) {
@@ -6279,8 +6995,8 @@ MaybeHandle<Object> JSObject::DefineAccessor(Handle<JSObject> object,
}
}
- DCHECK(getter->IsSpecFunction() || getter->IsUndefined() || getter->IsNull());
- DCHECK(setter->IsSpecFunction() || setter->IsUndefined() || setter->IsNull());
+ DCHECK(getter->IsCallable() || getter->IsUndefined() || getter->IsNull());
+ DCHECK(setter->IsCallable() || setter->IsUndefined() || setter->IsNull());
// At least one of the accessors needs to be a new value.
DCHECK(!getter->IsNull() || !setter->IsNull());
if (!getter->IsNull()) {
@@ -6727,7 +7443,7 @@ Handle<Map> Map::CopyInstallDescriptors(
#else
SLOW_DCHECK(result->layout_descriptor()->IsConsistentWithMap(*result));
#endif
- result->set_visitor_id(StaticVisitorBase::GetVisitorId(*result));
+ result->set_visitor_id(Heap::GetStaticVisitorIdForMap(*result));
}
Handle<Name> name = handle(descriptors->GetKey(new_descriptor));
@@ -6864,7 +7580,7 @@ Handle<Map> Map::Create(Isolate* isolate, int inobject_properties) {
copy->SetInObjectProperties(inobject_properties);
copy->set_unused_property_fields(inobject_properties);
copy->set_instance_size(new_instance_size);
- copy->set_visitor_id(StaticVisitorBase::GetVisitorId(*copy));
+ copy->set_visitor_id(Heap::GetStaticVisitorIdForMap(*copy));
return copy;
}
@@ -7709,53 +8425,6 @@ void FixedArray::Shrink(int new_length) {
}
-MaybeHandle<FixedArray> FixedArray::AddKeysFromArrayLike(
- Handle<FixedArray> content, Handle<JSObject> array, KeyFilter filter) {
- DCHECK(array->IsJSArray() || array->HasSloppyArgumentsElements());
- ElementsAccessor* accessor = array->GetElementsAccessor();
- Handle<FixedArray> result =
- accessor->AddElementsToFixedArray(array, content, filter);
-
-#ifdef ENABLE_SLOW_DCHECKS
- if (FLAG_enable_slow_asserts) {
- DisallowHeapAllocation no_allocation;
- for (int i = 0; i < result->length(); i++) {
- Object* current = result->get(i);
- DCHECK(current->IsNumber() || current->IsName());
- }
- }
-#endif
- return result;
-}
-
-
-MaybeHandle<FixedArray> FixedArray::UnionOfKeys(Handle<FixedArray> first,
- Handle<FixedArray> second) {
- if (second->length() == 0) return first;
- if (first->length() == 0) return second;
- Isolate* isolate = first->GetIsolate();
- Handle<FixedArray> result =
- isolate->factory()->NewFixedArray(first->length() + second->length());
- for (int i = 0; i < first->length(); i++) {
- result->set(i, first->get(i));
- }
- int pos = first->length();
- for (int j = 0; j < second->length(); j++) {
- Object* current = second->get(j);
- int i;
- for (i = 0; i < first->length(); i++) {
- if (current->KeyEquals(first->get(i))) break;
- }
- if (i == first->length()) {
- result->set(pos++, current);
- }
- }
-
- result->Shrink(pos);
- return result;
-}
-
-
void FixedArray::CopyTo(int pos, FixedArray* dest, int dest_pos, int len) {
DisallowHeapAllocation no_gc;
WriteBarrierMode mode = dest->GetWriteBarrierMode(no_gc);
@@ -7849,6 +8518,17 @@ void WeakFixedArray::Compact() {
}
+void WeakFixedArray::Iterator::Reset(Object* maybe_array) {
+ if (maybe_array->IsWeakFixedArray()) {
+ list_ = WeakFixedArray::cast(maybe_array);
+ index_ = 0;
+#ifdef DEBUG
+ last_used_index_ = list_->last_used_index();
+#endif // DEBUG
+ }
+}
+
+
void JSObject::PrototypeRegistryCompactionCallback::Callback(Object* value,
int old_index,
int new_index) {
@@ -8102,6 +8782,19 @@ Handle<DeoptimizationOutputData> DeoptimizationOutputData::New(
}
+// static
+Handle<LiteralsArray> LiteralsArray::New(Isolate* isolate,
+ Handle<TypeFeedbackVector> vector,
+ int number_of_literals,
+ PretenureFlag pretenure) {
+ Handle<FixedArray> literals = isolate->factory()->NewFixedArray(
+ number_of_literals + kFirstLiteralIndex, pretenure);
+ Handle<LiteralsArray> casted_literals = Handle<LiteralsArray>::cast(literals);
+ casted_literals->set_feedback_vector(*vector);
+ return casted_literals;
+}
+
+
int HandlerTable::LookupRange(int pc_offset, int* stack_depth_out,
CatchPrediction* prediction_out) {
int innermost_handler = -1, innermost_start = -1;
@@ -8160,6 +8853,110 @@ bool String::LooksValid() {
}
+// static
+MaybeHandle<String> Name::ToFunctionName(Handle<Name> name) {
+ if (name->IsString()) return Handle<String>::cast(name);
+ // ES6 section 9.2.11 SetFunctionName, step 4.
+ Isolate* const isolate = name->GetIsolate();
+ Handle<Object> description(Handle<Symbol>::cast(name)->name(), isolate);
+ if (description->IsUndefined()) return isolate->factory()->empty_string();
+ IncrementalStringBuilder builder(isolate);
+ builder.AppendCharacter('[');
+ builder.AppendString(Handle<String>::cast(description));
+ builder.AppendCharacter(']');
+ return builder.Finish();
+}
+
+
+namespace {
+
+bool AreDigits(const uint8_t* s, int from, int to) {
+ for (int i = from; i < to; i++) {
+ if (s[i] < '0' || s[i] > '9') return false;
+ }
+
+ return true;
+}
+
+
+int ParseDecimalInteger(const uint8_t* s, int from, int to) {
+ DCHECK(to - from < 10); // Overflow is not possible.
+ DCHECK(from < to);
+ int d = s[from] - '0';
+
+ for (int i = from + 1; i < to; i++) {
+ d = 10 * d + (s[i] - '0');
+ }
+
+ return d;
+}
+
+} // namespace
+
+
+// static
+Handle<Object> String::ToNumber(Handle<String> subject) {
+ Isolate* const isolate = subject->GetIsolate();
+
+ // Flatten {subject} string first.
+ subject = String::Flatten(subject);
+
+ // Fast array index case.
+ uint32_t index;
+ if (subject->AsArrayIndex(&index)) {
+ return isolate->factory()->NewNumberFromUint(index);
+ }
+
+ // Fast case: short integer or some sorts of junk values.
+ if (subject->IsSeqOneByteString()) {
+ int len = subject->length();
+ if (len == 0) return handle(Smi::FromInt(0), isolate);
+
+ DisallowHeapAllocation no_gc;
+ uint8_t const* data = Handle<SeqOneByteString>::cast(subject)->GetChars();
+ bool minus = (data[0] == '-');
+ int start_pos = (minus ? 1 : 0);
+
+ if (start_pos == len) {
+ return isolate->factory()->nan_value();
+ } else if (data[start_pos] > '9') {
+ // Fast check for a junk value. A valid string may start from a
+ // whitespace, a sign ('+' or '-'), the decimal point, a decimal digit
+ // or the 'I' character ('Infinity'). All of that have codes not greater
+ // than '9' except 'I' and &nbsp;.
+ if (data[start_pos] != 'I' && data[start_pos] != 0xa0) {
+ return isolate->factory()->nan_value();
+ }
+ } else if (len - start_pos < 10 && AreDigits(data, start_pos, len)) {
+ // The maximal/minimal smi has 10 digits. If the string has less digits
+ // we know it will fit into the smi-data type.
+ int d = ParseDecimalInteger(data, start_pos, len);
+ if (minus) {
+ if (d == 0) return isolate->factory()->minus_zero_value();
+ d = -d;
+ } else if (!subject->HasHashCode() && len <= String::kMaxArrayIndexSize &&
+ (len == 1 || data[0] != '0')) {
+ // String hash is not calculated yet but all the data are present.
+ // Update the hash field to speed up sequential convertions.
+ uint32_t hash = StringHasher::MakeArrayIndexHash(d, len);
+#ifdef DEBUG
+ subject->Hash(); // Force hash calculation.
+ DCHECK_EQ(static_cast<int>(subject->hash_field()),
+ static_cast<int>(hash));
+#endif
+ subject->set_hash_field(hash);
+ }
+ return handle(Smi::FromInt(d), isolate);
+ }
+ }
+
+ // Slower case.
+ int flags = ALLOW_HEX | ALLOW_OCTAL | ALLOW_BINARY;
+ return isolate->factory()->NewNumber(
+ StringToDouble(isolate->unicode_cache(), subject, flags));
+}
+
+
String::FlatContent String::GetFlatContent() {
DCHECK(!AllowHeapAllocation::IsAllowed());
int length = this->length();
@@ -8948,6 +9745,69 @@ bool String::SlowEquals(Handle<String> one, Handle<String> two) {
}
+// static
+ComparisonResult String::Compare(Handle<String> x, Handle<String> y) {
+ // A few fast case tests before we flatten.
+ if (x.is_identical_to(y)) {
+ return ComparisonResult::kEqual;
+ } else if (y->length() == 0) {
+ return x->length() == 0 ? ComparisonResult::kEqual
+ : ComparisonResult::kGreaterThan;
+ } else if (x->length() == 0) {
+ return ComparisonResult::kLessThan;
+ }
+
+ int const d = x->Get(0) - y->Get(0);
+ if (d < 0) {
+ return ComparisonResult::kLessThan;
+ } else if (d > 0) {
+ return ComparisonResult::kGreaterThan;
+ }
+
+ // Slow case.
+ x = String::Flatten(x);
+ y = String::Flatten(y);
+
+ DisallowHeapAllocation no_gc;
+ ComparisonResult result = ComparisonResult::kEqual;
+ int prefix_length = x->length();
+ if (y->length() < prefix_length) {
+ prefix_length = y->length();
+ result = ComparisonResult::kGreaterThan;
+ } else if (y->length() > prefix_length) {
+ result = ComparisonResult::kLessThan;
+ }
+ int r;
+ String::FlatContent x_content = x->GetFlatContent();
+ String::FlatContent y_content = y->GetFlatContent();
+ if (x_content.IsOneByte()) {
+ Vector<const uint8_t> x_chars = x_content.ToOneByteVector();
+ if (y_content.IsOneByte()) {
+ Vector<const uint8_t> y_chars = y_content.ToOneByteVector();
+ r = CompareChars(x_chars.start(), y_chars.start(), prefix_length);
+ } else {
+ Vector<const uc16> y_chars = y_content.ToUC16Vector();
+ r = CompareChars(x_chars.start(), y_chars.start(), prefix_length);
+ }
+ } else {
+ Vector<const uc16> x_chars = x_content.ToUC16Vector();
+ if (y_content.IsOneByte()) {
+ Vector<const uint8_t> y_chars = y_content.ToOneByteVector();
+ r = CompareChars(x_chars.start(), y_chars.start(), prefix_length);
+ } else {
+ Vector<const uc16> y_chars = y_content.ToUC16Vector();
+ r = CompareChars(x_chars.start(), y_chars.start(), prefix_length);
+ }
+ }
+ if (r < 0) {
+ result = ComparisonResult::kLessThan;
+ } else if (r > 0) {
+ result = ComparisonResult::kGreaterThan;
+ }
+ return result;
+}
+
+
bool String::IsUtf8EqualTo(Vector<const char> str, bool allow_prefix_match) {
int slen = length();
// Can't check exact length equality, but we can check bounds.
@@ -9068,16 +9928,9 @@ Handle<String> SeqString::Truncate(Handle<SeqString> string, int new_length) {
DCHECK_OBJECT_ALIGNED(start_of_string + new_size);
Heap* heap = string->GetHeap();
- NewSpace* newspace = heap->new_space();
- if (newspace->Contains(start_of_string) &&
- newspace->top() == start_of_string + old_size) {
- // Last allocated object in new space. Simply lower allocation top.
- newspace->set_top(start_of_string + new_size);
- } else {
- // Sizes are pointer size aligned, so that we can use filler objects
- // that are a multiple of pointer size.
- heap->CreateFillerObjectAt(start_of_string + new_size, delta);
- }
+ // Sizes are pointer size aligned, so that we can use filler objects
+ // that are a multiple of pointer size.
+ heap->CreateFillerObjectAt(start_of_string + new_size, delta);
heap->AdjustLiveBytes(*string, -delta, Heap::CONCURRENT_TO_SWEEPER);
// We are storing the new length using release store after creating a filler
@@ -9230,17 +10083,20 @@ int Map::Hash() {
}
-static bool CheckEquivalent(Map* first, Map* second) {
+namespace {
+
+bool CheckEquivalent(Map* first, Map* second) {
return first->GetConstructor() == second->GetConstructor() &&
first->prototype() == second->prototype() &&
first->instance_type() == second->instance_type() &&
first->bit_field() == second->bit_field() &&
first->is_extensible() == second->is_extensible() &&
first->is_strong() == second->is_strong() &&
- first->has_instance_call_handler() ==
- second->has_instance_call_handler();
+ first->is_hidden_prototype() == second->is_hidden_prototype();
}
+} // namespace
+
bool Map::EquivalentToForTransition(Map* other) {
return CheckEquivalent(this, other);
@@ -9328,30 +10184,6 @@ void JSFunction::AttemptConcurrentOptimization() {
}
-Handle<JSFunction> JSFunction::CloneClosure(Handle<JSFunction> function) {
- Isolate* isolate = function->GetIsolate();
- Handle<Map> map(function->map());
- Handle<SharedFunctionInfo> shared(function->shared());
- Handle<Context> context(function->context());
- Handle<JSFunction> clone =
- isolate->factory()->NewFunctionFromSharedFunctionInfo(shared, context);
-
- if (shared->bound()) {
- clone->set_function_bindings(function->function_bindings());
- }
-
- // In typical case, __proto__ of ``function`` is the default Function
- // prototype, which means that SetPrototype below is a no-op.
- // In rare cases when that is not true, we mutate the clone's __proto__.
- Handle<Object> original_prototype(map->prototype(), isolate);
- if (*original_prototype != clone->map()->prototype()) {
- JSObject::SetPrototype(clone, original_prototype, false).Assert();
- }
-
- return clone;
-}
-
-
void SharedFunctionInfo::AddSharedCodeToOptimizedCodeMap(
Handle<SharedFunctionInfo> shared, Handle<Code> code) {
Isolate* isolate = shared->GetIsolate();
@@ -9364,47 +10196,60 @@ void SharedFunctionInfo::AddSharedCodeToOptimizedCodeMap(
void SharedFunctionInfo::AddToOptimizedCodeMap(
- Handle<SharedFunctionInfo> shared,
- Handle<Context> native_context,
- Handle<Code> code,
- Handle<FixedArray> literals,
+ Handle<SharedFunctionInfo> shared, Handle<Context> native_context,
+ Handle<HeapObject> code, Handle<LiteralsArray> literals,
BailoutId osr_ast_id) {
Isolate* isolate = shared->GetIsolate();
- DCHECK(!shared->SearchOptimizedCodeMap(*native_context, osr_ast_id).code);
- DCHECK(code->kind() == Code::OPTIMIZED_FUNCTION);
+ DCHECK(*code == isolate->heap()->undefined_value() ||
+ !shared->SearchOptimizedCodeMap(*native_context, osr_ast_id).code);
+ DCHECK(*code == isolate->heap()->undefined_value() ||
+ Code::cast(*code)->kind() == Code::OPTIMIZED_FUNCTION);
DCHECK(native_context->IsNativeContext());
STATIC_ASSERT(kEntryLength == 4);
Handle<FixedArray> new_code_map;
Handle<Object> value(shared->optimized_code_map(), isolate);
- int old_length;
+ int entry;
if (value->IsSmi()) {
// No optimized code map.
DCHECK_EQ(0, Smi::cast(*value)->value());
new_code_map = isolate->factory()->NewFixedArray(kInitialLength, TENURED);
- old_length = kEntriesStart;
+ entry = kEntriesStart;
} else {
- // Copy old optimized code map and append one new entry.
Handle<FixedArray> old_code_map = Handle<FixedArray>::cast(value);
+ entry = shared->SearchOptimizedCodeMapEntry(*native_context, osr_ast_id);
+ if (entry > kSharedCodeIndex) {
+ // Found an existing context-specific entry, it must not contain any code.
+ DCHECK_EQ(isolate->heap()->undefined_value(),
+ old_code_map->get(entry + kCachedCodeOffset));
+ // Just set the code and literals to the entry.
+ old_code_map->set(entry + kCachedCodeOffset, *code);
+ old_code_map->set(entry + kLiteralsOffset, *literals);
+ return;
+ }
+
+ // Copy old optimized code map and append one new entry.
new_code_map = isolate->factory()->CopyFixedArrayAndGrow(
old_code_map, kEntryLength, TENURED);
- old_length = old_code_map->length();
+ int old_length = old_code_map->length();
// Zap the old map to avoid any stale entries. Note that this is required
// for correctness because entries are being treated weakly by the GC.
MemsetPointer(old_code_map->data_start(), isolate->heap()->the_hole_value(),
old_length);
+ entry = old_length;
}
- new_code_map->set(old_length + kContextOffset, *native_context);
- new_code_map->set(old_length + kCachedCodeOffset, *code);
- new_code_map->set(old_length + kLiteralsOffset, *literals);
- new_code_map->set(old_length + kOsrAstIdOffset,
- Smi::FromInt(osr_ast_id.ToInt()));
+ new_code_map->set(entry + kContextOffset, *native_context);
+ new_code_map->set(entry + kCachedCodeOffset, *code);
+ new_code_map->set(entry + kLiteralsOffset, *literals);
+ new_code_map->set(entry + kOsrAstIdOffset, Smi::FromInt(osr_ast_id.ToInt()));
#ifdef DEBUG
for (int i = kEntriesStart; i < new_code_map->length(); i += kEntryLength) {
DCHECK(new_code_map->get(i + kContextOffset)->IsNativeContext());
- DCHECK(new_code_map->get(i + kCachedCodeOffset)->IsCode());
- DCHECK(Code::cast(new_code_map->get(i + kCachedCodeOffset))->kind() ==
- Code::OPTIMIZED_FUNCTION);
+ Object* code = new_code_map->get(i + kCachedCodeOffset);
+ if (code != isolate->heap()->undefined_value()) {
+ DCHECK(code->IsCode());
+ DCHECK(Code::cast(code)->kind() == Code::OPTIMIZED_FUNCTION);
+ }
DCHECK(new_code_map->get(i + kLiteralsOffset)->IsFixedArray());
DCHECK(new_code_map->get(i + kOsrAstIdOffset)->IsSmi());
}
@@ -9433,37 +10278,43 @@ void SharedFunctionInfo::EvictFromOptimizedCodeMap(Code* optimized_code,
DisallowHeapAllocation no_gc;
if (optimized_code_map()->IsSmi()) return;
+ Heap* heap = GetHeap();
FixedArray* code_map = FixedArray::cast(optimized_code_map());
int dst = kEntriesStart;
int length = code_map->length();
for (int src = kEntriesStart; src < length; src += kEntryLength) {
DCHECK(code_map->get(src)->IsNativeContext());
- if (Code::cast(code_map->get(src + kCachedCodeOffset)) == optimized_code) {
- // Evict the src entry by not copying it to the dst entry.
+ if (code_map->get(src + kCachedCodeOffset) == optimized_code) {
+ BailoutId osr(Smi::cast(code_map->get(src + kOsrAstIdOffset))->value());
if (FLAG_trace_opt) {
PrintF("[evicting entry from optimizing code map (%s) for ", reason);
ShortPrint();
- BailoutId osr(Smi::cast(code_map->get(src + kOsrAstIdOffset))->value());
if (osr.IsNone()) {
PrintF("]\n");
} else {
PrintF(" (osr ast id %d)]\n", osr.ToInt());
}
}
- } else {
- // Keep the src entry by copying it to the dst entry.
- if (dst != src) {
- code_map->set(dst + kContextOffset,
- code_map->get(src + kContextOffset));
- code_map->set(dst + kCachedCodeOffset,
- code_map->get(src + kCachedCodeOffset));
- code_map->set(dst + kLiteralsOffset,
- code_map->get(src + kLiteralsOffset));
- code_map->set(dst + kOsrAstIdOffset,
- code_map->get(src + kOsrAstIdOffset));
+ if (!osr.IsNone()) {
+ // Evict the src entry by not copying it to the dst entry.
+ continue;
}
- dst += kEntryLength;
+ // In case of non-OSR entry just clear the code in order to proceed
+ // sharing literals.
+ code_map->set_undefined(src + kCachedCodeOffset);
+ }
+
+ // Keep the src entry by copying it to the dst entry.
+ if (dst != src) {
+ code_map->set(dst + kContextOffset, code_map->get(src + kContextOffset));
+ code_map->set(dst + kCachedCodeOffset,
+ code_map->get(src + kCachedCodeOffset));
+ code_map->set(dst + kLiteralsOffset,
+ code_map->get(src + kLiteralsOffset));
+ code_map->set(dst + kOsrAstIdOffset,
+ code_map->get(src + kOsrAstIdOffset));
}
+ dst += kEntryLength;
}
if (code_map->get(kSharedCodeIndex) == optimized_code) {
// Evict context-independent code as well.
@@ -9476,8 +10327,8 @@ void SharedFunctionInfo::EvictFromOptimizedCodeMap(Code* optimized_code,
}
if (dst != length) {
// Always trim even when array is cleared because of heap verifier.
- GetHeap()->RightTrimFixedArray<Heap::CONCURRENT_TO_SWEEPER>(code_map,
- length - dst);
+ heap->RightTrimFixedArray<Heap::CONCURRENT_TO_SWEEPER>(code_map,
+ length - dst);
if (code_map->length() == kEntriesStart &&
code_map->get(kSharedCodeIndex)->IsUndefined()) {
ClearOptimizedCodeMap();
@@ -9515,7 +10366,7 @@ static void ShrinkInstanceSize(Map* map, void* data) {
map->set_instance_size(map->instance_size() - slack * kPointerSize);
// Visitor id might depend on the instance size, recalculate it.
- map->set_visitor_id(StaticVisitorBase::GetVisitorId(map));
+ map->set_visitor_id(Heap::GetStaticVisitorIdForMap(map));
}
@@ -9663,7 +10514,7 @@ bool JSObject::UnregisterPrototypeUser(Handle<Map> user, Isolate* isolate) {
if (slot == PrototypeInfo::UNREGISTERED) return false;
if (prototype->IsJSGlobalProxy()) {
PrototypeIterator iter(isolate, prototype);
- prototype = Handle<JSObject>::cast(PrototypeIterator::GetCurrent(iter));
+ prototype = PrototypeIterator::GetCurrent<JSObject>(iter);
}
DCHECK(prototype->map()->is_prototype_map());
Object* maybe_proto_info = prototype->map()->prototype_info();
@@ -9699,16 +10550,10 @@ static void InvalidatePrototypeChainsInternal(Map* map) {
cell->set_value(Smi::FromInt(Map::kPrototypeChainInvalid));
}
- Object* maybe_array = proto_info->prototype_users();
- if (!maybe_array->IsWeakFixedArray()) return;
-
- WeakFixedArray* users = WeakFixedArray::cast(maybe_array);
- for (int i = 0; i < users->Length(); ++i) {
- Object* maybe_user = users->Get(i);
- if (maybe_user->IsSmi()) continue;
-
- // For now, only maps register themselves as users.
- Map* user = Map::cast(maybe_user);
+ WeakFixedArray::Iterator iterator(proto_info->prototype_users());
+ // For now, only maps register themselves as users.
+ Map* user;
+ while ((user = iterator.Next<Map>())) {
// Walk the prototype chain (backwards, towards leaf objects) if necessary.
InvalidatePrototypeChainsInternal(user);
}
@@ -9721,7 +10566,7 @@ void JSObject::InvalidatePrototypeChains(Map* map) {
DisallowHeapAllocation no_gc;
if (map->IsJSGlobalProxyMap()) {
PrototypeIterator iter(map);
- map = JSObject::cast(iter.GetCurrent())->map();
+ map = iter.GetCurrent<JSObject>()->map();
}
InvalidatePrototypeChainsInternal(map);
}
@@ -9761,7 +10606,7 @@ Handle<Cell> Map::GetOrCreatePrototypeChainValidityCell(Handle<Map> map,
Handle<JSObject> prototype = Handle<JSObject>::cast(maybe_prototype);
if (prototype->IsJSGlobalProxy()) {
PrototypeIterator iter(isolate, prototype);
- prototype = Handle<JSObject>::cast(PrototypeIterator::GetCurrent(iter));
+ prototype = PrototypeIterator::GetCurrent<JSObject>(iter);
}
// Ensure the prototype is registered with its own prototypes so its cell
// will be invalidated when necessary.
@@ -9860,6 +10705,9 @@ void JSFunction::SetInstancePrototype(Handle<JSFunction> function,
function->set_prototype_or_initial_map(*value);
} else {
Handle<Map> new_map = Map::Copy(initial_map, "SetInstancePrototype");
+ if (function->map()->is_strong()) {
+ new_map->set_is_strong();
+ }
JSFunction::SetInitialMap(function, new_map, value);
// If the function is used as the global Array function, cache the
@@ -9897,7 +10745,7 @@ void JSFunction::SetInstancePrototype(Handle<JSFunction> function,
void JSFunction::SetPrototype(Handle<JSFunction> function,
Handle<Object> value) {
- DCHECK(function->should_have_prototype());
+ DCHECK(function->IsConstructor());
Handle<Object> construct_prototype = value;
// If the value is not a JSReceiver, store the value in the map's
@@ -9984,6 +10832,9 @@ void JSFunction::EnsureHasInitialMap(Handle<JSFunction> function) {
in_object_properties = function->shared()->CalculateInObjectProperties();
}
Handle<Map> map = isolate->factory()->NewMap(instance_type, instance_size);
+ if (function->map()->is_strong()) {
+ map->set_is_strong();
+ }
// Fetch or allocate prototype.
Handle<Object> prototype;
@@ -9997,7 +10848,8 @@ void JSFunction::EnsureHasInitialMap(Handle<JSFunction> function) {
DCHECK(map->has_fast_object_elements());
// Finally link initial map and constructor function.
- JSFunction::SetInitialMap(function, map, Handle<JSReceiver>::cast(prototype));
+ DCHECK(prototype->IsJSReceiver());
+ JSFunction::SetInitialMap(function, map, prototype);
if (!function->shared()->is_generator()) {
function->StartInobjectSlackTracking();
@@ -10108,8 +10960,8 @@ int Script::GetColumnNumber(Handle<Script> script, int code_pos) {
DisallowHeapAllocation no_allocation;
FixedArray* line_ends_array = FixedArray::cast(script->line_ends());
- line_number = line_number - script->line_offset()->value();
- if (line_number == 0) return code_pos + script->column_offset()->value();
+ line_number = line_number - script->line_offset();
+ if (line_number == 0) return code_pos + script->column_offset();
int prev_line_end_pos =
Smi::cast(line_ends_array->get(line_number - 1))->value();
return code_pos - (prev_line_end_pos + 1);
@@ -10124,7 +10976,7 @@ int Script::GetLineNumberWithArray(int code_pos) {
if (line_ends_len == 0) return -1;
if ((Smi::cast(line_ends_array->get(0)))->value() >= code_pos) {
- return line_offset()->value();
+ return line_offset();
}
int left = 0;
@@ -10136,7 +10988,7 @@ int Script::GetLineNumberWithArray(int code_pos) {
left += half;
}
}
- return right + line_offset()->value();
+ return right + line_offset();
}
@@ -10212,22 +11064,48 @@ Handle<JSObject> Script::GetWrapper(Handle<Script> script) {
MaybeHandle<SharedFunctionInfo> Script::FindSharedFunctionInfo(
FunctionLiteral* fun) {
- if (shared_function_infos()->IsWeakFixedArray()) {
- WeakFixedArray* array = WeakFixedArray::cast(shared_function_infos());
- for (int i = 0; i < array->Length(); i++) {
- Object* obj = array->Get(i);
- if (!obj->IsSharedFunctionInfo()) continue;
- SharedFunctionInfo* shared = SharedFunctionInfo::cast(obj);
- if (fun->function_token_position() == shared->function_token_position() &&
- fun->start_position() == shared->start_position()) {
- return Handle<SharedFunctionInfo>(shared);
- }
+ WeakFixedArray::Iterator iterator(shared_function_infos());
+ SharedFunctionInfo* shared;
+ while ((shared = iterator.Next<SharedFunctionInfo>())) {
+ if (fun->function_token_position() == shared->function_token_position() &&
+ fun->start_position() == shared->start_position()) {
+ return Handle<SharedFunctionInfo>(shared);
}
}
return MaybeHandle<SharedFunctionInfo>();
}
+Script::Iterator::Iterator(Isolate* isolate)
+ : iterator_(isolate->heap()->script_list()) {}
+
+
+Script* Script::Iterator::Next() { return iterator_.Next<Script>(); }
+
+
+SharedFunctionInfo::Iterator::Iterator(Isolate* isolate)
+ : script_iterator_(isolate), sfi_iterator_(NULL) {
+ NextScript();
+}
+
+
+bool SharedFunctionInfo::Iterator::NextScript() {
+ Script* script = script_iterator_.Next();
+ if (script == NULL) return false;
+ sfi_iterator_.Reset(script->shared_function_infos());
+ return true;
+}
+
+
+SharedFunctionInfo* SharedFunctionInfo::Iterator::Next() {
+ do {
+ SharedFunctionInfo* next = sfi_iterator_.Next<SharedFunctionInfo>();
+ if (next != NULL) return next;
+ } while (NextScript());
+ return NULL;
+}
+
+
void SharedFunctionInfo::SetScript(Handle<SharedFunctionInfo> shared,
Handle<Object> script_object) {
if (shared->script() == *script_object) return;
@@ -10245,10 +11123,11 @@ void SharedFunctionInfo::SetScript(Handle<SharedFunctionInfo> shared,
Handle<Script> script = Handle<Script>::cast(script_object);
Handle<Object> list(script->shared_function_infos(), shared->GetIsolate());
#ifdef DEBUG
- if (list->IsWeakFixedArray()) {
- Handle<WeakFixedArray> array = Handle<WeakFixedArray>::cast(list);
- for (int i = 0; i < array->Length(); ++i) {
- DCHECK(array->Get(i) != *shared);
+ {
+ WeakFixedArray::Iterator iterator(*list);
+ SharedFunctionInfo* next;
+ while ((next = iterator.Next<SharedFunctionInfo>())) {
+ DCHECK_NE(next, *shared);
}
}
#endif // DEBUG
@@ -10471,8 +11350,8 @@ void SharedFunctionInfo::ResetForNewContext(int new_ic_age) {
}
-CodeAndLiterals SharedFunctionInfo::SearchOptimizedCodeMap(
- Context* native_context, BailoutId osr_ast_id) {
+int SharedFunctionInfo::SearchOptimizedCodeMapEntry(Context* native_context,
+ BailoutId osr_ast_id) {
DisallowHeapAllocation no_gc;
DCHECK(native_context->IsNativeContext());
Object* value = optimized_code_map();
@@ -10483,21 +11362,41 @@ CodeAndLiterals SharedFunctionInfo::SearchOptimizedCodeMap(
for (int i = kEntriesStart; i < length; i += kEntryLength) {
if (optimized_code_map->get(i + kContextOffset) == native_context &&
optimized_code_map->get(i + kOsrAstIdOffset) == osr_ast_id_smi) {
- return {Code::cast(optimized_code_map->get(i + kCachedCodeOffset)),
- FixedArray::cast(optimized_code_map->get(i + kLiteralsOffset))};
+ return i;
}
}
Object* shared_code = optimized_code_map->get(kSharedCodeIndex);
if (shared_code->IsCode() && osr_ast_id.IsNone()) {
- return {Code::cast(shared_code), nullptr};
+ return kSharedCodeIndex;
}
- if (FLAG_trace_opt) {
- PrintF("[didn't find optimized code in optimized code map for ");
- ShortPrint();
- PrintF("]\n");
+ }
+ return -1;
+}
+
+
+CodeAndLiterals SharedFunctionInfo::SearchOptimizedCodeMap(
+ Context* native_context, BailoutId osr_ast_id) {
+ CodeAndLiterals result = {nullptr, nullptr};
+ int entry = SearchOptimizedCodeMapEntry(native_context, osr_ast_id);
+ if (entry != kNotFound) {
+ FixedArray* code_map = FixedArray::cast(optimized_code_map());
+ if (entry == kSharedCodeIndex) {
+ result = {Code::cast(code_map->get(kSharedCodeIndex)), nullptr};
+
+ } else {
+ DCHECK_LE(entry + kEntryLength, code_map->length());
+ Object* code = code_map->get(entry + kCachedCodeOffset);
+ result = {code->IsUndefined() ? nullptr : Code::cast(code),
+ LiteralsArray::cast(code_map->get(entry + kLiteralsOffset))};
}
}
- return {nullptr, nullptr};
+ if (FLAG_trace_opt && !optimized_code_map()->IsSmi() &&
+ result.code == nullptr) {
+ PrintF("[didn't find optimized code in optimized code map for ");
+ ShortPrint();
+ PrintF("]\n");
+ }
+ return result;
}
@@ -10605,7 +11504,7 @@ void Code::Relocate(intptr_t delta) {
for (RelocIterator it(this, RelocInfo::kApplyMask); !it.done(); it.next()) {
it.rinfo()->apply(delta);
}
- CpuFeatures::FlushICache(instruction_start(), instruction_size());
+ Assembler::FlushICache(GetIsolate(), instruction_start(), instruction_size());
}
@@ -10659,7 +11558,7 @@ void Code::CopyFrom(const CodeDesc& desc) {
it.rinfo()->apply(delta);
}
}
- CpuFeatures::FlushICache(instruction_start(), instruction_size());
+ Assembler::FlushICache(GetIsolate(), instruction_start(), instruction_size());
}
@@ -11439,7 +12338,7 @@ void Code::PrintExtraICState(std::ostream& os, // NOLINT
void Code::Disassemble(const char* name, std::ostream& os) { // NOLINT
os << "kind = " << Kind2String(kind()) << "\n";
if (IsCodeStubOrIC()) {
- const char* n = CodeStub::MajorName(CodeStub::GetMajorKey(this), true);
+ const char* n = CodeStub::MajorName(CodeStub::GetMajorKey(this));
os << "major_key = " << (n == NULL ? "null" : n) << "\n";
}
if (is_inline_cache_stub()) {
@@ -11584,6 +12483,7 @@ void Code::Disassemble(const char* name, std::ostream& os) { // NOLINT
void BytecodeArray::Disassemble(std::ostream& os) {
+ os << "Parameter count " << parameter_count() << "\n";
os << "Frame size " << frame_size() << "\n";
Vector<char> buf = Vector<char>::New(50);
@@ -11597,9 +12497,12 @@ void BytecodeArray::Disassemble(std::ostream& os) {
SNPrintF(buf, "%p", bytecode_start);
os << buf.start() << " : ";
- interpreter::Bytecodes::Decode(os, bytecode_start);
+ interpreter::Bytecodes::Decode(os, bytecode_start, parameter_count());
os << "\n";
}
+
+ os << "Constant pool (size = " << constant_pool()->length() << ")\n";
+ constant_pool()->Print();
}
@@ -12061,7 +12964,7 @@ MaybeHandle<Object> JSObject::SetPrototype(Handle<JSObject> object,
for (PrototypeIterator iter(isolate, *value,
PrototypeIterator::START_AT_RECEIVER);
!iter.IsAtEnd(); iter.Advance()) {
- if (JSReceiver::cast(iter.GetCurrent()) == *object) {
+ if (iter.GetCurrent<JSReceiver>() == *object) {
// Cycle detected.
THROW_NEW_ERROR(isolate, NewTypeError(MessageTemplate::kCyclicProto),
Object);
@@ -12077,8 +12980,7 @@ MaybeHandle<Object> JSObject::SetPrototype(Handle<JSObject> object,
// hidden and set the new prototype on that object.
PrototypeIterator iter(isolate, real_receiver);
while (!iter.IsAtEnd(PrototypeIterator::END_AT_NON_HIDDEN)) {
- real_receiver =
- Handle<JSObject>::cast(PrototypeIterator::GetCurrent(iter));
+ real_receiver = PrototypeIterator::GetCurrent<JSObject>(iter);
iter.Advance();
if (!real_receiver->map()->is_extensible()) {
THROW_NEW_ERROR(
@@ -12107,7 +13009,7 @@ MaybeHandle<Object> JSObject::SetPrototype(Handle<JSObject> object,
// If the prototype chain didn't previously have element callbacks, then
// KeyedStoreICs need to be cleared to ensure any that involve this
// map go generic.
- object->GetHeap()->ClearAllICsByKind(Code::KEYED_STORE_IC);
+ object->GetHeap()->ClearAllKeyedStoreICs();
}
heap->ClearInstanceofCache();
@@ -12277,7 +13179,7 @@ MaybeHandle<Object> JSObject::AddDataElement(Handle<JSObject> object,
to = GetHoleyElementsKind(to);
kind = GetHoleyElementsKind(kind);
}
- to = IsMoreGeneralElementsKindTransition(kind, to) ? to : kind;
+ to = GetMoreGeneralElementsKind(kind, to);
ElementsAccessor* accessor = ElementsAccessor::ForKind(to);
accessor->Add(object, index, value, attributes, new_capacity);
@@ -13834,7 +14736,7 @@ Handle<Object> JSObject::PrepareElementsForSort(Handle<JSObject> object,
Handle<FixedArrayBase> elements_base(object->elements());
uint32_t elements_length = static_cast<uint32_t>(elements_base->length());
if (limit > elements_length) {
- limit = elements_length ;
+ limit = elements_length;
}
if (limit == 0) {
return handle(Smi::FromInt(0), isolate);
@@ -13950,12 +14852,6 @@ size_t JSTypedArray::element_size() {
}
-void FixedArray::SetValue(uint32_t index, Object* value) { set(index, value); }
-
-
-void FixedDoubleArray::SetValue(uint32_t index, Object* value) {
- set(index, value->Number());
-}
void GlobalObject::InvalidatePropertyCell(Handle<GlobalObject> global,
Handle<Name> name) {
DCHECK(!global->HasFastProperties());
@@ -14106,7 +15002,7 @@ void StringTable::EnsureCapacityForDeserialization(Isolate* isolate,
// We need a key instance for the virtual hash function.
InternalizedStringKey dummy_key(Handle<String>::null());
table = StringTable::EnsureCapacity(table, expected, &dummy_key);
- isolate->factory()->set_string_table(table);
+ isolate->heap()->SetRootStringTable(*table);
}
@@ -14140,7 +15036,7 @@ Handle<String> StringTable::LookupKey(Isolate* isolate, HashTableKey* key) {
table->set(EntryToIndex(entry), *string);
table->ElementAdded();
- isolate->factory()->set_string_table(table);
+ isolate->heap()->SetRootStringTable(*table);
return Handle<String>::cast(string);
}
@@ -14521,7 +15417,7 @@ void SeededNumberDictionary::UpdateMaxNumberKey(uint32_t key,
if (key > kRequiresSlowElementsLimit) {
if (used_as_prototype) {
// TODO(verwaest): Remove this hack.
- GetHeap()->ClearAllICsByKind(Code::KEYED_STORE_IC);
+ GetHeap()->ClearAllKeyedStoreICs();
}
set_requires_slow_elements();
return;
@@ -14870,49 +15766,6 @@ void WeakHashTable::AddEntry(int entry, Handle<WeakCell> key_cell,
}
-#ifdef DEBUG
-Object* WeakValueHashTable::LookupWeak(Handle<Object> key) {
- Object* value = Lookup(key);
- if (value->IsWeakCell() && !WeakCell::cast(value)->cleared()) {
- value = WeakCell::cast(value)->value();
- }
- return value;
-}
-#endif // DEBUG
-
-
-Handle<WeakValueHashTable> WeakValueHashTable::PutWeak(
- Handle<WeakValueHashTable> table, Handle<Object> key,
- Handle<HeapObject> value) {
- Handle<WeakCell> cell = value->GetIsolate()->factory()->NewWeakCell(value);
- return Handle<WeakValueHashTable>::cast(
- Put(Handle<ObjectHashTable>::cast(table), key, cell));
-}
-
-
-Handle<FixedArray> WeakValueHashTable::GetWeakValues(
- Handle<WeakValueHashTable> table) {
- Isolate* isolate = table->GetIsolate();
- uint32_t capacity = table->Capacity();
- Handle<FixedArray> results = isolate->factory()->NewFixedArray(capacity);
- int length = 0;
- for (uint32_t i = 0; i < capacity; i++) {
- uint32_t key_index = table->EntryToIndex(i);
- Object* key = table->get(key_index);
- if (!table->IsKey(key)) continue;
- uint32_t value_index = table->EntryToValueIndex(i);
- WeakCell* value_cell = WeakCell::cast(table->get(value_index));
- if (value_cell->cleared()) {
- table->RemoveEntry(i);
- } else {
- results->set(length++, value_cell->value());
- }
- }
- results->Shrink(length);
- return results;
-}
-
-
template<class Derived, class Iterator, int entrysize>
Handle<Derived> OrderedHashTable<Derived, Iterator, entrysize>::Allocate(
Isolate* isolate, int capacity, PretenureFlag pretenure) {
@@ -14985,6 +15838,48 @@ Handle<Derived> OrderedHashTable<Derived, Iterator, entrysize>::Clear(
return new_table;
}
+template <class Derived, class Iterator, int entrysize>
+bool OrderedHashTable<Derived, Iterator, entrysize>::HasKey(
+ Handle<Derived> table, Handle<Object> key) {
+ int entry = table->KeyToFirstEntry(*key);
+ // Walk the chain in the bucket to find the key.
+ while (entry != kNotFound) {
+ Object* candidate_key = table->KeyAt(entry);
+ if (candidate_key->SameValueZero(*key)) return true;
+ entry = table->NextChainEntry(entry);
+ }
+ return false;
+}
+
+
+Handle<OrderedHashSet> OrderedHashSet::Add(Handle<OrderedHashSet> table,
+ Handle<Object> key) {
+ int hash = Object::GetOrCreateHash(table->GetIsolate(), key)->value();
+ int entry = table->HashToEntry(hash);
+ // Walk the chain of the bucket and try finding the key.
+ while (entry != kNotFound) {
+ Object* candidate_key = table->KeyAt(entry);
+ // Do not add if we have the key already
+ if (candidate_key->SameValueZero(*key)) return table;
+ entry = table->NextChainEntry(entry);
+ }
+
+ table = OrderedHashSet::EnsureGrowable(table);
+ // Read the existing bucket values.
+ int bucket = table->HashToBucket(hash);
+ int previous_entry = table->HashToEntry(hash);
+ int nof = table->NumberOfElements();
+ // Insert a new entry at the end,
+ int new_entry = nof + table->NumberOfDeletedElements();
+ int new_index = table->EntryToIndex(new_entry);
+ table->set(new_index, *key);
+ table->set(new_index + kChainOffset, Smi::FromInt(previous_entry));
+ // and point the bucket to the new entry.
+ table->set(kHashTableStartIndex + bucket, Smi::FromInt(new_entry));
+ table->SetNumberOfElements(nof + 1);
+ return table;
+}
+
template<class Derived, class Iterator, int entrysize>
Handle<Derived> OrderedHashTable<Derived, Iterator, entrysize>::Rehash(
@@ -15047,6 +15942,9 @@ template Handle<OrderedHashSet>
OrderedHashTable<OrderedHashSet, JSSetIterator, 1>::Clear(
Handle<OrderedHashSet> table);
+template bool OrderedHashTable<OrderedHashSet, JSSetIterator, 1>::HasKey(
+ Handle<OrderedHashSet> table, Handle<Object> key);
+
template Handle<OrderedHashMap>
OrderedHashTable<OrderedHashMap, JSMapIterator, 2>::Allocate(
@@ -15064,6 +15962,9 @@ template Handle<OrderedHashMap>
OrderedHashTable<OrderedHashMap, JSMapIterator, 2>::Clear(
Handle<OrderedHashMap> table);
+template bool OrderedHashTable<OrderedHashMap, JSMapIterator, 2>::HasKey(
+ Handle<OrderedHashMap> table, Handle<Object> key);
+
template<class Derived, class TableType>
void OrderedHashTableIterator<Derived, TableType>::Transition() {
@@ -15169,6 +16070,75 @@ template void
OrderedHashTableIterator<JSMapIterator, OrderedHashMap>::Transition();
+void JSSet::Initialize(Handle<JSSet> set, Isolate* isolate) {
+ Handle<OrderedHashSet> table = isolate->factory()->NewOrderedHashSet();
+ set->set_table(*table);
+}
+
+
+void JSSet::Clear(Handle<JSSet> set) {
+ Handle<OrderedHashSet> table(OrderedHashSet::cast(set->table()));
+ table = OrderedHashSet::Clear(table);
+ set->set_table(*table);
+}
+
+
+void JSMap::Initialize(Handle<JSMap> map, Isolate* isolate) {
+ Handle<OrderedHashMap> table = isolate->factory()->NewOrderedHashMap();
+ map->set_table(*table);
+}
+
+
+void JSMap::Clear(Handle<JSMap> map) {
+ Handle<OrderedHashMap> table(OrderedHashMap::cast(map->table()));
+ table = OrderedHashMap::Clear(table);
+ map->set_table(*table);
+}
+
+
+void JSWeakCollection::Initialize(Handle<JSWeakCollection> weak_collection,
+ Isolate* isolate) {
+ DCHECK_EQ(0, weak_collection->map()->GetInObjectProperties());
+ Handle<ObjectHashTable> table = ObjectHashTable::New(isolate, 0);
+ weak_collection->set_table(*table);
+}
+
+
+void JSWeakCollection::Set(Handle<JSWeakCollection> weak_collection,
+ Handle<Object> key, Handle<Object> value,
+ int32_t hash) {
+ DCHECK(key->IsJSReceiver() || key->IsSymbol());
+ Handle<ObjectHashTable> table(
+ ObjectHashTable::cast(weak_collection->table()));
+ DCHECK(table->IsKey(*key));
+ Handle<ObjectHashTable> new_table =
+ ObjectHashTable::Put(table, key, value, hash);
+ weak_collection->set_table(*new_table);
+ if (*table != *new_table) {
+ // Zap the old table since we didn't record slots for its elements.
+ table->FillWithHoles(0, table->length());
+ }
+}
+
+
+bool JSWeakCollection::Delete(Handle<JSWeakCollection> weak_collection,
+ Handle<Object> key, int32_t hash) {
+ DCHECK(key->IsJSReceiver() || key->IsSymbol());
+ Handle<ObjectHashTable> table(
+ ObjectHashTable::cast(weak_collection->table()));
+ DCHECK(table->IsKey(*key));
+ bool was_present = false;
+ Handle<ObjectHashTable> new_table =
+ ObjectHashTable::Remove(table, key, &was_present, hash);
+ weak_collection->set_table(*new_table);
+ if (*table != *new_table) {
+ // Zap the old table since we didn't record slots for its elements.
+ table->FillWithHoles(0, table->length());
+ }
+ return was_present;
+}
+
+
// Check if there is a break point at this code position.
bool DebugInfo::HasBreakPoint(int code_position) {
// Get the break point info object for this code position.
@@ -15249,10 +16219,9 @@ void DebugInfo::SetBreakPoint(Handle<DebugInfo> debug_info,
// Allocate new BreakPointInfo object and set the break point.
Handle<BreakPointInfo> new_break_point_info = Handle<BreakPointInfo>::cast(
isolate->factory()->NewStruct(BREAK_POINT_INFO_TYPE));
- new_break_point_info->set_code_position(Smi::FromInt(code_position));
- new_break_point_info->set_source_position(Smi::FromInt(source_position));
- new_break_point_info->
- set_statement_position(Smi::FromInt(statement_position));
+ new_break_point_info->set_code_position(code_position);
+ new_break_point_info->set_source_position(source_position);
+ new_break_point_info->set_statement_position(statement_position);
new_break_point_info->set_break_point_objects(
isolate->heap()->undefined_value());
BreakPointInfo::SetBreakPoint(new_break_point_info, break_point_object);
@@ -15314,7 +16283,7 @@ int DebugInfo::GetBreakPointInfoIndex(int code_position) {
if (!break_points()->get(i)->IsUndefined()) {
BreakPointInfo* break_point_info =
BreakPointInfo::cast(break_points()->get(i));
- if (break_point_info->code_position()->value() == code_position) {
+ if (break_point_info->code_position() == code_position) {
return i;
}
}
@@ -15536,6 +16505,27 @@ void JSDate::SetValue(Object* value, bool is_value_nan) {
}
+// static
+MaybeHandle<Object> JSDate::ToPrimitive(Handle<JSReceiver> receiver,
+ Handle<Object> hint) {
+ Isolate* const isolate = receiver->GetIsolate();
+ if (hint->IsString()) {
+ Handle<String> hint_string = Handle<String>::cast(hint);
+ if (hint_string->Equals(isolate->heap()->number_string())) {
+ return JSReceiver::OrdinaryToPrimitive(receiver,
+ OrdinaryToPrimitiveHint::kNumber);
+ }
+ if (hint_string->Equals(isolate->heap()->default_string()) ||
+ hint_string->Equals(isolate->heap()->string_string())) {
+ return JSReceiver::OrdinaryToPrimitive(receiver,
+ OrdinaryToPrimitiveHint::kString);
+ }
+ }
+ THROW_NEW_ERROR(isolate, NewTypeError(MessageTemplate::kInvalidHint, hint),
+ Object);
+}
+
+
void JSDate::SetCachedFields(int64_t local_time_ms, DateCache* date_cache) {
int days = DateCache::DaysFromTime(local_time_ms);
int time_in_day_ms = DateCache::TimeInDay(local_time_ms, days);
@@ -15565,6 +16555,61 @@ void JSArrayBuffer::Neuter() {
}
+void JSArrayBuffer::Setup(Handle<JSArrayBuffer> array_buffer, Isolate* isolate,
+ bool is_external, void* data, size_t allocated_length,
+ SharedFlag shared) {
+ DCHECK(array_buffer->GetInternalFieldCount() ==
+ v8::ArrayBuffer::kInternalFieldCount);
+ for (int i = 0; i < v8::ArrayBuffer::kInternalFieldCount; i++) {
+ array_buffer->SetInternalField(i, Smi::FromInt(0));
+ }
+ array_buffer->set_bit_field(0);
+ array_buffer->set_is_external(is_external);
+ array_buffer->set_is_neuterable(shared == SharedFlag::kNotShared);
+ array_buffer->set_is_shared(shared == SharedFlag::kShared);
+
+ Handle<Object> byte_length =
+ isolate->factory()->NewNumberFromSize(allocated_length);
+ CHECK(byte_length->IsSmi() || byte_length->IsHeapNumber());
+ array_buffer->set_byte_length(*byte_length);
+ // Initialize backing store at last to avoid handling of |JSArrayBuffers| that
+ // are currently being constructed in the |ArrayBufferTracker|. The
+ // registration method below handles the case of registering a buffer that has
+ // already been promoted.
+ array_buffer->set_backing_store(data);
+
+ if (data && !is_external) {
+ isolate->heap()->RegisterNewArrayBuffer(*array_buffer);
+ }
+}
+
+
+bool JSArrayBuffer::SetupAllocatingData(Handle<JSArrayBuffer> array_buffer,
+ Isolate* isolate,
+ size_t allocated_length,
+ bool initialize, SharedFlag shared) {
+ void* data;
+ CHECK(isolate->array_buffer_allocator() != NULL);
+ // Prevent creating array buffers when serializing.
+ DCHECK(!isolate->serializer_enabled());
+ if (allocated_length != 0) {
+ if (initialize) {
+ data = isolate->array_buffer_allocator()->Allocate(allocated_length);
+ } else {
+ data = isolate->array_buffer_allocator()->AllocateUninitialized(
+ allocated_length);
+ }
+ if (data == NULL) return false;
+ } else {
+ data = NULL;
+ }
+
+ JSArrayBuffer::Setup(array_buffer, isolate, false, data, allocated_length,
+ shared);
+ return true;
+}
+
+
Handle<JSArrayBuffer> JSTypedArray::MaterializeArrayBuffer(
Handle<JSTypedArray> typed_array) {
@@ -15581,11 +16626,16 @@ Handle<JSArrayBuffer> JSTypedArray::MaterializeArrayBuffer(
void* backing_store =
isolate->array_buffer_allocator()->AllocateUninitialized(
fixed_typed_array->DataSize());
- buffer->set_backing_store(backing_store);
buffer->set_is_external(false);
- isolate->heap()->RegisterNewArrayBuffer(isolate->heap()->InNewSpace(*buffer),
- backing_store,
- fixed_typed_array->DataSize());
+ DCHECK(buffer->byte_length()->IsSmi() ||
+ buffer->byte_length()->IsHeapNumber());
+ DCHECK(NumberToInt32(buffer->byte_length()) == fixed_typed_array->DataSize());
+ // Initialize backing store at last to avoid handling of |JSArrayBuffers| that
+ // are currently being constructed in the |ArrayBufferTracker|. The
+ // registration method below handles the case of registering a buffer that has
+ // already been promoted.
+ buffer->set_backing_store(backing_store);
+ isolate->heap()->RegisterNewArrayBuffer(*buffer);
memcpy(buffer->backing_store(),
fixed_typed_array->DataPtr(),
fixed_typed_array->DataSize());