Commit 67f9e191 authored by sgjesse@chromium.org's avatar sgjesse@chromium.org

Fix some usage of "this" in builtins

The implementation of Object.prototype.valueOf and Object.prototype.toString now calls ToObject on "this" as mandated by the spec.
Review URL: http://codereview.chromium.org/542112

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@3651 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
parent 73390e61
...@@ -3470,6 +3470,20 @@ void CodeGenerator::GenerateIsFunction(ZoneList<Expression*>* args) { ...@@ -3470,6 +3470,20 @@ void CodeGenerator::GenerateIsFunction(ZoneList<Expression*>* args) {
} }
void CodeGenerator::GenerateIsUndetectableObject(ZoneList<Expression*>* args) {
VirtualFrame::SpilledScope spilled_scope;
ASSERT(args->length() == 1);
LoadAndSpill(args->at(0));
frame_->EmitPop(r0);
__ tst(r0, Operand(kSmiTagMask));
false_target()->Branch(eq);
__ ldr(r1, FieldMemOperand(r0, HeapObject::kMapOffset));
__ ldrb(r1, FieldMemOperand(r1, Map::kBitFieldOffset));
__ tst(r1, Operand(1 << Map::kIsUndetectable));
cc_reg_ = ne;
}
void CodeGenerator::GenerateIsConstructCall(ZoneList<Expression*>* args) { void CodeGenerator::GenerateIsConstructCall(ZoneList<Expression*>* args) {
VirtualFrame::SpilledScope spilled_scope; VirtualFrame::SpilledScope spilled_scope;
ASSERT(args->length() == 0); ASSERT(args->length() == 0);
......
...@@ -341,6 +341,7 @@ class CodeGenerator: public AstVisitor { ...@@ -341,6 +341,7 @@ class CodeGenerator: public AstVisitor {
void GenerateIsArray(ZoneList<Expression*>* args); void GenerateIsArray(ZoneList<Expression*>* args);
void GenerateIsObject(ZoneList<Expression*>* args); void GenerateIsObject(ZoneList<Expression*>* args);
void GenerateIsFunction(ZoneList<Expression*>* args); void GenerateIsFunction(ZoneList<Expression*>* args);
void GenerateIsUndetectableObject(ZoneList<Expression*>* args);
// Support for construct call checks. // Support for construct call checks.
void GenerateIsConstructCall(ZoneList<Expression*>* args); void GenerateIsConstructCall(ZoneList<Expression*>* args);
......
...@@ -344,6 +344,7 @@ CodeGenerator::InlineRuntimeLUT CodeGenerator::kInlineRuntimeLUT[] = { ...@@ -344,6 +344,7 @@ CodeGenerator::InlineRuntimeLUT CodeGenerator::kInlineRuntimeLUT[] = {
{&CodeGenerator::GenerateRandomPositiveSmi, "_RandomPositiveSmi"}, {&CodeGenerator::GenerateRandomPositiveSmi, "_RandomPositiveSmi"},
{&CodeGenerator::GenerateIsObject, "_IsObject"}, {&CodeGenerator::GenerateIsObject, "_IsObject"},
{&CodeGenerator::GenerateIsFunction, "_IsFunction"}, {&CodeGenerator::GenerateIsFunction, "_IsFunction"},
{&CodeGenerator::GenerateIsUndetectableObject, "_IsUndetectableObject"},
{&CodeGenerator::GenerateStringAdd, "_StringAdd"}, {&CodeGenerator::GenerateStringAdd, "_StringAdd"},
{&CodeGenerator::GenerateSubString, "_SubString"}, {&CodeGenerator::GenerateSubString, "_SubString"},
{&CodeGenerator::GenerateStringCompare, "_StringCompare"}, {&CodeGenerator::GenerateStringCompare, "_StringCompare"},
......
...@@ -5183,6 +5183,26 @@ void CodeGenerator::GenerateIsFunction(ZoneList<Expression*>* args) { ...@@ -5183,6 +5183,26 @@ void CodeGenerator::GenerateIsFunction(ZoneList<Expression*>* args) {
} }
void CodeGenerator::GenerateIsUndetectableObject(ZoneList<Expression*>* args) {
ASSERT(args->length() == 1);
Load(args->at(0));
Result obj = frame_->Pop();
obj.ToRegister();
__ test(obj.reg(), Immediate(kSmiTagMask));
destination()->false_target()->Branch(zero);
Result temp = allocator()->Allocate();
ASSERT(temp.is_valid());
__ mov(temp.reg(),
FieldOperand(obj.reg(), HeapObject::kMapOffset));
__ movzx_b(temp.reg(),
FieldOperand(temp.reg(), Map::kBitFieldOffset));
__ test(temp.reg(), Immediate(1 << Map::kIsUndetectable));
obj.Unuse();
temp.Unuse();
destination()->Split(not_zero);
}
void CodeGenerator::GenerateIsConstructCall(ZoneList<Expression*>* args) { void CodeGenerator::GenerateIsConstructCall(ZoneList<Expression*>* args) {
ASSERT(args->length() == 0); ASSERT(args->length() == 0);
......
...@@ -517,6 +517,7 @@ class CodeGenerator: public AstVisitor { ...@@ -517,6 +517,7 @@ class CodeGenerator: public AstVisitor {
void GenerateIsArray(ZoneList<Expression*>* args); void GenerateIsArray(ZoneList<Expression*>* args);
void GenerateIsObject(ZoneList<Expression*>* args); void GenerateIsObject(ZoneList<Expression*>* args);
void GenerateIsFunction(ZoneList<Expression*>* args); void GenerateIsFunction(ZoneList<Expression*>* args);
void GenerateIsUndetectableObject(ZoneList<Expression*>* args);
// Support for construct call checks. // Support for construct call checks.
void GenerateIsConstructCall(ZoneList<Expression*>* args); void GenerateIsConstructCall(ZoneList<Expression*>* args);
......
...@@ -92,6 +92,7 @@ macro IS_ERROR(arg) = (%_ClassOf(arg) === 'Error'); ...@@ -92,6 +92,7 @@ macro IS_ERROR(arg) = (%_ClassOf(arg) === 'Error');
macro IS_SCRIPT(arg) = (%_ClassOf(arg) === 'Script'); macro IS_SCRIPT(arg) = (%_ClassOf(arg) === 'Script');
macro IS_ARGUMENTS(arg) = (%_ClassOf(arg) === 'Arguments'); macro IS_ARGUMENTS(arg) = (%_ClassOf(arg) === 'Arguments');
macro IS_GLOBAL(arg) = (%_ClassOf(arg) === 'global'); macro IS_GLOBAL(arg) = (%_ClassOf(arg) === 'global');
macro IS_UNDETECTABLE(arg) = (%_IsUndetectableObject(arg));
macro FLOOR(arg) = $floor(arg); macro FLOOR(arg) = $floor(arg);
# Inline macros. Use %IS_VAR to make sure arg is evaluated only once. # Inline macros. Use %IS_VAR to make sure arg is evaluated only once.
......
...@@ -541,7 +541,9 @@ function ToObject(x) { ...@@ -541,7 +541,9 @@ function ToObject(x) {
if (IS_STRING(x)) return new $String(x); if (IS_STRING(x)) return new $String(x);
if (IS_NUMBER(x)) return new $Number(x); if (IS_NUMBER(x)) return new $Number(x);
if (IS_BOOLEAN(x)) return new $Boolean(x); if (IS_BOOLEAN(x)) return new $Boolean(x);
if (x == null) throw %MakeTypeError('null_to_object', []); if (IS_NULL_OR_UNDEFINED(x) && !IS_UNDETECTABLE(x)) {
throw %MakeTypeError('null_to_object', []);
}
return x; return x;
} }
......
...@@ -197,7 +197,7 @@ $Object.prototype.constructor = $Object; ...@@ -197,7 +197,7 @@ $Object.prototype.constructor = $Object;
// ECMA-262 - 15.2.4.2 // ECMA-262 - 15.2.4.2
function ObjectToString() { function ObjectToString() {
return "[object " + %_ClassOf(this) + "]"; return "[object " + %_ClassOf(ToObject(this)) + "]";
} }
...@@ -209,7 +209,7 @@ function ObjectToLocaleString() { ...@@ -209,7 +209,7 @@ function ObjectToLocaleString() {
// ECMA-262 - 15.2.4.4 // ECMA-262 - 15.2.4.4
function ObjectValueOf() { function ObjectValueOf() {
return this; return ToObject(this);
} }
......
...@@ -3622,6 +3622,22 @@ void CodeGenerator::GenerateIsFunction(ZoneList<Expression*>* args) { ...@@ -3622,6 +3622,22 @@ void CodeGenerator::GenerateIsFunction(ZoneList<Expression*>* args) {
} }
void CodeGenerator::GenerateIsUndetectableObject(ZoneList<Expression*>* args) {
ASSERT(args->length() == 1);
Load(args->at(0));
Result obj = frame_->Pop();
obj.ToRegister();
Condition is_smi = masm_->CheckSmi(obj.reg());
destination()->false_target()->Branch(is_smi);
__ movq(kScratchRegister, FieldOperand(obj.reg(), HeapObject::kMapOffset));
__ movzxbl(kScratchRegister,
FieldOperand(kScratchRegister, Map::kBitFieldOffset));
__ testl(kScratchRegister, Immediate(1 << Map::kIsUndetectable));
obj.Unuse();
destination()->Split(not_zero);
}
void CodeGenerator::GenerateIsConstructCall(ZoneList<Expression*>* args) { void CodeGenerator::GenerateIsConstructCall(ZoneList<Expression*>* args) {
ASSERT(args->length() == 0); ASSERT(args->length() == 0);
......
...@@ -514,6 +514,7 @@ class CodeGenerator: public AstVisitor { ...@@ -514,6 +514,7 @@ class CodeGenerator: public AstVisitor {
void GenerateIsArray(ZoneList<Expression*>* args); void GenerateIsArray(ZoneList<Expression*>* args);
void GenerateIsObject(ZoneList<Expression*>* args); void GenerateIsObject(ZoneList<Expression*>* args);
void GenerateIsFunction(ZoneList<Expression*>* args); void GenerateIsFunction(ZoneList<Expression*>* args);
void GenerateIsUndetectableObject(ZoneList<Expression*>* args);
// Support for construct call checks. // Support for construct call checks.
void GenerateIsConstructCall(ZoneList<Expression*>* args); void GenerateIsConstructCall(ZoneList<Expression*>* args);
......
...@@ -28,6 +28,9 @@ ...@@ -28,6 +28,9 @@
// When calling user-defined functions on strings, booleans or // When calling user-defined functions on strings, booleans or
// numbers, we should create a wrapper object. // numbers, we should create a wrapper object.
// When running the tests use loops to ensure that the call site moves through
// the different IC states and that both the runtime system and the generated
// IC code is tested.
function RunTests() { function RunTests() {
for (var i = 0; i < 10; i++) { for (var i = 0; i < 10; i++) {
assertEquals('object', 'xxx'.TypeOfThis()); assertEquals('object', 'xxx'.TypeOfThis());
...@@ -77,6 +80,22 @@ function RunTests() { ...@@ -77,6 +80,22 @@ function RunTests() {
assertEquals('object', (42)[7]()); assertEquals('object', (42)[7]());
assertEquals('object', (3.14)[7]()); assertEquals('object', (3.14)[7]());
} }
for (var i = 0; i < 10; i++) {
assertEquals('object', typeof 'xxx'.ObjectValueOf());
assertEquals('object', typeof true.ObjectValueOf());
assertEquals('object', typeof false.ObjectValueOf());
assertEquals('object', typeof (42).ObjectValueOf());
assertEquals('object', typeof (3.14).ObjectValueOf());
}
for (var i = 0; i < 10; i++) {
assertEquals('[object String]', 'xxx'.ObjectToString());
assertEquals('[object Boolean]', true.ObjectToString());
assertEquals('[object Boolean]', false.ObjectToString());
assertEquals('[object Number]', (42).ObjectToString());
assertEquals('[object Number]', (3.14).ObjectToString());
}
} }
function TypeOfThis() { return typeof this; } function TypeOfThis() { return typeof this; }
...@@ -87,7 +106,14 @@ Boolean.prototype.TypeOfThis = TypeOfThis; ...@@ -87,7 +106,14 @@ Boolean.prototype.TypeOfThis = TypeOfThis;
Number.prototype.TypeOfThis = TypeOfThis; Number.prototype.TypeOfThis = TypeOfThis;
Boolean.prototype[7] = TypeOfThis; Boolean.prototype[7] = TypeOfThis;
Number.prototype[7] = TypeOfThis; Number.prototype[7] = TypeOfThis;
String.prototype.ObjectValueOf = Object.prototype.valueOf;
Boolean.prototype.ObjectValueOf = Object.prototype.valueOf;
Number.prototype.ObjectValueOf = Object.prototype.valueOf;
String.prototype.ObjectToString = Object.prototype.toString;
Boolean.prototype.ObjectToString = Object.prototype.toString;
Number.prototype.ObjectToString = Object.prototype.toString;
RunTests(); RunTests();
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment