Fix some usage of "this" in builtins
authorsgjesse@chromium.org <sgjesse@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Tue, 19 Jan 2010 14:15:47 +0000 (14:15 +0000)
committersgjesse@chromium.org <sgjesse@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Tue, 19 Jan 2010 14:15:47 +0000 (14:15 +0000)
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

src/arm/codegen-arm.cc
src/arm/codegen-arm.h
src/codegen.cc
src/ia32/codegen-ia32.cc
src/ia32/codegen-ia32.h
src/macros.py
src/runtime.js
src/v8natives.js
src/x64/codegen-x64.cc
src/x64/codegen-x64.h
test/mjsunit/value-wrapper.js

index 0c1dbcc..1dac4cc 100644 (file)
@@ -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) {
   VirtualFrame::SpilledScope spilled_scope;
   ASSERT(args->length() == 0);
index f5de0eb..5f132bd 100644 (file)
@@ -341,6 +341,7 @@ class CodeGenerator: public AstVisitor {
   void GenerateIsArray(ZoneList<Expression*>* args);
   void GenerateIsObject(ZoneList<Expression*>* args);
   void GenerateIsFunction(ZoneList<Expression*>* args);
+  void GenerateIsUndetectableObject(ZoneList<Expression*>* args);
 
   // Support for construct call checks.
   void GenerateIsConstructCall(ZoneList<Expression*>* args);
index fd7e0e8..3620e22 100644 (file)
@@ -344,6 +344,7 @@ CodeGenerator::InlineRuntimeLUT CodeGenerator::kInlineRuntimeLUT[] = {
   {&CodeGenerator::GenerateRandomPositiveSmi, "_RandomPositiveSmi"},
   {&CodeGenerator::GenerateIsObject, "_IsObject"},
   {&CodeGenerator::GenerateIsFunction, "_IsFunction"},
+  {&CodeGenerator::GenerateIsUndetectableObject, "_IsUndetectableObject"},
   {&CodeGenerator::GenerateStringAdd, "_StringAdd"},
   {&CodeGenerator::GenerateSubString, "_SubString"},
   {&CodeGenerator::GenerateStringCompare, "_StringCompare"},
index 240f4da..37b8acd 100644 (file)
@@ -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) {
   ASSERT(args->length() == 0);
 
index 56cf978..d2288f7 100644 (file)
@@ -517,6 +517,7 @@ class CodeGenerator: public AstVisitor {
   void GenerateIsArray(ZoneList<Expression*>* args);
   void GenerateIsObject(ZoneList<Expression*>* args);
   void GenerateIsFunction(ZoneList<Expression*>* args);
+  void GenerateIsUndetectableObject(ZoneList<Expression*>* args);
 
   // Support for construct call checks.
   void GenerateIsConstructCall(ZoneList<Expression*>* args);
index 1e436a0..c160b49 100644 (file)
@@ -92,6 +92,7 @@ macro IS_ERROR(arg)             = (%_ClassOf(arg) === 'Error');
 macro IS_SCRIPT(arg)            = (%_ClassOf(arg) === 'Script');
 macro IS_ARGUMENTS(arg)         = (%_ClassOf(arg) === 'Arguments');
 macro IS_GLOBAL(arg)            = (%_ClassOf(arg) === 'global');
+macro IS_UNDETECTABLE(arg)      = (%_IsUndetectableObject(arg));
 macro FLOOR(arg)                = $floor(arg);
 
 # Inline macros. Use %IS_VAR to make sure arg is evaluated only once.
index ce2f197..c4c855e 100644 (file)
@@ -541,7 +541,9 @@ function ToObject(x) {
   if (IS_STRING(x)) return new $String(x);
   if (IS_NUMBER(x)) return new $Number(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;
 }
 
index 3dcf430..7475065 100644 (file)
@@ -197,7 +197,7 @@ $Object.prototype.constructor = $Object;
 
 // ECMA-262 - 15.2.4.2
 function ObjectToString() {
-  return "[object " + %_ClassOf(this) + "]";
+  return "[object " + %_ClassOf(ToObject(this)) + "]";
 }
 
 
@@ -209,7 +209,7 @@ function ObjectToLocaleString() {
 
 // ECMA-262 - 15.2.4.4
 function ObjectValueOf() {
-  return this;
+  return ToObject(this);
 }
 
 
index 0cf68eb..3dcb75e 100644 (file)
@@ -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) {
   ASSERT(args->length() == 0);
 
index 50bb023..deff71c 100644 (file)
@@ -514,6 +514,7 @@ class CodeGenerator: public AstVisitor {
   void GenerateIsArray(ZoneList<Expression*>* args);
   void GenerateIsObject(ZoneList<Expression*>* args);
   void GenerateIsFunction(ZoneList<Expression*>* args);
+  void GenerateIsUndetectableObject(ZoneList<Expression*>* args);
 
   // Support for construct call checks.
   void GenerateIsConstructCall(ZoneList<Expression*>* args);
index 33ef013..88330b4 100644 (file)
@@ -28,6 +28,9 @@
 // When calling user-defined functions on strings, booleans or
 // 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() {
   for (var i = 0; i < 10; i++) {
     assertEquals('object', 'xxx'.TypeOfThis());
@@ -77,6 +80,22 @@ function RunTests() {
     assertEquals('object', (42)[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; }
@@ -87,7 +106,14 @@ Boolean.prototype.TypeOfThis = TypeOfThis;
 Number.prototype.TypeOfThis = TypeOfThis;
 Boolean.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();