| Index: src/ia32/safe-codegen-ia32.cc
|
| ===================================================================
|
| --- src/ia32/safe-codegen-ia32.cc (revision 0)
|
| +++ src/ia32/safe-codegen-ia32.cc (revision 0)
|
| @@ -0,0 +1,557 @@
|
| +// Copyright 2010 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.
|
| +
|
| +#include "v8.h"
|
| +
|
| +#include "codegen-inl.h"
|
| +#include "compiler.h"
|
| +#include "debug.h"
|
| +#include "ast.h"
|
| +#include "virtual-frame-inl.h"
|
| +#include "safe-codegen-ia32.h"
|
| +#include "parser.h"
|
| +#include "macro-assembler-ia32.h"
|
| +
|
| +namespace v8 {
|
| +namespace internal {
|
| +
|
| +#define __ ACCESS_MASM(masm_)
|
| +
|
| +
|
| +// SafeSyntaxChecker - An AST Visitor that bails out and returns false
|
| +// for any unsupported AST nodes in a side-effect free expression.
|
| +
|
| +#define BAILOUT(reason) \
|
| + do { \
|
| + if (FLAG_trace_bailout) { \
|
| + PrintF("%s\n", reason); \
|
| + } \
|
| + has_supported_syntax_ = false; \
|
| + return; \
|
| + } while (false)
|
| +
|
| +
|
| +#define CHECK_BAILOUT \
|
| + do { \
|
| + if (!has_supported_syntax_) return; \
|
| + } while (false)
|
| +
|
| +
|
| +#define DEFINE_STMT_VISIT(type) \
|
| + void SafeSyntaxChecker::Visit##type(type* stmt) { \
|
| + UNREACHABLE(); \
|
| + } \
|
| + \
|
| + void SafeGenerator::Visit##type(type* stmt) { \
|
| + UNREACHABLE(); \
|
| + }
|
| +
|
| +STATEMENT_NODE_LIST(DEFINE_STMT_VISIT)
|
| +
|
| +DEFINE_STMT_VISIT(Declaration)
|
| +
|
| +#undef DEFINE_STMT_VISIT
|
| +
|
| +void SafeSyntaxChecker::VisitFunctionLiteral(FunctionLiteral* expr) {
|
| + BAILOUT("FunctionLiteral");
|
| +}
|
| +
|
| +
|
| +void SafeSyntaxChecker::VisitFunctionBoilerplateLiteral(
|
| + FunctionBoilerplateLiteral* expr) {
|
| + BAILOUT("FunctionBoilerplateLiteral");
|
| +}
|
| +
|
| +
|
| +void SafeSyntaxChecker::VisitConditional(Conditional* expr) {
|
| + BAILOUT("Conditional");
|
| +}
|
| +
|
| +
|
| +void SafeSyntaxChecker::VisitSlot(Slot* expr) {
|
| + // Load variables directly from local or parameter slots.
|
| + // The arguments slot could be the hole, if lazy arguments are used,
|
| + // and is probably not a smi or heap number in any case.
|
| + if ((expr->type() == Slot::LOCAL && !expr->is_arguments()) ||
|
| + expr->type() == Slot::PARAMETER) {
|
| + ++xmm_stack_height_;
|
| + if (xmm_stack_height_ > MAX_XMM_STACK_HEIGHT) {
|
| + BAILOUT("Expression stack overflow");
|
| + }
|
| + } else {
|
| + BAILOUT("Slot is not local or parameter slot.");
|
| + }
|
| +}
|
| +
|
| +
|
| +void SafeSyntaxChecker::VisitVariableProxy(VariableProxy* expr) {
|
| + Variable* var = expr->AsVariable();
|
| + if (var != NULL && var->slot() != NULL) {
|
| + Visit(var->slot());
|
| + } else if (var != NULL && var->is_global() && !var->is_this()) {
|
| + BAILOUT("Global variable");
|
| + // Global variables are supported. Do nothing.
|
| + } else {
|
| + BAILOUT("VariableProxy has non-slot variable");
|
| + }
|
| +}
|
| +
|
| +
|
| +void SafeSyntaxChecker::VisitLiteral(Literal* expr) {
|
| + // Check that literal is a number.
|
| + if (expr->handle()->IsSmi() || expr->handle()->IsHeapNumber()) {
|
| + ++xmm_stack_height_;
|
| + if (xmm_stack_height_ > MAX_XMM_STACK_HEIGHT) {
|
| + BAILOUT("XMM stack height too great");
|
| + }
|
| + if (expr->handle()->IsHeapNumber()) {
|
| + has_constant_float_ = true;
|
| + }
|
| + } else {
|
| + BAILOUT("Non-number literal");
|
| + }
|
| +}
|
| +
|
| +
|
| +void SafeSyntaxChecker::VisitRegExpLiteral(RegExpLiteral* expr) {
|
| + BAILOUT("RegExpLiteral");
|
| +}
|
| +
|
| +
|
| +void SafeSyntaxChecker::VisitObjectLiteral(ObjectLiteral* expr) {
|
| + BAILOUT("ObjectLiteral");
|
| +}
|
| +
|
| +
|
| +void SafeSyntaxChecker::VisitArrayLiteral(ArrayLiteral* expr) {
|
| + BAILOUT("ArrayLiteral");
|
| +}
|
| +
|
| +
|
| +void SafeSyntaxChecker::VisitCatchExtensionObject(
|
| + CatchExtensionObject* expr) {
|
| + BAILOUT("CatchExtensionObject");
|
| +}
|
| +
|
| +
|
| +void SafeSyntaxChecker::VisitAssignment(Assignment* expr) {
|
| + BAILOUT("Assignment has a side effect");
|
| +}
|
| +
|
| +
|
| +void SafeSyntaxChecker::VisitThrow(Throw* expr) {
|
| + BAILOUT("Throw");
|
| +}
|
| +
|
| +
|
| +void SafeSyntaxChecker::VisitProperty(Property* expr) {
|
| + BAILOUT("Property");
|
| +}
|
| +
|
| +
|
| +void SafeSyntaxChecker::VisitCall(Call* expr) {
|
| + BAILOUT("Call");
|
| +}
|
| +
|
| +
|
| +void SafeSyntaxChecker::VisitCallNew(CallNew* expr) {
|
| + BAILOUT("CallNew");
|
| +}
|
| +
|
| +
|
| +void SafeSyntaxChecker::VisitCallRuntime(CallRuntime* expr) {
|
| + BAILOUT("CallRuntime");
|
| +}
|
| +
|
| +
|
| +void SafeSyntaxChecker::VisitUnaryOperation(UnaryOperation* expr) {
|
| + switch (expr->op()) {
|
| + case Token::ADD:
|
| + Visit(expr->expression());
|
| + break;
|
| + case Token::SUB:
|
| + Visit(expr->expression());
|
| + CHECK_BAILOUT;
|
| + if (xmm_stack_height_ == MAX_XMM_STACK_HEIGHT) {
|
| + // Need one extra register for doing the computation.
|
| + BAILOUT("XMM stack height too great");
|
| + }
|
| + ++num_operations_;
|
| + break;
|
| + case Token::DELETE:
|
| + case Token::TYPEOF:
|
| + case Token::VOID:
|
| + case Token::BIT_NOT:
|
| + case Token::NOT:
|
| + BAILOUT("Unsupported Unary Operation");
|
| + break;
|
| + default:
|
| + UNREACHABLE();
|
| + }
|
| +}
|
| +
|
| +
|
| +void SafeSyntaxChecker::VisitCountOperation(CountOperation* expr) {
|
| + BAILOUT("CountOperation");
|
| +}
|
| +
|
| +
|
| +void SafeSyntaxChecker::VisitBinaryOperation(BinaryOperation* expr) {
|
| + switch (expr->op()) {
|
| + case Token::ADD:
|
| + case Token::SUB:
|
| + case Token::DIV:
|
| + case Token::MUL:
|
| + Visit(expr->left());
|
| + CHECK_BAILOUT;
|
| + Visit(expr->right());
|
| + CHECK_BAILOUT;
|
| + ++num_operations_;
|
| + --xmm_stack_height_;
|
| + break;
|
| + case Token::MOD:
|
| + case Token::BIT_OR:
|
| + case Token::BIT_AND:
|
| + case Token::BIT_XOR:
|
| + case Token::SHL:
|
| + case Token::SHR:
|
| + case Token::SAR:
|
| + case Token::COMMA:
|
| + case Token::OR:
|
| + case Token::AND:
|
| + BAILOUT("Unsupported Binary Operation");
|
| + break;
|
| + default:
|
| + UNREACHABLE();
|
| + }
|
| +}
|
| +
|
| +
|
| +void SafeSyntaxChecker::VisitCompareOperation(CompareOperation* expr) {
|
| + BAILOUT("CompareOperation");
|
| +}
|
| +
|
| +
|
| +void SafeSyntaxChecker::VisitThisFunction(ThisFunction* expr) {
|
| + BAILOUT("ThisFunction");
|
| +}
|
| +
|
| +
|
| +// Generate code for a side-effect free expression.
|
| +// whesse works above this line
|
| +// --------------------------------------------------
|
| +// lrn works below this line
|
| +
|
| +Result SafeGenerator::Generate(Expression* expr) {
|
| + JumpTarget allocation_succeeded;
|
| + Label allocation_failed;
|
| + ASSERT(CpuFeatures::IsSupported(SSE2));
|
| + CpuFeatures::Scope fscope(SSE2);
|
| +
|
| + VirtualFrame* clone = new VirtualFrame(cgen_->frame());
|
| + __ AllocateHeapNumber(final_result_->reg(), scratch_->reg(),
|
| + no_reg, &allocation_failed);
|
| + cgen_->frame()->Push(scratch_);
|
| + allocation_succeeded.Jump(final_result_);
|
| + RegisterFile empty_regs;
|
| + cgen_->SetFrame(clone, &empty_regs);
|
| + __ bind(&allocation_failed);
|
| + unsafe_target_->Jump();
|
| +
|
| + allocation_succeeded.Bind(final_result_);
|
| + *scratch_ = cgen_->frame()->Pop();
|
| + Visit(expr);
|
| + StoreXMM(final_result_->reg());
|
| + Result return_value = *final_result_;
|
| + final_result_->Unuse();
|
| + scratch_->Unuse();
|
| + return return_value;
|
| +}
|
| +
|
| +void SafeGenerator::PushXMM(Handle<HeapNumber> literal) {
|
| + XMMRegister reg = AllocateStackElement();
|
| + __ mov(scratch_->reg(), Immediate(literal));
|
| + __ movdbl(reg, FieldOperand(scratch_->reg(), HeapNumber::kValueOffset));
|
| +}
|
| +
|
| +
|
| +void SafeGenerator::PushXMM(Handle<Smi> literal) {
|
| + XMMRegister reg = AllocateStackElement();
|
| + __ mov(scratch_->reg(), Immediate(literal->value()));
|
| + __ cvtsi2sd(reg, Operand(scratch_->reg()));
|
| +}
|
| +
|
| +
|
| +void SafeGenerator::PushXMM(Slot* slot) {
|
| + Register scratch = scratch_->reg();
|
| + ASSERT((slot->type() == Slot::LOCAL && !slot->is_arguments()) ||
|
| + slot->type() == Slot::PARAMETER);
|
| + if (slot->type() == Slot::PARAMETER) {
|
| + cgen_->frame()->PushParameterAt(slot->index());
|
| + } else { // slot->type == Slot::LOCAL
|
| + cgen_->frame()->PushLocalAt(slot->index());
|
| + }
|
| + Result value = cgen_->frame()->Pop();
|
| + XMMRegister reg = AllocateStackElement();
|
| +
|
| + if (value.is_register()) {
|
| + // Convert to double.
|
| + __ test(Operand(value.reg()), Immediate(kSmiTagMask));
|
| + Label is_smi;
|
| + Label done;
|
| + __ j(zero, &is_smi);
|
| + // This test fails on non-numbers, including the hole representing
|
| + // an uninitialized constant.
|
| + __ cmp(FieldOperand(value.reg(), HeapObject::kMapOffset),
|
| + Immediate(Factory::heap_number_map()));
|
| + unsafe_target_->Branch(not_equal);
|
| + __ movdbl(reg, FieldOperand(value.reg(), HeapNumber::kValueOffset));
|
| + __ jmp(&done);
|
| +
|
| + __ bind(&is_smi);
|
| + // Should we spill the existing register, and untag it, or should
|
| + // we copy to the scratch register?
|
| + __ mov(scratch, value.reg());
|
| + __ SmiUntag(scratch);
|
| + __ cvtsi2sd(reg, Operand(scratch));
|
| +
|
| + __ bind(&done);
|
| + } else {
|
| + ASSERT(value.is_constant());
|
| + if (value.handle()->IsHeapNumber()) {
|
| + __ mov(scratch, value.handle());
|
| + __ movdbl(reg, FieldOperand(scratch, HeapNumber::kValueOffset));
|
| + } else {
|
| + ASSERT(value.handle()->IsSmi());
|
| + __ mov(scratch, Immediate(Smi::cast(*value.handle())->value()));
|
| + __ cvtsi2sd(reg, Operand(scratch));
|
| + }
|
| + }
|
| +}
|
| +
|
| +
|
| +void SafeGenerator::StoreXMM(Register heapNumber) {
|
| + ASSERT(xmm_stack_height_ > 0);
|
| + XMMRegister reg = XMMStackElement(0);
|
| + __ movdbl(FieldOperand(heapNumber, HeapNumber::kValueOffset), reg);
|
| + FreeStackTop();
|
| +}
|
| +
|
| +
|
| +// Utility functions.
|
| +XMMRegister SafeGenerator::XMMStackElement(int offset_from_top) {
|
| + ASSERT(offset_from_top < xmm_stack_height_);
|
| + ASSERT(offset_from_top < kNumXMMRegisters); // The rest have been spilled!
|
| + int reg_code = (xmm_stack_height_ - offset_from_top - 1);
|
| + XMMRegister reg = { reg_code };
|
| + ASSERT(reg.is_valid());
|
| + return reg;
|
| +}
|
| +
|
| +
|
| +void SafeGenerator::VisitFunctionLiteral(FunctionLiteral* expr) {
|
| + UNREACHABLE();
|
| +}
|
| +
|
| +
|
| +void SafeGenerator::VisitFunctionBoilerplateLiteral(
|
| + FunctionBoilerplateLiteral* expr) {
|
| + UNREACHABLE();
|
| +}
|
| +
|
| +
|
| +void SafeGenerator::VisitConditional(Conditional* expr) {
|
| + UNREACHABLE();
|
| +}
|
| +
|
| +
|
| +void SafeGenerator::VisitSlot(Slot* expr) {
|
| + // Check that slot is local or context.
|
| + if ((expr->type() == Slot::LOCAL && !expr->is_arguments()) ||
|
| + expr->type() == Slot::PARAMETER) {
|
| + PushXMM(expr);
|
| + } else {
|
| + UNREACHABLE();
|
| + }
|
| +}
|
| +
|
| +
|
| +void SafeGenerator::VisitVariableProxy(VariableProxy* expr) {
|
| + Variable* var = expr->AsVariable();
|
| + if (var != NULL && var->slot() != NULL) {
|
| + Visit(var->slot());
|
| + } else {
|
| + UNREACHABLE();
|
| + }
|
| +}
|
| +
|
| +
|
| +void SafeGenerator::VisitLiteral(Literal* expr) {
|
| + // Check that literal is a number.
|
| + if (expr->handle()->IsSmi()) {
|
| + PushXMM(Handle<Smi>::cast(expr->handle()));
|
| + } else if (expr->handle()->IsHeapNumber()) {
|
| + PushXMM(Handle<HeapNumber>::cast(expr->handle()));
|
| + } else {
|
| + UNREACHABLE();
|
| + }
|
| +}
|
| +
|
| +
|
| +void SafeGenerator::VisitRegExpLiteral(RegExpLiteral* expr) {
|
| + UNREACHABLE();
|
| +}
|
| +
|
| +
|
| +void SafeGenerator::VisitObjectLiteral(ObjectLiteral* expr) {
|
| + UNREACHABLE();
|
| +}
|
| +
|
| +
|
| +void SafeGenerator::VisitArrayLiteral(ArrayLiteral* expr) {
|
| + UNREACHABLE();
|
| +}
|
| +
|
| +
|
| +void SafeGenerator::VisitCatchExtensionObject(
|
| + CatchExtensionObject* expr) {
|
| + UNREACHABLE();
|
| +}
|
| +
|
| +
|
| +void SafeGenerator::VisitAssignment(Assignment* expr) {
|
| + UNREACHABLE();
|
| +}
|
| +
|
| +
|
| +void SafeGenerator::VisitThrow(Throw* expr) {
|
| + UNREACHABLE();
|
| +}
|
| +
|
| +
|
| +void SafeGenerator::VisitProperty(Property* expr) {
|
| + UNREACHABLE();
|
| +}
|
| +
|
| +
|
| +void SafeGenerator::VisitCall(Call* expr) {
|
| + UNREACHABLE();
|
| +}
|
| +
|
| +
|
| +void SafeGenerator::VisitCallNew(CallNew* expr) {
|
| + UNREACHABLE();
|
| +}
|
| +
|
| +
|
| +void SafeGenerator::VisitCallRuntime(CallRuntime* expr) {
|
| + UNREACHABLE();
|
| +}
|
| +
|
| +
|
| +void SafeGenerator::VisitUnaryOperation(UnaryOperation* expr) {
|
| + switch (expr->op()) {
|
| + case Token::ADD:
|
| + Visit(expr->expression());
|
| + break;
|
| + case Token::SUB: {
|
| + Visit(expr->expression());
|
| + XMMRegister arg = XMMStackElement(0);
|
| + XMMRegister tmp = AllocateStackElement();
|
| + // Load bit pattern 0x8000000000000000 to new XMM register,
|
| + // and PXOR it with the result of expr to negate that.
|
| + __ mov(Operand(scratch_->reg()), Immediate(0x80000000)); // -0 as float.
|
| + __ movd(tmp, Operand(scratch_->reg()));
|
| + __ cvtss2sd(tmp, tmp);
|
| + __ pxor(arg, tmp);
|
| + FreeStackTop();
|
| + break;
|
| + }
|
| + case Token::DELETE:
|
| + case Token::TYPEOF:
|
| + case Token::VOID:
|
| + case Token::BIT_NOT:
|
| + case Token::NOT:
|
| + UNREACHABLE();
|
| + break;
|
| + default:
|
| + UNREACHABLE();
|
| + }
|
| +}
|
| +
|
| +
|
| +void SafeGenerator::VisitCountOperation(CountOperation* expr) {
|
| + UNREACHABLE();
|
| +}
|
| +
|
| +
|
| +void SafeGenerator::VisitBinaryOperation(BinaryOperation* expr) {
|
| + Comment cmnt(masm_, "[ BinaryOperation");
|
| + Visit(expr->left());
|
| + Visit(expr->right());
|
| + ASSERT(xmm_stack_height_ >= 2);
|
| + switch (expr->op()) {
|
| + case Token::ADD:
|
| + __ addsd(XMMStackElement(1), XMMStackElement(0));
|
| + break;
|
| + case Token::SUB:
|
| + __ subsd(XMMStackElement(1), XMMStackElement(0));
|
| + break;
|
| + case Token::DIV:
|
| + __ divsd(XMMStackElement(1), XMMStackElement(0));
|
| + break;
|
| + case Token::MUL:
|
| + __ mulsd(XMMStackElement(1), XMMStackElement(0));
|
| + break;
|
| + case Token::MOD:
|
| + case Token::BIT_OR:
|
| + case Token::BIT_AND:
|
| + case Token::BIT_XOR:
|
| + case Token::SHL:
|
| + case Token::SHR:
|
| + case Token::SAR:
|
| + case Token::COMMA:
|
| + case Token::OR:
|
| + case Token::AND:
|
| + default:
|
| + UNREACHABLE();
|
| + }
|
| + FreeStackTop();
|
| +}
|
| +
|
| +
|
| +void SafeGenerator::VisitCompareOperation(CompareOperation* expr) {
|
| + UNREACHABLE();
|
| +}
|
| +
|
| +
|
| +void SafeGenerator::VisitThisFunction(ThisFunction* expr) {
|
| + UNREACHABLE();
|
| +}
|
| +#undef __
|
| +
|
| +} } // namespace v8::internal
|
|
|