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 . |
+ 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(); |