void LoadReference(Reference* ref);
void UnloadReference(Reference* ref);
- MemOperand ContextOperand(Register context, int index) const {
+ static MemOperand ContextOperand(Register context, int index) {
return MemOperand(context, Context::SlotOffset(index));
}
JumpTarget* slow);
// Expressions
- MemOperand GlobalObject() const {
+ static MemOperand GlobalObject() {
return ContextOperand(cp, Context::GLOBAL_INDEX);
}
friend class VirtualFrame;
friend class JumpTarget;
friend class Reference;
+ friend class FastCodeGenerator;
DISALLOW_COPY_AND_ASSIGN(CodeGenerator);
};
Expression* rhs = expr->value();
Visit(rhs);
- // Left-hand side is always a (parameter or local) slot.
+ // Left-hand side can only be a global or a (parameter or local) slot.
Variable* var = expr->target()->AsVariableProxy()->AsVariable();
- ASSERT(var != NULL && var->slot() != NULL);
+ ASSERT(var != NULL);
+ ASSERT(var->is_global() || var->slot() != NULL);
// Complete the assignment based on the location of the right-hand-side
// value and the desired location of the assignment value.
ASSERT(!destination.is_constant());
ASSERT(!source.is_nowhere());
- if (source.is_temporary()) {
+ if (var->is_global()) {
+ // Assignment to a global variable, use inline caching. Right-hand-side
+ // value is passed in r0, variable name in r2, and the global object on
+ // the stack.
+ if (source.is_temporary()) {
+ __ pop(r0);
+ } else {
+ ASSERT(source.is_constant());
+ ASSERT(rhs->AsLiteral() != NULL);
+ __ mov(r0, Operand(rhs->AsLiteral()->handle()));
+ }
+ __ mov(r2, Operand(var->name()));
+ __ ldr(ip, CodeGenerator::GlobalObject());
+ __ push(ip);
+ Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Initialize));
+ __ Call(ic, RelocInfo::CODE_TARGET);
+ // Overwrite the global object on the stack with the result if needed.
if (destination.is_temporary()) {
- // Case 'temp1 <- (var = temp0)'. Preserve right-hand-side temporary
- // on the stack.
- __ ldr(ip, MemOperand(sp));
+ __ str(r0, MemOperand(sp));
} else {
ASSERT(destination.is_nowhere());
- // Case 'var = temp'. Discard right-hand-side temporary.
- __ pop(ip);
+ __ pop();
}
- __ str(ip, MemOperand(fp, SlotOffset(var->slot())));
+
} else {
- ASSERT(source.is_constant());
- ASSERT(rhs->AsLiteral() != NULL);
- // Two cases: 'temp <- (var = constant)', or 'var = constant' with a
- // discarded result. Always perform the assignment.
- __ mov(ip, Operand(rhs->AsLiteral()->handle()));
- __ str(ip, MemOperand(fp, SlotOffset(var->slot())));
- if (destination.is_temporary()) {
- // Case 'temp <- (var = constant)'. Save result.
- __ push(ip);
+ if (source.is_temporary()) {
+ if (destination.is_temporary()) {
+ // Case 'temp1 <- (var = temp0)'. Preserve right-hand-side
+ // temporary on the stack.
+ __ ldr(ip, MemOperand(sp));
+ } else {
+ ASSERT(destination.is_nowhere());
+ // Case 'var = temp'. Discard right-hand-side temporary.
+ __ pop(ip);
+ }
+ __ str(ip, MemOperand(fp, SlotOffset(var->slot())));
+ } else {
+ ASSERT(source.is_constant());
+ ASSERT(rhs->AsLiteral() != NULL);
+ // Two cases: 'temp <- (var = constant)', or 'var = constant' with a
+ // discarded result. Always perform the assignment.
+ __ mov(ip, Operand(rhs->AsLiteral()->handle()));
+ __ str(ip, MemOperand(fp, SlotOffset(var->slot())));
+ if (destination.is_temporary()) {
+ // Case 'temp <- (var = constant)'. Save result.
+ __ push(ip);
+ }
}
}
}
void VirtualFrame::RawCallCodeObject(Handle<Code> code,
- RelocInfo::Mode rmode) {
+ RelocInfo::Mode rmode) {
ASSERT(cgen()->HasValidEntryRegisters());
__ Call(code, rmode);
}
}
Variable* var = expr->target()->AsVariableProxy()->AsVariable();
- if (var == NULL || var->is_global()) BAILOUT("non-variable assignment");
+ if (var == NULL) BAILOUT("non-variable assignment");
- ASSERT(var->slot() != NULL);
- Slot::Type type = var->slot()->type();
- if (type != Slot::PARAMETER && type != Slot::LOCAL) {
- BAILOUT("non-parameter/non-local slot assignment");
+ if (!var->is_global()) {
+ ASSERT(var->slot() != NULL);
+ Slot::Type type = var->slot()->type();
+ if (type != Slot::PARAMETER && type != Slot::LOCAL) {
+ BAILOUT("non-parameter/non-local slot assignment");
+ }
}
Visit(expr->value());
void LoadReference(Reference* ref);
void UnloadReference(Reference* ref);
- Operand ContextOperand(Register context, int index) const {
+ static Operand ContextOperand(Register context, int index) {
return Operand(context, Context::SlotOffset(index));
}
JumpTarget* slow);
// Expressions
- Operand GlobalObject() const {
+ static Operand GlobalObject() {
return ContextOperand(esi, Context::GLOBAL_INDEX);
}
friend class JumpTarget;
friend class Reference;
friend class Result;
+ friend class FastCodeGenerator;
friend class CodeGeneratorPatcher; // Used in test-log-stack-tracer.cc
Expression* rhs = expr->value();
Visit(rhs);
- // Left-hand side is always a (parameter or local) slot.
+ // Left-hand side can only be a global or a (parameter or local) slot.
Variable* var = expr->target()->AsVariableProxy()->AsVariable();
- ASSERT(var != NULL && var->slot() != NULL);
+ ASSERT(var != NULL);
+ ASSERT(var->is_global() || var->slot() != NULL);
// Complete the assignment based on the location of the right-hand-side
// value and the desired location of the assignment value.
ASSERT(!destination.is_constant());
ASSERT(!source.is_nowhere());
- if (source.is_temporary()) {
+ if (var->is_global()) {
+ // Assignment to a global variable, use inline caching. Right-hand-side
+ // value is passed in eax, variable name in ecx, and the global object
+ // on the stack.
+ if (source.is_temporary()) {
+ __ pop(eax);
+ } else {
+ ASSERT(source.is_constant());
+ ASSERT(rhs->AsLiteral() != NULL);
+ __ mov(eax, rhs->AsLiteral()->handle());
+ }
+ __ mov(ecx, var->name());
+ __ push(CodeGenerator::GlobalObject());
+ Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Initialize));
+ __ call(ic, RelocInfo::CODE_TARGET);
+ // Overwrite the global object on the stack with the result if needed.
if (destination.is_temporary()) {
- // Case 'temp1 <- (var = temp0)'. Preserve right-hand-side temporary
- // on the stack.
- __ mov(eax, Operand(esp, 0));
- __ mov(Operand(ebp, SlotOffset(var->slot())), eax);
+ __ mov(Operand(esp, 0), eax);
} else {
ASSERT(destination.is_nowhere());
- // Case 'var = temp'. Discard right-hand-side temporary.
- __ pop(Operand(ebp, SlotOffset(var->slot())));
+ __ pop(eax);
}
+
} else {
- ASSERT(source.is_constant());
- ASSERT(rhs->AsLiteral() != NULL);
- // Two cases: 'temp <- (var = constant)', or 'var = constant' with a
- // discarded result. Always perform the assignment.
- __ mov(eax, rhs->AsLiteral()->handle());
- __ mov(Operand(ebp, SlotOffset(var->slot())), eax);
- if (destination.is_temporary()) {
- // Case 'temp <- (var = constant)'. Save result.
- __ push(eax);
+ // Local or parameter assignment.
+ if (source.is_temporary()) {
+ if (destination.is_temporary()) {
+ // Case 'temp1 <- (var = temp0)'. Preserve right-hand-side
+ // temporary on the stack.
+ __ mov(eax, Operand(esp, 0));
+ __ mov(Operand(ebp, SlotOffset(var->slot())), eax);
+ } else {
+ ASSERT(destination.is_nowhere());
+ // Case 'var = temp'. Discard right-hand-side temporary.
+ __ pop(Operand(ebp, SlotOffset(var->slot())));
+ }
+ } else {
+ ASSERT(source.is_constant());
+ ASSERT(rhs->AsLiteral() != NULL);
+ // Two cases: 'temp <- (var = constant)', or 'var = constant' with a
+ // discarded result. Always perform the assignment.
+ __ mov(eax, rhs->AsLiteral()->handle());
+ __ mov(Operand(ebp, SlotOffset(var->slot())), eax);
+ if (destination.is_temporary()) {
+ // Case 'temp <- (var = constant)'. Save result.
+ __ push(eax);
+ }
}
}
}
void LoadReference(Reference* ref);
void UnloadReference(Reference* ref);
- Operand ContextOperand(Register context, int index) const {
+ static Operand ContextOperand(Register context, int index) {
return Operand(context, Context::SlotOffset(index));
}
JumpTarget* slow);
// Expressions
- Operand GlobalObject() const {
+ static Operand GlobalObject() {
return ContextOperand(rsi, Context::GLOBAL_INDEX);
}
friend class JumpTarget;
friend class Reference;
friend class Result;
+ friend class FastCodeGenerator;
friend class CodeGeneratorPatcher; // Used in test-log-stack-tracer.cc
Expression* rhs = expr->value();
Visit(rhs);
- // Left-hand side is always a (parameter or local) slot.
+ // Left-hand side can only be a global or a (parameter or local) slot.
Variable* var = expr->target()->AsVariableProxy()->AsVariable();
- ASSERT(var != NULL && var->slot() != NULL);
+ ASSERT(var != NULL);
+ ASSERT(var->is_global() || var->slot() != NULL);
// Complete the assignment based on the location of the right-hand-side
// value and the desired location of the assignment value.
ASSERT(!destination.is_constant());
ASSERT(!source.is_nowhere());
- if (source.is_temporary()) {
+ if (var->is_global()) {
+ // Assignment to a global variable, use inline caching. Right-hand-side
+ // value is passed in rax, variable name in rcx, and the global object
+ // on the stack.
+ if (source.is_temporary()) {
+ __ pop(rax);
+ } else {
+ ASSERT(source.is_constant());
+ ASSERT(rhs->AsLiteral() != NULL);
+ __ Move(rax, rhs->AsLiteral()->handle());
+ }
+ __ Move(rcx, var->name());
+ __ push(CodeGenerator::GlobalObject());
+ Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Initialize));
+ __ Call(ic, RelocInfo::CODE_TARGET);
+ // Overwrite the global object on the stack with the result if needed.
if (destination.is_temporary()) {
- // Case 'temp1 <- (var = temp0)'. Preserve right-hand-side temporary
- // on the stack.
- __ movq(kScratchRegister, Operand(rsp, 0));
- __ movq(Operand(rbp, SlotOffset(var->slot())), kScratchRegister);
+ __ movq(Operand(rsp, 0), rax);
} else {
- ASSERT(destination.is_nowhere());
- // Case 'var = temp'. Discard right-hand-side temporary.
- __ pop(Operand(rbp, SlotOffset(var->slot())));
+ __ pop(rax);
}
} else {
- ASSERT(source.is_constant());
- ASSERT(rhs->AsLiteral() != NULL);
- // Two cases: 'temp <- (var = constant)', or 'var = constant' with a
- // discarded result. Always perform the assignment.
- __ Move(kScratchRegister, rhs->AsLiteral()->handle());
- __ movq(Operand(rbp, SlotOffset(var->slot())), kScratchRegister);
- if (destination.is_temporary()) {
- // Case 'temp <- (var = constant)'. Save result.
- __ push(kScratchRegister);
+ if (source.is_temporary()) {
+ if (destination.is_temporary()) {
+ // Case 'temp1 <- (var = temp0)'. Preserve right-hand-side temporary
+ // on the stack.
+ __ movq(kScratchRegister, Operand(rsp, 0));
+ __ movq(Operand(rbp, SlotOffset(var->slot())), kScratchRegister);
+ } else {
+ ASSERT(destination.is_nowhere());
+ // Case 'var = temp'. Discard right-hand-side temporary.
+ __ pop(Operand(rbp, SlotOffset(var->slot())));
+ }
+ } else {
+ ASSERT(source.is_constant());
+ ASSERT(rhs->AsLiteral() != NULL);
+ // Two cases: 'temp <- (var = constant)', or 'var = constant' with a
+ // discarded result. Always perform the assignment.
+ __ Move(kScratchRegister, rhs->AsLiteral()->handle());
+ __ movq(Operand(rbp, SlotOffset(var->slot())), kScratchRegister);
+ if (destination.is_temporary()) {
+ // Case 'temp <- (var = constant)'. Save result.
+ __ push(kScratchRegister);
+ }
}
}
}
--- /dev/null
+// Copyright 2009 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following
+// disclaimer in the documentation and/or other materials provided
+// with the distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived
+// from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Test references and assignments to global variables.
+var g = 0;
+
+// Test compilation of a global variable store.
+assertEquals(1, eval('g = 1'));
+// Test that the store worked.
+assertEquals(1, g);
+
+// Test that patching the IC in the compiled code works.
+assertEquals(1, eval('g = 1'));
+assertEquals(1, g);
+assertEquals(1, eval('g = 1'));
+assertEquals(1, g);
+
+// Test a second store.
+assertEquals("2", eval('g = "2"'));
+assertEquals("2", g);