Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(250)

Unified Diff: src/objects.cc

Issue 1306303003: [es6] Implement spec compliant ToPrimitive in the runtime. (Closed) Base URL: https://chromium.googlesource.com/v8/v8.git@master
Patch Set: Address Michis comments. Created 5 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « src/objects.h ('k') | src/objects-inl.h » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: src/objects.cc
diff --git a/src/objects.cc b/src/objects.cc
index fc461887cf0bc6e85263fd082b019abb5e20d7f2..260a64b91d2b436c796b61493770445f6e9b154f 100644
--- a/src/objects.cc
+++ b/src/objects.cc
@@ -90,14 +90,57 @@ MaybeHandle<JSReceiver> Object::ToObject(Isolate* isolate,
}
-MaybeHandle<Name> Object::ToName(Isolate* isolate, Handle<Object> object) {
- if (object->IsName()) {
- return Handle<Name>::cast(object);
- } else {
- Handle<Object> converted;
- ASSIGN_RETURN_ON_EXCEPTION(isolate, converted,
- Execution::ToString(isolate, object), Name);
- return Handle<Name>::cast(converted);
+// static
+MaybeHandle<Object> Object::ToNumber(Isolate* isolate, Handle<Object> input) {
+ while (true) {
+ if (input->IsNumber()) {
+ return input;
+ }
+ if (input->IsOddball()) {
+ return handle(Handle<Oddball>::cast(input)->to_number(), isolate);
+ }
+ if (input->IsString()) {
+ return String::ToNumber(Handle<String>::cast(input));
+ }
+ 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<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);
}
}
@@ -109,7 +152,6 @@ 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;
}
@@ -157,6 +199,26 @@ bool Object::IsPromise(Handle<Object> object) {
}
+// 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()) {
@@ -1485,6 +1547,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) &&
@@ -3279,7 +3408,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::ToNumber(it->isolate(), value),
Object);
// ToNumber above might modify the receiver, causing the cached
// holder_map to mismatch the actual holder->map() after this point.
@@ -5881,6 +6010,75 @@ 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);
adamk 2015/08/28 19:36:15 This is going to change behavior when invoking ToP
+ 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)
+ ? isolate->factory()->string_string()
+ : isolate->factory()->number_string());
+}
+
+
+// static
+MaybeHandle<Object> JSReceiver::OrdinaryToPrimitive(Handle<JSReceiver> receiver,
+ Handle<String> hint) {
+ Isolate* const isolate = receiver->GetIsolate();
+ Handle<String> method_names[2];
+ if (hint.is_identical_to(isolate->factory()->number_string())) {
+ method_names[0] = isolate->factory()->valueOf_string();
+ method_names[1] = isolate->factory()->toString_string();
+ } else {
+ DCHECK(hint.is_identical_to(isolate->factory()->string_string()));
+ method_names[0] = isolate->factory()->toString_string();
+ method_names[1] = isolate->factory()->valueOf_string();
+ }
+ 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).
@@ -8152,6 +8350,95 @@ bool String::LooksValid() {
}
+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();
« no previous file with comments | « src/objects.h ('k') | src/objects-inl.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698