}
Handle<Object> number_v;
- if (!Execution::ToNumber(isolate, length_obj).ToHandle(&number_v)) {
+ if (!Object::ToNumber(isolate, length_obj).ToHandle(&number_v)) {
isolate->OptionalRescheduleException(false);
return;
}
PREPARE_FOR_EXECUTION(context, "ToString", String);
Local<String> result;
has_pending_exception =
- !ToLocal<String>(i::Execution::ToString(isolate, obj), &result);
+ !ToLocal<String>(i::Object::ToString(isolate, obj), &result);
RETURN_ON_FAILED_EXECUTION(String);
RETURN_ESCAPED(result);
}
PREPARE_FOR_EXECUTION(context, "ToNumber", Number);
Local<Number> result;
has_pending_exception =
- !ToLocal<Number>(i::Execution::ToNumber(isolate, obj), &result);
+ !ToLocal<Number>(i::Object::ToNumber(isolate, obj), &result);
RETURN_ON_FAILED_EXECUTION(Number);
RETURN_ESCAPED(result);
}
if (obj->IsNumber()) return Just(obj->Number());
PREPARE_FOR_EXECUTION_PRIMITIVE(context, "NumberValue", double);
i::Handle<i::Object> num;
- has_pending_exception = !i::Execution::ToNumber(isolate, obj).ToHandle(&num);
+ has_pending_exception = !i::Object::ToNumber(isolate, obj).ToHandle(&num);
RETURN_ON_FAILED_EXECUTION_PRIMITIVE(double);
return Just(num->Number());
}
PREPARE_FOR_EXECUTION(context, "ToArrayIndex", Uint32);
i::Handle<i::Object> string_obj;
has_pending_exception =
- !i::Execution::ToString(isolate, self).ToHandle(&string_obj);
+ !i::Object::ToString(isolate, self).ToHandle(&string_obj);
RETURN_ON_FAILED_EXECUTION(Uint32);
i::Handle<i::String> str = i::Handle<i::String>::cast(string_obj);
uint32_t index;
auto self = Utils::OpenHandle(this);
auto key_obj = Utils::OpenHandle(*key);
if (!key_obj->IsName()) {
- has_pending_exception = !i::Execution::ToString(
- isolate, key_obj).ToHandle(&key_obj);
+ has_pending_exception =
+ !i::Object::ToString(isolate, key_obj).ToHandle(&key_obj);
RETURN_ON_FAILED_EXECUTION_PRIMITIVE(PropertyAttribute);
}
auto key_name = i::Handle<i::Name>::cast(key_obj);
__ bind(¬_oddball);
__ push(r0); // Push argument.
- __ InvokeBuiltin(Context::TO_NUMBER_BUILTIN_INDEX, JUMP_FUNCTION);
+ __ TailCallRuntime(Runtime::kToNumber, 1, 1);
}
__ Bind(¬_oddball);
__ Push(x0); // Push argument.
- __ InvokeBuiltin(Context::TO_NUMBER_BUILTIN_INDEX, JUMP_FUNCTION);
+ __ TailCallRuntime(Runtime::kToNumber, 1, 1);
}
case Runtime::kInlineGetPrototype:
case Runtime::kInlineRegExpExec:
case Runtime::kInlineToObject:
+ case Runtime::kInlineToPrimitive:
+ case Runtime::kInlineToPrimitive_Number:
+ case Runtime::kInlineToPrimitive_String:
+ case Runtime::kInlineOrdinaryToPrimitive:
+ case Runtime::kInlineToNumber:
return 1;
case Runtime::kInlineDeoptimizeNow:
case Runtime::kInlineThrowNotDateError:
V(SUB_BUILTIN_INDEX, JSFunction, sub_builtin) \
V(SUB_STRONG_BUILTIN_INDEX, JSFunction, sub_strong_builtin) \
V(TO_NAME_BUILTIN_INDEX, JSFunction, to_name_builtin) \
- V(TO_NUMBER_BUILTIN_INDEX, JSFunction, to_number_builtin) \
V(TO_STRING_BUILTIN_INDEX, JSFunction, to_string_builtin)
}
+// 20.3.4.45 Date.prototype [ @@toPrimitive ] ( hint )
+function DateToPrimitive(hint) {
+ if (!IS_SPEC_OBJECT(this)) {
+ throw MakeTypeError(kIncompatibleMethodReceiver,
+ "Date.prototype [ @@toPrimitive ]", this);
+ }
+ if (hint === "default") {
+ hint = "string";
+ } else if (hint !== "number" && hint !== "string") {
+ throw MakeTypeError(kInvalidHint, hint);
+ }
+ return %OrdinaryToPrimitive(this, hint);
+}
+
+
// ECMA 262 - 15.9.5.8
function DateValueOf() {
CHECK_DATE(this);
}
+// 20.3.4.37 Date.prototype.toJSON ( key )
function DateToJSON(key) {
var o = TO_OBJECT(this);
- var tv = $defaultNumber(o);
+ var tv = TO_PRIMITIVE_NUMBER(o);
if (IS_NUMBER(tv) && !NUMBER_IS_FINITE(tv)) {
return null;
}
// Set up non-enumerable constructor property of the Date prototype object.
%AddNamedProperty(GlobalDate.prototype, "constructor", GlobalDate, DONT_ENUM);
+utils.SetFunctionName(DateToPrimitive, symbolToPrimitive);
+%AddNamedProperty(GlobalDate.prototype, symbolToPrimitive, DateToPrimitive,
+ DONT_ENUM | READ_ONLY);
// Set up non-enumerable functions of the Date prototype object and
// set their names.
Handle<Object> exception;
if (!maybe_exception.ToHandle(&exception)) break;
Handle<Object> result;
- if (!Execution::ToString(isolate_, exception).ToHandle(&result)) break;
+ if (!Object::ToString(isolate_, exception).ToHandle(&result)) break;
answer = Handle<String>::cast(result);
}
} while (false)
-MaybeHandle<Object> Execution::ToNumber(
- Isolate* isolate, Handle<Object> obj) {
- RETURN_NATIVE_CALL(to_number, { obj });
-}
-
-
-MaybeHandle<Object> Execution::ToString(
- Isolate* isolate, Handle<Object> obj) {
- RETURN_NATIVE_CALL(to_string, { obj });
-}
-
-
MaybeHandle<Object> Execution::ToDetailString(
Isolate* isolate, Handle<Object> obj) {
RETURN_NATIVE_CALL(to_detail_string, { obj });
MaybeHandle<Object> Execution::ToInt32(Isolate* isolate, Handle<Object> obj) {
- ASSIGN_RETURN_ON_EXCEPTION(isolate, obj, Execution::ToNumber(isolate, obj),
+ ASSIGN_RETURN_ON_EXCEPTION(isolate, obj, Object::ToNumber(isolate, obj),
Object);
return isolate->factory()->NewNumberFromInt(DoubleToInt32(obj->Number()));
}
MaybeHandle<Object> Execution::ToUint32(Isolate* isolate, Handle<Object> obj) {
- ASSIGN_RETURN_ON_EXCEPTION(isolate, obj, Execution::ToNumber(isolate, obj),
+ ASSIGN_RETURN_ON_EXCEPTION(isolate, obj, Object::ToNumber(isolate, obj),
Object);
return isolate->factory()->NewNumberFromUint(DoubleToUint32(obj->Number()));
}
Handle<Object> argv[],
MaybeHandle<Object>* exception_out = NULL);
- // ECMA-262 9.3
- MUST_USE_RESULT static MaybeHandle<Object> ToNumber(
- Isolate* isolate, Handle<Object> obj);
-
// ECMA-262 9.4
MUST_USE_RESULT static MaybeHandle<Object> ToInteger(
Isolate* isolate, Handle<Object> obj);
Isolate* isolate, Handle<Object> obj);
// ECMA-262 9.8
- MUST_USE_RESULT static MaybeHandle<Object> ToString(
- Isolate* isolate, Handle<Object> obj);
-
- // ECMA-262 9.8
MUST_USE_RESULT static MaybeHandle<Object> ToDetailString(
Isolate* isolate, Handle<Object> obj);
// string "valueOf" the result is false.
// The use of ip to store the valueOf string assumes that it is not otherwise
// used in the loop below.
- __ mov(ip, Operand(isolate()->factory()->value_of_string()));
+ __ LoadRoot(ip, Heap::kvalueOf_stringRootIndex);
__ jmp(&entry);
__ bind(&loop);
__ ldr(r3, MemOperand(r4, 0));
// string "valueOf" the result is false.
Register valueof_string = x1;
int descriptor_size = DescriptorArray::kDescriptorSize * kPointerSize;
- __ Mov(valueof_string, Operand(isolate()->factory()->value_of_string()));
+ __ LoadRoot(valueof_string, Heap::kvalueOf_stringRootIndex);
__ Bind(&loop);
__ Ldr(x15, MemOperand(descriptors, descriptor_size, PostIndex));
__ Cmp(x15, valueof_string);
__ jmp(&entry);
__ bind(&loop);
__ mov(edx, FieldOperand(ebx, 0));
- __ cmp(edx, isolate()->factory()->value_of_string());
+ __ cmp(edx, isolate()->factory()->valueOf_string());
__ j(equal, if_false);
__ add(ebx, Immediate(DescriptorArray::kDescriptorSize * kPointerSize));
__ bind(&entry);
// string "valueOf" the result is false.
// The use of t2 to store the valueOf string assumes that it is not otherwise
// used in the loop below.
- __ li(t2, Operand(isolate()->factory()->value_of_string()));
+ __ LoadRoot(t2, Heap::kvalueOf_stringRootIndex);
__ jmp(&entry);
__ bind(&loop);
__ lw(a3, MemOperand(t0, 0));
// string "valueOf" the result is false.
// The use of a6 to store the valueOf string assumes that it is not otherwise
// used in the loop below.
- __ li(a6, Operand(isolate()->factory()->value_of_string()));
+ __ LoadRoot(a6, Heap::kvalueOf_stringRootIndex);
__ jmp(&entry);
__ bind(&loop);
__ ld(a3, MemOperand(a4, 0));
// string "valueOf" the result is false.
// The use of ip to store the valueOf string assumes that it is not otherwise
// used in the loop below.
- __ mov(ip, Operand(isolate()->factory()->value_of_string()));
+ __ LoadRoot(ip, Heap::kvalueOf_stringRootIndex);
__ b(&entry);
__ bind(&loop);
__ LoadP(r6, MemOperand(r7, 0));
__ jmp(&entry);
__ bind(&loop);
__ movp(rdx, FieldOperand(r8, 0));
- __ Cmp(rdx, isolate()->factory()->value_of_string());
+ __ CompareRoot(rdx, Heap::kvalueOf_stringRootIndex);
__ j(equal, if_false);
__ addp(r8, Immediate(DescriptorArray::kDescriptorSize * kPointerSize));
__ bind(&entry);
__ jmp(&entry);
__ bind(&loop);
__ mov(edx, FieldOperand(ebx, 0));
- __ cmp(edx, isolate()->factory()->value_of_string());
+ __ cmp(edx, isolate()->factory()->valueOf_string());
__ j(equal, if_false);
__ add(ebx, Immediate(DescriptorArray::kDescriptorSize * kPointerSize));
__ bind(&entry);
V(Boolean_string, "Boolean") \
V(callee_string, "callee") \
V(constructor_string, "constructor") \
+ V(default_string, "default") \
V(dot_result_string, ".result") \
V(eval_string, "eval") \
V(float32x4_string, "float32x4") \
V(Date_string, "Date") \
V(char_at_string, "CharAt") \
V(undefined_string, "undefined") \
- V(value_of_string, "valueOf") \
+ V(valueOf_string, "valueOf") \
V(stack_string, "stack") \
+ V(toString_string, "toString") \
V(toJSON_string, "toJSON") \
V(KeyedLoadMonomorphic_string, "KeyedLoadMonomorphic") \
V(KeyedStoreMonomorphic_string, "KeyedStoreMonomorphic") \
Symbol.isConcatSpreadable) \
V(is_regexp_symbol, symbolIsRegExp, Symbol.isRegExp) \
V(iterator_symbol, symbolIterator, Symbol.iterator) \
+ V(to_primitive_symbol, symbolToPrimitive, Symbol.toPrimitive) \
V(to_string_tag_symbol, symbolToStringTag, Symbol.toStringTag) \
V(unscopables_symbol, symbolUnscopables, Symbol.unscopables)
__ pop(ecx); // Pop return address.
__ push(eax); // Push argument.
__ push(ecx); // Push return address.
- __ InvokeBuiltin(Context::TO_NUMBER_BUILTIN_INDEX, JUMP_FUNCTION);
+ __ TailCallRuntime(Runtime::kToNumber, 1, 1);
}
if (class_name == isolate_->heap()->String_string()) {
Handle<Object> value;
ASSIGN_RETURN_ON_EXCEPTION_VALUE(
- isolate_, value, Execution::ToString(isolate_, object), EXCEPTION);
+ isolate_, value, Object::ToString(isolate_, object), EXCEPTION);
SerializeString(Handle<String>::cast(value));
} else if (class_name == isolate_->heap()->Number_string()) {
Handle<Object> value;
ASSIGN_RETURN_ON_EXCEPTION_VALUE(
- isolate_, value, Execution::ToNumber(isolate_, object), EXCEPTION);
+ isolate_, value, Object::ToNumber(isolate_, object), EXCEPTION);
if (value->IsSmi()) return SerializeSmi(Smi::cast(*value));
SerializeHeapNumber(Handle<HeapNumber>::cast(value));
} else if (class_name == isolate_->heap()->Boolean_string()) {
macro TO_STRING_INLINE(arg) = (IS_STRING(%IS_VAR(arg)) ? arg : $nonStringToString(arg));
macro TO_NUMBER_INLINE(arg) = (IS_NUMBER(%IS_VAR(arg)) ? arg : $nonNumberToNumber(arg));
macro TO_OBJECT(arg) = (%_ToObject(arg));
+macro TO_PRIMITIVE(arg) = (%_ToPrimitive(arg));
+macro TO_PRIMITIVE_NUMBER(arg) = (%_ToPrimitive_Number(arg));
+macro TO_PRIMITIVE_STRING(arg) = (%_ToPrimitive_String(arg));
macro JSON_NUMBER_TO_STRING(arg) = ((%_IsSmi(%IS_VAR(arg)) || arg - arg == 0) ? %_NumberToString(arg) : "null");
macro HAS_OWN_PROPERTY(arg, index) = (%_CallFunction(arg, index, ObjectHasOwnProperty));
macro SHOULD_CREATE_WRAPPER(functionName, receiver) = (!IS_SPEC_OBJECT(receiver) && %IsSloppyModeFunction(functionName));
String);
if (obj->IsUndefined()) return default_value;
if (!obj->IsString()) {
- ASSIGN_RETURN_ON_EXCEPTION(isolate, obj, Execution::ToString(isolate, obj),
+ ASSIGN_RETURN_ON_EXCEPTION(isolate, obj, Object::ToString(isolate, obj),
String);
}
return Handle<String>::cast(obj);
"Offset is outside the bounds of the DataView") \
T(InvalidDataViewLength, "Invalid data view length") \
T(InvalidDataViewOffset, "Start offset is outside the bounds of the buffer") \
+ T(InvalidHint, "Invalid hint: %") \
T(InvalidLanguageTag, "Invalid language tag: %") \
T(InvalidWeakMapKey, "Invalid value used as weak map key") \
T(InvalidWeakSetValue, "Invalid value used in weak set") \
__ bind(¬_oddball);
__ push(a0); // Push argument.
- __ InvokeBuiltin(Context::TO_NUMBER_BUILTIN_INDEX, JUMP_FUNCTION);
+ __ TailCallRuntime(Runtime::kToNumber, 1, 1);
}
__ bind(¬_oddball);
__ push(a0); // Push argument.
- __ InvokeBuiltin(Context::TO_NUMBER_BUILTIN_INDEX, JUMP_FUNCTION);
+ __ TailCallRuntime(Runtime::kToNumber, 1, 1);
}
}
+// static
MaybeHandle<JSReceiver> Object::ToObject(Isolate* isolate,
Handle<Object> object) {
return ToObject(
}
+// static
+MaybeHandle<Name> Object::ToName(Isolate* isolate, Handle<Object> input) {
+ if (input->IsName()) return Handle<Name>::cast(input);
+ return ToString(isolate, input);
+}
+
+
+// static
+MaybeHandle<Object> Object::ToPrimitive(Handle<Object> input,
+ ToPrimitiveHint hint) {
+ if (input->IsPrimitive()) return input;
+ return JSReceiver::ToPrimitive(Handle<JSReceiver>::cast(input), hint);
+}
+
+
bool Object::HasSpecificClassOf(String* name) {
return this->IsJSObject() && (JSObject::cast(this)->class_name() == name);
}
}
-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);
}
}
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;
}
}
+// 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()) {
(*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) &&
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.
}
+// 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)
+ ? 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).
}
+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();
};
+// Valid hints for the abstract operation ToPrimitive,
+// implemented according to ES6, section 7.1.1.
+enum class ToPrimitiveHint { kDefault, kNumber, kString };
+
+
enum TypeofMode { INSIDE_TYPEOF, NOT_INSIDE_TYPEOF };
MUST_USE_RESULT static MaybeHandle<JSReceiver> ToObject(
Isolate* isolate, Handle<Object> object, Handle<Context> context);
- // Convert to a Name if needed.
- MUST_USE_RESULT static MaybeHandle<Name> ToName(Isolate* isolate,
- Handle<Object> object);
+ // ES6 section 7.1.14 ToPropertyKey
+ MUST_USE_RESULT static inline MaybeHandle<Name> ToName(Isolate* isolate,
+ Handle<Object> input);
+
+ // ES6 section 7.1.1 ToPrimitive
+ MUST_USE_RESULT static inline MaybeHandle<Object> ToPrimitive(
+ Handle<Object> input, ToPrimitiveHint hint = ToPrimitiveHint::kDefault);
+
+ // ES6 section 7.1.3 ToNumber
+ MUST_USE_RESULT static MaybeHandle<Object> ToNumber(Isolate* isolate,
+ Handle<Object> input);
+
+ // ES6 section 7.1.12 ToString
+ MUST_USE_RESULT static MaybeHandle<String> ToString(Isolate* isolate,
+ Handle<Object> input);
+
+ // ES6 section 7.3.9 GetMethod
+ MUST_USE_RESULT static MaybeHandle<Object> GetMethod(
+ Handle<JSReceiver> receiver, Handle<Name> name);
MUST_USE_RESULT static MaybeHandle<Object> GetProperty(
LookupIterator* it, LanguageMode language_mode = SLOPPY);
DECLARE_PRINTER(Simd128Value)
DECLARE_VERIFIER(Simd128Value)
+ static Handle<String> ToString(Handle<Simd128Value> input);
+
// Equality operations.
inline bool Equals(Simd128Value* that);
\
DECLARE_PRINTER(Type) \
\
+ static Handle<String> ToString(Handle<Type> input); \
+ \
inline bool Equals(Type* that); \
\
private: \
public:
DECLARE_CAST(JSReceiver)
+ // ES6 section 7.1.1 ToPrimitive
+ MUST_USE_RESULT static MaybeHandle<Object> ToPrimitive(
+ Handle<JSReceiver> receiver,
+ ToPrimitiveHint hint = ToPrimitiveHint::kDefault);
+ MUST_USE_RESULT static MaybeHandle<Object> OrdinaryToPrimitive(
+ Handle<JSReceiver> receiver, Handle<String> hint);
+
// Implementation of [[HasProperty]], ECMA-262 5th edition, section 8.12.6.
MUST_USE_RESULT static inline Maybe<bool> HasProperty(
Handle<JSReceiver> object, Handle<Name> name);
// to this method are not efficient unless the string is flat.
INLINE(uint16_t Get(int index));
+ // ES6 section 7.1.3.1 ToNumber Applied to the String Type
+ static Handle<Object> ToNumber(Handle<String> subject);
+
// Flattens the string. Checks first inline to see if it is
// necessary. Does nothing if the string is not a cons string.
// Flattening allocates a sequential string with the same data as
__ bind(¬_oddball);
__ push(r3); // Push argument.
- __ InvokeBuiltin(Context::TO_NUMBER_BUILTIN_INDEX, JUMP_FUNCTION);
+ __ TailCallRuntime(Runtime::kToNumber, 1, 1);
}
// The following declarations are shared with other native JS files.
// They are all declared at this one spot to avoid redeclaration errors.
-var $defaultNumber;
var $defaultString;
var $NaN;
var $nonNumberToNumber;
// ----------------------------------------------------------------------------
// Exports
-$defaultNumber = DefaultNumber;
$defaultString = DefaultString;
$NaN = %GetRootNaN();
$nonNumberToNumber = NonNumberToNumber;
"sub_builtin", SUB,
"sub_strong_builtin", SUB_STRONG,
"to_name_builtin", TO_NAME,
- "to_number_builtin", TO_NUMBER,
"to_string_builtin", TO_STRING,
]);
Handle<Object> value;
ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, value,
- Execution::ToNumber(isolate, date));
+ Object::ToNumber(isolate, date));
icu::SimpleDateFormat* date_format =
DateFormat::UnpackDateFormat(isolate, date_format_holder);
Handle<Object> value;
ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, value,
- Execution::ToNumber(isolate, number));
+ Object::ToNumber(isolate, number));
icu::DecimalFormat* number_format =
NumberFormat::UnpackNumberFormat(isolate, number_format_holder);
}
-static 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;
-}
-
-
-static 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;
-}
-
-
RUNTIME_FUNCTION(Runtime_StringToNumber) {
HandleScope handle_scope(isolate);
- DCHECK(args.length() == 1);
+ DCHECK_EQ(1, args.length());
CONVERT_ARG_HANDLE_CHECKED(String, subject, 0);
- subject = String::Flatten(subject);
-
- // Fast case: short integer or some sorts of junk values.
- if (subject->IsSeqOneByteString()) {
- int len = subject->length();
- if (len == 0) return Smi::FromInt(0);
-
- 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->heap()->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->heap()->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->heap()->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 Smi::FromInt(d);
- }
- }
-
- // Slower case.
- int flags = ALLOW_HEX | ALLOW_OCTAL | ALLOW_BINARY;
- return *isolate->factory()->NewNumber(
- StringToDouble(isolate->unicode_cache(), subject, flags));
+ return *String::ToNumber(subject);
}
}
+RUNTIME_FUNCTION(Runtime_ToPrimitive) {
+ HandleScope scope(isolate);
+ DCHECK_EQ(1, args.length());
+ CONVERT_ARG_HANDLE_CHECKED(Object, input, 0);
+ Handle<Object> result;
+ ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, result,
+ Object::ToPrimitive(input));
+ return *result;
+}
+
+
+RUNTIME_FUNCTION(Runtime_ToPrimitive_Number) {
+ HandleScope scope(isolate);
+ DCHECK_EQ(1, args.length());
+ CONVERT_ARG_HANDLE_CHECKED(Object, input, 0);
+ Handle<Object> result;
+ ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
+ isolate, result, Object::ToPrimitive(input, ToPrimitiveHint::kNumber));
+ return *result;
+}
+
+
+RUNTIME_FUNCTION(Runtime_ToPrimitive_String) {
+ HandleScope scope(isolate);
+ DCHECK_EQ(1, args.length());
+ CONVERT_ARG_HANDLE_CHECKED(Object, input, 0);
+ Handle<Object> result;
+ ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
+ isolate, result, Object::ToPrimitive(input, ToPrimitiveHint::kString));
+ return *result;
+}
+
+
+RUNTIME_FUNCTION(Runtime_OrdinaryToPrimitive) {
+ HandleScope scope(isolate);
+ DCHECK_EQ(2, args.length());
+ CONVERT_ARG_HANDLE_CHECKED(JSReceiver, receiver, 0);
+ CONVERT_ARG_HANDLE_CHECKED(String, hint, 1);
+ Handle<Object> result;
+ ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
+ isolate, result, JSReceiver::OrdinaryToPrimitive(receiver, hint));
+ return *result;
+}
+
+
+RUNTIME_FUNCTION(Runtime_ToNumber) {
+ HandleScope scope(isolate);
+ DCHECK_EQ(1, args.length());
+ CONVERT_ARG_HANDLE_CHECKED(Object, input, 0);
+ Handle<Object> result;
+ ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, result,
+ Object::ToNumber(isolate, input));
+ return *result;
+}
+
+
RUNTIME_FUNCTION(Runtime_StrictEquals) {
SealHandleScope scope(isolate);
DCHECK_EQ(2, args.length());
// Convert the key to a string.
Handle<Object> converted;
ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, converted,
- Execution::ToString(isolate, raw_key));
+ Object::ToString(isolate, raw_key));
Handle<String> key = Handle<String>::cast(converted);
// Try to convert the string key into an array index.
F(DefineGetterPropertyUnchecked, 4, 1) \
F(DefineSetterPropertyUnchecked, 4, 1) \
F(ToObject, 1, 1) \
+ F(ToPrimitive, 1, 1) \
+ F(ToPrimitive_Number, 1, 1) \
+ F(ToPrimitive_String, 1, 1) \
+ F(OrdinaryToPrimitive, 2, 1) \
+ F(ToNumber, 1, 1) \
F(StrictEquals, 2, 1) \
F(InstanceOf, 2, 1) \
F(HasInPrototypeChain, 2, 1)
// - symbolIsConcatSpreadable
// - symbolIsRegExp
// - symbolIterator
+// - symbolToPrimitive
// - symbolToStringTag
// - symbolUnscopables
}
+// 19.4.3.4 Symbol.prototype [ @@toPrimitive ] ( hint )
+function SymbolToPrimitive(hint) {
+ if (!(IS_SYMBOL(this) || IS_SYMBOL_WRAPPER(this))) {
+ throw MakeTypeError(kIncompatibleMethodReceiver,
+ "Symbol.prototype [ @@toPrimitive ]", this);
+ }
+ return %_ValueOf(this);
+}
+
+
function SymbolToString() {
if (!(IS_SYMBOL(this) || IS_SYMBOL_WRAPPER(this))) {
throw MakeTypeError(kIncompatibleMethodReceiver,
// "isConcatSpreadable", symbolIsConcatSpreadable,
// "isRegExp", symbolIsRegExp,
"iterator", symbolIterator,
+ "toPrimitive", symbolToPrimitive,
// TODO(dslomov, caitp): Currently defined in harmony-tostring.js ---
// Move here when shipping
// "toStringTag", symbolToStringTag,
%AddNamedProperty(
GlobalSymbol.prototype, "constructor", GlobalSymbol, DONT_ENUM);
+utils.SetFunctionName(SymbolToPrimitive, symbolToPrimitive);
+%AddNamedProperty(
+ GlobalSymbol.prototype, symbolToPrimitive, SymbolToPrimitive,
+ DONT_ENUM | READ_ONLY);
%AddNamedProperty(
GlobalSymbol.prototype, symbolToStringTag, "Symbol", DONT_ENUM | READ_ONLY);
__ PopReturnAddressTo(rcx); // Pop return address.
__ Push(rax); // Push argument.
__ PushReturnAddressFrom(rcx); // Push return address.
- __ InvokeBuiltin(Context::TO_NUMBER_BUILTIN_INDEX, JUMP_FUNCTION);
+ __ TailCallRuntime(Runtime::kToNumber, 1, 1);
}
__ pop(ecx); // Pop return address.
__ push(eax); // Push argument.
__ push(ecx); // Push return address.
- __ InvokeBuiltin(Context::TO_NUMBER_BUILTIN_INDEX, JUMP_FUNCTION);
+ __ TailCallRuntime(Runtime::kToNumber, 1, 1);
}
static void CheckOddball(Isolate* isolate, Object* obj, const char* string) {
CHECK(obj->IsOddball());
Handle<Object> handle(obj, isolate);
- Object* print_string =
- *Execution::ToString(isolate, handle).ToHandleChecked();
+ Object* print_string = *Object::ToString(isolate, handle).ToHandleChecked();
CHECK(String::cast(print_string)->IsUtf8EqualTo(CStrVector(string)));
}
static void CheckSmi(Isolate* isolate, int value, const char* string) {
Handle<Object> handle(Smi::FromInt(value), isolate);
- Object* print_string =
- *Execution::ToString(isolate, handle).ToHandleChecked();
+ Object* print_string = *Object::ToString(isolate, handle).ToHandleChecked();
CHECK(String::cast(print_string)->IsUtf8EqualTo(CStrVector(string)));
}
Handle<Object> number = isolate->factory()->NewNumber(value);
CHECK(number->IsNumber());
Handle<Object> print_string =
- Execution::ToString(isolate, number).ToHandleChecked();
+ Object::ToString(isolate, number).ToHandleChecked();
CHECK(String::cast(*print_string)->IsUtf8EqualTo(CStrVector(string)));
}
--- /dev/null
+// Copyright 2015 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// Flags: --allow-natives-syntax
+
+assertEquals(1, %ToNumber(1));
+assertEquals(1, %_ToNumber(1));
+
+assertEquals(.5, %ToNumber(.5));
+assertEquals(.5, %_ToNumber(.5));
+
+assertEquals(0, %ToNumber(null));
+assertEquals(0, %_ToNumber(null));
+
+assertEquals(1, %ToNumber(true));
+assertEquals(1, %_ToNumber(true));
+
+assertEquals(0, %ToNumber(false));
+assertEquals(0, %_ToNumber(false));
+
+assertEquals(NaN, %ToNumber(undefined));
+assertEquals(NaN, %_ToNumber(undefined));
+
+assertEquals(-1, %ToNumber("-1"));
+assertEquals(-1, %_ToNumber("-1"));
+assertEquals(123, %ToNumber("123"));
+assertEquals(123, %_ToNumber("123"));
+assertEquals(NaN, %ToNumber("random text"));
+assertEquals(NaN, %_ToNumber("random text"));
+
+assertThrows(function() { %ToNumber(Symbol.toPrimitive) }, TypeError);
+assertThrows(function() { %_ToNumber(Symbol.toPrimitive) }, TypeError);
+
+var a = { toString: function() { return 54321 }};
+assertEquals(54321, %ToNumber(a));
+assertEquals(54321, %_ToNumber(a));
+
+var b = { valueOf: function() { return 42 }};
+assertEquals(42, %ToNumber(b));
+assertEquals(42, %_ToNumber(b));
+
+var c = {
+ toString: function() { return "x"},
+ valueOf: function() { return 123 }
+};
+assertEquals(123, %ToNumber(c));
+assertEquals(123, %_ToNumber(c));
+
+var d = {
+ [Symbol.toPrimitive]: function(hint) {
+ assertEquals("number", hint);
+ return 987654321;
+ }
+};
+assertEquals(987654321, %ToNumber(d));
+assertEquals(987654321, %_ToNumber(d));
--- /dev/null
+// Copyright 2015 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// Flags: --allow-natives-syntax
+
+assertEquals(1, %ToPrimitive(1));
+assertEquals(1, %ToPrimitive_Number(1));
+assertEquals(1, %ToPrimitive_String(1));
+assertEquals(1, %_ToPrimitive(1));
+assertEquals(1, %_ToPrimitive_Number(1));
+assertEquals(1, %_ToPrimitive_String(1));
+
+assertEquals(.5, %ToPrimitive(.5));
+assertEquals(.5, %ToPrimitive_Number(.5));
+assertEquals(.5, %ToPrimitive_String(.5));
+assertEquals(.5, %_ToPrimitive(.5));
+assertEquals(.5, %_ToPrimitive_Number(.5));
+assertEquals(.5, %_ToPrimitive_String(.5));
+
+assertEquals(null, %ToPrimitive(null));
+assertEquals(null, %ToPrimitive_Number(null));
+assertEquals(null, %ToPrimitive_String(null));
+assertEquals(null, %_ToPrimitive(null));
+assertEquals(null, %_ToPrimitive_Number(null));
+assertEquals(null, %_ToPrimitive_String(null));
+
+assertEquals(true, %ToPrimitive(true));
+assertEquals(true, %ToPrimitive_Number(true));
+assertEquals(true, %ToPrimitive_String(true));
+assertEquals(true, %_ToPrimitive(true));
+assertEquals(true, %_ToPrimitive_Number(true));
+assertEquals(true, %_ToPrimitive_String(true));
+
+assertEquals(false, %ToPrimitive(false));
+assertEquals(false, %ToPrimitive_Number(false));
+assertEquals(false, %ToPrimitive_String(false));
+assertEquals(false, %_ToPrimitive(false));
+assertEquals(false, %_ToPrimitive_Number(false));
+assertEquals(false, %_ToPrimitive_String(false));
+
+assertEquals(undefined, %ToPrimitive(undefined));
+assertEquals(undefined, %ToPrimitive_Number(undefined));
+assertEquals(undefined, %ToPrimitive_String(undefined));
+assertEquals(undefined, %_ToPrimitive(undefined));
+assertEquals(undefined, %_ToPrimitive_Number(undefined));
+assertEquals(undefined, %_ToPrimitive_String(undefined));
+
+assertEquals("random text", %ToPrimitive("random text"));
+assertEquals("random text", %ToPrimitive_Number("random text"));
+assertEquals("random text", %ToPrimitive_String("random text"));
+assertEquals("random text", %_ToPrimitive("random text"));
+assertEquals("random text", %_ToPrimitive_Number("random text"));
+assertEquals("random text", %_ToPrimitive_String("random text"));
+
+assertEquals(Symbol.toPrimitive, %ToPrimitive(Symbol.toPrimitive));
+assertEquals(Symbol.toPrimitive, %ToPrimitive_Number(Symbol.toPrimitive));
+assertEquals(Symbol.toPrimitive, %ToPrimitive_String(Symbol.toPrimitive));
+assertEquals(Symbol.toPrimitive, %_ToPrimitive(Symbol.toPrimitive));
+assertEquals(Symbol.toPrimitive, %_ToPrimitive_Number(Symbol.toPrimitive));
+assertEquals(Symbol.toPrimitive, %_ToPrimitive_String(Symbol.toPrimitive));
+
+var a = { toString: function() { return "xyz" }};
+assertEquals("xyz", %ToPrimitive(a));
+assertEquals("xyz", %ToPrimitive_Number(a));
+assertEquals("xyz", %ToPrimitive_String(a));
+assertEquals("xyz", %_ToPrimitive(a));
+assertEquals("xyz", %_ToPrimitive_Number(a));
+assertEquals("xyz", %_ToPrimitive_String(a));
+assertEquals("xyz", %OrdinaryToPrimitive(a, "number"));
+assertEquals("xyz", %OrdinaryToPrimitive(a, "string"));
+assertEquals("xyz", %_OrdinaryToPrimitive(a, "number"));
+assertEquals("xyz", %_OrdinaryToPrimitive(a, "string"));
+
+var b = { valueOf: function() { return 42 }};
+assertEquals(42, %ToPrimitive(b));
+assertEquals(42, %ToPrimitive_Number(b));
+assertEquals("[object Object]", %ToPrimitive_String(b));
+assertEquals(42, %_ToPrimitive(b));
+assertEquals(42, %_ToPrimitive_Number(b));
+assertEquals("[object Object]", %_ToPrimitive_String(b));
+assertEquals(42, %OrdinaryToPrimitive(b, "number"));
+assertEquals("[object Object]", %OrdinaryToPrimitive(b, "string"));
+assertEquals(42, %_OrdinaryToPrimitive(b, "number"));
+assertEquals("[object Object]", %_OrdinaryToPrimitive(b, "string"));
+
+var c = {
+ toString: function() { return "x"},
+ valueOf: function() { return 123 }
+};
+assertEquals(123, %ToPrimitive(c));
+assertEquals(123, %ToPrimitive_Number(c));
+assertEquals("x", %ToPrimitive_String(c));
+assertEquals(123, %_ToPrimitive(c));
+assertEquals(123, %_ToPrimitive_Number(c));
+assertEquals("x", %_ToPrimitive_String(c));
+assertEquals(123, %OrdinaryToPrimitive(c, "number"));
+assertEquals("x", %OrdinaryToPrimitive(c, "string"));
+assertEquals(123, %_OrdinaryToPrimitive(c, "number"));
+assertEquals("x", %_OrdinaryToPrimitive(c, "string"));
+
+var d = {
+ [Symbol.toPrimitive]: function(hint) { return hint }
+};
+assertEquals("default", %ToPrimitive(d));
+assertEquals("number", %ToPrimitive_Number(d));
+assertEquals("string", %ToPrimitive_String(d));
+assertEquals("default", %_ToPrimitive(d));
+assertEquals("number", %_ToPrimitive_Number(d));
+assertEquals("string", %_ToPrimitive_String(d));