Add support for global variable references in toplevel code. We use
authorkmillikin@chromium.org <kmillikin@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Wed, 21 Oct 2009 09:38:21 +0000 (09:38 +0000)
committerkmillikin@chromium.org <kmillikin@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Wed, 21 Oct 2009 09:38:21 +0000 (09:38 +0000)
the normal named load IC mechanism for now.  Generated code is similar
to the case for global variable assignments.

Review URL: http://codereview.chromium.org/294021

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@3101 ce2b1a6d-e550-0410-aec6-3dcde31c8c00

src/arm/fast-codegen-arm.cc
src/compiler.cc
src/ia32/fast-codegen-ia32.cc
src/x64/fast-codegen-x64.cc
test/mjsunit/compiler/globals.js

index 49a2058..5f243a2 100644 (file)
@@ -185,11 +185,27 @@ void FastCodeGenerator::VisitFunctionLiteral(FunctionLiteral* expr) {
 void FastCodeGenerator::VisitVariableProxy(VariableProxy* expr) {
   Comment cmnt(masm_, "[ VariableProxy");
   Expression* rewrite = expr->var()->rewrite();
-  ASSERT(rewrite != NULL);
+  if (rewrite == NULL) {
+    Comment cmnt(masm_, "Global variable");
+    // Use inline caching. Variable name is passed in r2 and the global
+    // object on the stack.
+    __ ldr(ip, CodeGenerator::GlobalObject());
+    __ push(ip);
+    __ mov(r2, Operand(expr->name()));
+    Handle<Code> ic(Builtins::builtin(Builtins::LoadIC_Initialize));
+    __ Call(ic, RelocInfo::CODE_TARGET_CONTEXT);
+    if (expr->location().is_temporary()) {
+      // Replace the global object with the result.
+      __ str(r0, MemOperand(sp));
+    } else {
+      ASSERT(expr->location().is_nowhere());
+      __ pop();
+    }
 
-  Slot* slot = rewrite->AsSlot();
-  ASSERT(slot != NULL);
-  { Comment cmnt(masm_, "[ Slot");
+  } else {
+    Comment cmnt(masm_, "Stack slot");
+    Slot* slot = rewrite->AsSlot();
+    ASSERT(slot != NULL);
     if (expr->location().is_temporary()) {
       __ ldr(ip, MemOperand(fp, SlotOffset(slot)));
       __ push(ip);
index 57dc77d..bfa671d 100644 (file)
@@ -628,8 +628,7 @@ void CodeGenSelector::VisitSlot(Slot* expr) {
 
 void CodeGenSelector::VisitVariableProxy(VariableProxy* expr) {
   Expression* rewrite = expr->var()->rewrite();
-  if (rewrite == NULL) BAILOUT("global variable reference");
-  Visit(rewrite);
+  if (rewrite != NULL) Visit(rewrite);
 }
 
 
index 0c585e5..d78c31c 100644 (file)
@@ -172,11 +172,31 @@ void FastCodeGenerator::VisitFunctionLiteral(FunctionLiteral* expr) {
 void FastCodeGenerator::VisitVariableProxy(VariableProxy* expr) {
   Comment cmnt(masm_, "[ VariableProxy");
   Expression* rewrite = expr->var()->rewrite();
-  ASSERT(rewrite != NULL);
+  if (rewrite == NULL) {
+    Comment cmnt(masm_, "Global variable");
+    // Use inline caching. Variable name is passed in ecx and the global
+    // object on the stack.
+    __ push(CodeGenerator::GlobalObject());
+    __ mov(ecx, expr->name());
+    Handle<Code> ic(Builtins::builtin(Builtins::LoadIC_Initialize));
+    __ call(ic, RelocInfo::CODE_TARGET_CONTEXT);
+
+    // A test eax instruction following the call is used by the IC to
+    // indicate that the inobject property case was inlined.  Ensure there
+    // is no test eax instruction here.  Remember that the assembler may
+    // choose to do peephole optimization (eg, push/pop elimination).
+    if (expr->location().is_temporary()) {
+      // Replace the global object with the result.
+      __ mov(Operand(esp, 0), eax);
+    } else {
+      ASSERT(expr->location().is_nowhere());
+      __ pop(eax);
+    }
 
-  Slot* slot = rewrite->AsSlot();
-  ASSERT(slot != NULL);
-  { Comment cmnt(masm_, "[ Slot");
+  } else {
+    Comment cmnt(masm_, "Stack slot");
+    Slot* slot = rewrite->AsSlot();
+    ASSERT(slot != NULL);
     if (expr->location().is_temporary()) {
       __ push(Operand(ebp, SlotOffset(slot)));
     } else {
index 34851aa..e7a9e88 100644 (file)
@@ -189,11 +189,30 @@ void FastCodeGenerator::VisitFunctionLiteral(FunctionLiteral* expr) {
 void FastCodeGenerator::VisitVariableProxy(VariableProxy* expr) {
   Comment cmnt(masm_, "[ VariableProxy");
   Expression* rewrite = expr->var()->rewrite();
-  ASSERT(rewrite != NULL);
+  if (rewrite == NULL) {
+    Comment cmnt(masm_, "Global variable");
+    // Use inline caching. Variable name is passed in rcx and the global
+    // object on the stack.
+    __ push(CodeGenerator::GlobalObject());
+    __ Move(rcx, expr->name());
+    Handle<Code> ic(Builtins::builtin(Builtins::LoadIC_Initialize));
+    __ Call(ic, RelocInfo::CODE_TARGET_CONTEXT);
 
-  Slot* slot = rewrite->AsSlot();
-  ASSERT(slot != NULL);
-  { Comment cmnt(masm_, "[ Slot");
+    // A test rax instruction following the call is used by the IC to
+    // indicate that the inobject property case was inlined.  Ensure there
+    // is no test rax instruction here.
+    if (expr->location().is_temporary()) {
+      // Replace the global object with the result.
+      __ movq(Operand(rsp, 0), rax);
+    } else {
+      ASSERT(expr->location().is_nowhere());
+      __ pop(rax);
+    }
+
+  } else {
+    Comment cmnt(masm_, "Stack slot");
+    Slot* slot = rewrite->AsSlot();
+    ASSERT(slot != NULL);
     if (expr->location().is_temporary()) {
       __ push(Operand(rbp, SlotOffset(slot)));
     } else {
index 0be772b..066f927 100644 (file)
@@ -42,3 +42,14 @@ assertEquals(1, g);
 // Test a second store.
 assertEquals("2", eval('g = "2"'));
 assertEquals("2", g);
+
+// Test a load.
+assertEquals("2", eval('g'));
+
+// Test that patching the IC in the compiled code works.
+assertEquals("2", eval('g'));
+assertEquals("2", eval('g'));
+
+// Test a second load.
+g = 3;
+assertEquals(3, eval('g'));