| OLD | NEW |
| (Empty) | |
| 1 // Copyright 2010 the V8 project authors. All rights reserved. |
| 2 // Redistribution and use in source and binary forms, with or without |
| 3 // modification, are permitted provided that the following conditions are |
| 4 // met: |
| 5 // |
| 6 // * Redistributions of source code must retain the above copyright |
| 7 // notice, this list of conditions and the following disclaimer. |
| 8 // * Redistributions in binary form must reproduce the above |
| 9 // copyright notice, this list of conditions and the following |
| 10 // disclaimer in the documentation and/or other materials provided |
| 11 // with the distribution. |
| 12 // * Neither the name of Google Inc. nor the names of its |
| 13 // contributors may be used to endorse or promote products derived |
| 14 // from this software without specific prior written permission. |
| 15 // |
| 16 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
| 17 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
| 18 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
| 19 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
| 20 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
| 21 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
| 22 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
| 23 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
| 24 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
| 25 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
| 26 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
| 27 |
| 28 #include "v8.h" |
| 29 |
| 30 #include "codegen-inl.h" |
| 31 #include "compiler.h" |
| 32 #include "debug.h" |
| 33 #include "ast.h" |
| 34 #include "virtual-frame-inl.h" |
| 35 #include "safe-codegen-ia32.h" |
| 36 #include "parser.h" |
| 37 #include "macro-assembler-ia32.h" |
| 38 |
| 39 namespace v8 { |
| 40 namespace internal { |
| 41 |
| 42 #define __ ACCESS_MASM(masm_) |
| 43 |
| 44 |
| 45 // SafeSyntaxChecker - An AST Visitor that bails out and returns false |
| 46 // for any unsupported AST nodes in a side-effect free expression. |
| 47 |
| 48 #define BAILOUT(reason) \ |
| 49 do { \ |
| 50 if (FLAG_trace_bailout) { \ |
| 51 PrintF("%s\n", reason); \ |
| 52 } \ |
| 53 has_supported_syntax_ = false; \ |
| 54 return; \ |
| 55 } while (false) |
| 56 |
| 57 |
| 58 #define CHECK_BAILOUT \ |
| 59 do { \ |
| 60 if (!has_supported_syntax_) return; \ |
| 61 } while (false) |
| 62 |
| 63 |
| 64 #define DEFINE_STMT_VISIT(type) \ |
| 65 void SafeSyntaxChecker::Visit##type(type* stmt) { \ |
| 66 UNREACHABLE(); \ |
| 67 } \ |
| 68 \ |
| 69 void SafeGenerator::Visit##type(type* stmt) { \ |
| 70 UNREACHABLE(); \ |
| 71 } |
| 72 |
| 73 STATEMENT_NODE_LIST(DEFINE_STMT_VISIT) |
| 74 |
| 75 DEFINE_STMT_VISIT(Declaration) |
| 76 |
| 77 #undef DEFINE_STMT_VISIT |
| 78 |
| 79 void SafeSyntaxChecker::VisitFunctionLiteral(FunctionLiteral* expr) { |
| 80 BAILOUT("FunctionLiteral"); |
| 81 } |
| 82 |
| 83 |
| 84 void SafeSyntaxChecker::VisitFunctionBoilerplateLiteral( |
| 85 FunctionBoilerplateLiteral* expr) { |
| 86 BAILOUT("FunctionBoilerplateLiteral"); |
| 87 } |
| 88 |
| 89 |
| 90 void SafeSyntaxChecker::VisitConditional(Conditional* expr) { |
| 91 BAILOUT("Conditional"); |
| 92 } |
| 93 |
| 94 |
| 95 void SafeSyntaxChecker::VisitSlot(Slot* expr) { |
| 96 // Load variables directly from local or parameter slots. |
| 97 // The arguments slot could be the hole, if lazy arguments are used, |
| 98 // and is probably not a smi or heap number in any case. |
| 99 if ((expr->type() == Slot::LOCAL && !expr->is_arguments()) || |
| 100 expr->type() == Slot::PARAMETER) { |
| 101 ++xmm_stack_height_; |
| 102 if (xmm_stack_height_ > MAX_XMM_STACK_HEIGHT) { |
| 103 BAILOUT("Expression stack overflow"); |
| 104 } |
| 105 } else { |
| 106 BAILOUT("Slot is not local or parameter slot."); |
| 107 } |
| 108 } |
| 109 |
| 110 |
| 111 void SafeSyntaxChecker::VisitVariableProxy(VariableProxy* expr) { |
| 112 Variable* var = expr->AsVariable(); |
| 113 if (var != NULL && var->slot() != NULL) { |
| 114 Visit(var->slot()); |
| 115 } else if (var != NULL && var->is_global() && !var->is_this()) { |
| 116 BAILOUT("Global variable"); |
| 117 // Global variables are supported. Do nothing. |
| 118 } else { |
| 119 BAILOUT("VariableProxy has non-slot variable"); |
| 120 } |
| 121 } |
| 122 |
| 123 |
| 124 void SafeSyntaxChecker::VisitLiteral(Literal* expr) { |
| 125 // Check that literal is a number. |
| 126 if (expr->handle()->IsSmi() || expr->handle()->IsHeapNumber()) { |
| 127 ++xmm_stack_height_; |
| 128 if (xmm_stack_height_ > MAX_XMM_STACK_HEIGHT) { |
| 129 BAILOUT("XMM stack height too great"); |
| 130 } |
| 131 if (expr->handle()->IsHeapNumber()) { |
| 132 has_constant_float_ = true; |
| 133 } |
| 134 } else { |
| 135 BAILOUT("Non-number literal"); |
| 136 } |
| 137 } |
| 138 |
| 139 |
| 140 void SafeSyntaxChecker::VisitRegExpLiteral(RegExpLiteral* expr) { |
| 141 BAILOUT("RegExpLiteral"); |
| 142 } |
| 143 |
| 144 |
| 145 void SafeSyntaxChecker::VisitObjectLiteral(ObjectLiteral* expr) { |
| 146 BAILOUT("ObjectLiteral"); |
| 147 } |
| 148 |
| 149 |
| 150 void SafeSyntaxChecker::VisitArrayLiteral(ArrayLiteral* expr) { |
| 151 BAILOUT("ArrayLiteral"); |
| 152 } |
| 153 |
| 154 |
| 155 void SafeSyntaxChecker::VisitCatchExtensionObject( |
| 156 CatchExtensionObject* expr) { |
| 157 BAILOUT("CatchExtensionObject"); |
| 158 } |
| 159 |
| 160 |
| 161 void SafeSyntaxChecker::VisitAssignment(Assignment* expr) { |
| 162 BAILOUT("Assignment has a side effect"); |
| 163 } |
| 164 |
| 165 |
| 166 void SafeSyntaxChecker::VisitThrow(Throw* expr) { |
| 167 BAILOUT("Throw"); |
| 168 } |
| 169 |
| 170 |
| 171 void SafeSyntaxChecker::VisitProperty(Property* expr) { |
| 172 BAILOUT("Property"); |
| 173 } |
| 174 |
| 175 |
| 176 void SafeSyntaxChecker::VisitCall(Call* expr) { |
| 177 BAILOUT("Call"); |
| 178 } |
| 179 |
| 180 |
| 181 void SafeSyntaxChecker::VisitCallNew(CallNew* expr) { |
| 182 BAILOUT("CallNew"); |
| 183 } |
| 184 |
| 185 |
| 186 void SafeSyntaxChecker::VisitCallRuntime(CallRuntime* expr) { |
| 187 BAILOUT("CallRuntime"); |
| 188 } |
| 189 |
| 190 |
| 191 void SafeSyntaxChecker::VisitUnaryOperation(UnaryOperation* expr) { |
| 192 switch (expr->op()) { |
| 193 case Token::ADD: |
| 194 Visit(expr->expression()); |
| 195 break; |
| 196 case Token::SUB: |
| 197 Visit(expr->expression()); |
| 198 CHECK_BAILOUT; |
| 199 if (xmm_stack_height_ == MAX_XMM_STACK_HEIGHT) { |
| 200 // Need one extra register for doing the computation. |
| 201 BAILOUT("XMM stack height too great"); |
| 202 } |
| 203 ++num_operations_; |
| 204 break; |
| 205 case Token::DELETE: |
| 206 case Token::TYPEOF: |
| 207 case Token::VOID: |
| 208 case Token::BIT_NOT: |
| 209 case Token::NOT: |
| 210 BAILOUT("Unsupported Unary Operation"); |
| 211 break; |
| 212 default: |
| 213 UNREACHABLE(); |
| 214 } |
| 215 } |
| 216 |
| 217 |
| 218 void SafeSyntaxChecker::VisitCountOperation(CountOperation* expr) { |
| 219 BAILOUT("CountOperation"); |
| 220 } |
| 221 |
| 222 |
| 223 void SafeSyntaxChecker::VisitBinaryOperation(BinaryOperation* expr) { |
| 224 switch (expr->op()) { |
| 225 case Token::ADD: |
| 226 case Token::SUB: |
| 227 case Token::DIV: |
| 228 case Token::MUL: |
| 229 Visit(expr->left()); |
| 230 CHECK_BAILOUT; |
| 231 Visit(expr->right()); |
| 232 CHECK_BAILOUT; |
| 233 ++num_operations_; |
| 234 --xmm_stack_height_; |
| 235 break; |
| 236 case Token::MOD: |
| 237 case Token::BIT_OR: |
| 238 case Token::BIT_AND: |
| 239 case Token::BIT_XOR: |
| 240 case Token::SHL: |
| 241 case Token::SHR: |
| 242 case Token::SAR: |
| 243 case Token::COMMA: |
| 244 case Token::OR: |
| 245 case Token::AND: |
| 246 BAILOUT("Unsupported Binary Operation"); |
| 247 break; |
| 248 default: |
| 249 UNREACHABLE(); |
| 250 } |
| 251 } |
| 252 |
| 253 |
| 254 void SafeSyntaxChecker::VisitCompareOperation(CompareOperation* expr) { |
| 255 BAILOUT("CompareOperation"); |
| 256 } |
| 257 |
| 258 |
| 259 void SafeSyntaxChecker::VisitThisFunction(ThisFunction* expr) { |
| 260 BAILOUT("ThisFunction"); |
| 261 } |
| 262 |
| 263 |
| 264 // Generate code for a side-effect free expression. |
| 265 // whesse works above this line |
| 266 // -------------------------------------------------- |
| 267 // lrn works below this line |
| 268 |
| 269 Result SafeGenerator::Generate(Expression* expr) { |
| 270 JumpTarget allocation_succeeded; |
| 271 Label allocation_failed; |
| 272 ASSERT(CpuFeatures::IsSupported(SSE2)); |
| 273 CpuFeatures::Scope fscope(SSE2); |
| 274 |
| 275 VirtualFrame* clone = new VirtualFrame(cgen_->frame()); |
| 276 __ AllocateHeapNumber(final_result_->reg(), scratch_->reg(), |
| 277 no_reg, &allocation_failed); |
| 278 cgen_->frame()->Push(scratch_); |
| 279 allocation_succeeded.Jump(final_result_); |
| 280 RegisterFile empty_regs; |
| 281 cgen_->SetFrame(clone, &empty_regs); |
| 282 __ bind(&allocation_failed); |
| 283 unsafe_target_->Jump(); |
| 284 |
| 285 allocation_succeeded.Bind(final_result_); |
| 286 *scratch_ = cgen_->frame()->Pop(); |
| 287 Visit(expr); |
| 288 StoreXMM(final_result_->reg()); |
| 289 Result return_value = *final_result_; |
| 290 final_result_->Unuse(); |
| 291 scratch_->Unuse(); |
| 292 return return_value; |
| 293 } |
| 294 |
| 295 void SafeGenerator::PushXMM(Handle<HeapNumber> literal) { |
| 296 XMMRegister reg = AllocateStackElement(); |
| 297 __ mov(scratch_->reg(), Immediate(literal)); |
| 298 __ movdbl(reg, FieldOperand(scratch_->reg(), HeapNumber::kValueOffset)); |
| 299 } |
| 300 |
| 301 |
| 302 void SafeGenerator::PushXMM(Handle<Smi> literal) { |
| 303 XMMRegister reg = AllocateStackElement(); |
| 304 __ mov(scratch_->reg(), Immediate(literal->value())); |
| 305 __ cvtsi2sd(reg, Operand(scratch_->reg())); |
| 306 } |
| 307 |
| 308 |
| 309 void SafeGenerator::PushXMM(Slot* slot) { |
| 310 Register scratch = scratch_->reg(); |
| 311 ASSERT((slot->type() == Slot::LOCAL && !slot->is_arguments()) || |
| 312 slot->type() == Slot::PARAMETER); |
| 313 if (slot->type() == Slot::PARAMETER) { |
| 314 cgen_->frame()->PushParameterAt(slot->index()); |
| 315 } else { // slot->type == Slot::LOCAL |
| 316 cgen_->frame()->PushLocalAt(slot->index()); |
| 317 } |
| 318 Result value = cgen_->frame()->Pop(); |
| 319 XMMRegister reg = AllocateStackElement(); |
| 320 |
| 321 if (value.is_register()) { |
| 322 // Convert to double. |
| 323 __ test(Operand(value.reg()), Immediate(kSmiTagMask)); |
| 324 Label is_smi; |
| 325 Label done; |
| 326 __ j(zero, &is_smi); |
| 327 // This test fails on non-numbers, including the hole representing |
| 328 // an uninitialized constant. |
| 329 __ cmp(FieldOperand(value.reg(), HeapObject::kMapOffset), |
| 330 Immediate(Factory::heap_number_map())); |
| 331 unsafe_target_->Branch(not_equal); |
| 332 __ movdbl(reg, FieldOperand(value.reg(), HeapNumber::kValueOffset)); |
| 333 __ jmp(&done); |
| 334 |
| 335 __ bind(&is_smi); |
| 336 // Should we spill the existing register, and untag it, or should |
| 337 // we copy to the scratch register? |
| 338 __ mov(scratch, value.reg()); |
| 339 __ SmiUntag(scratch); |
| 340 __ cvtsi2sd(reg, Operand(scratch)); |
| 341 |
| 342 __ bind(&done); |
| 343 } else { |
| 344 ASSERT(value.is_constant()); |
| 345 if (value.handle()->IsHeapNumber()) { |
| 346 __ mov(scratch, value.handle()); |
| 347 __ movdbl(reg, FieldOperand(scratch, HeapNumber::kValueOffset)); |
| 348 } else { |
| 349 ASSERT(value.handle()->IsSmi()); |
| 350 __ mov(scratch, Immediate(Smi::cast(*value.handle())->value())); |
| 351 __ cvtsi2sd(reg, Operand(scratch)); |
| 352 } |
| 353 } |
| 354 } |
| 355 |
| 356 |
| 357 void SafeGenerator::StoreXMM(Register heapNumber) { |
| 358 ASSERT(xmm_stack_height_ > 0); |
| 359 XMMRegister reg = XMMStackElement(0); |
| 360 __ movdbl(FieldOperand(heapNumber, HeapNumber::kValueOffset), reg); |
| 361 FreeStackTop(); |
| 362 } |
| 363 |
| 364 |
| 365 // Utility functions. |
| 366 XMMRegister SafeGenerator::XMMStackElement(int offset_from_top) { |
| 367 ASSERT(offset_from_top < xmm_stack_height_); |
| 368 ASSERT(offset_from_top < kNumXMMRegisters); // The rest have been spilled! |
| 369 int reg_code = (xmm_stack_height_ - offset_from_top - 1); |
| 370 XMMRegister reg = { reg_code }; |
| 371 ASSERT(reg.is_valid()); |
| 372 return reg; |
| 373 } |
| 374 |
| 375 |
| 376 void SafeGenerator::VisitFunctionLiteral(FunctionLiteral* expr) { |
| 377 UNREACHABLE(); |
| 378 } |
| 379 |
| 380 |
| 381 void SafeGenerator::VisitFunctionBoilerplateLiteral( |
| 382 FunctionBoilerplateLiteral* expr) { |
| 383 UNREACHABLE(); |
| 384 } |
| 385 |
| 386 |
| 387 void SafeGenerator::VisitConditional(Conditional* expr) { |
| 388 UNREACHABLE(); |
| 389 } |
| 390 |
| 391 |
| 392 void SafeGenerator::VisitSlot(Slot* expr) { |
| 393 // Check that slot is local or context. |
| 394 if ((expr->type() == Slot::LOCAL && !expr->is_arguments()) || |
| 395 expr->type() == Slot::PARAMETER) { |
| 396 PushXMM(expr); |
| 397 } else { |
| 398 UNREACHABLE(); |
| 399 } |
| 400 } |
| 401 |
| 402 |
| 403 void SafeGenerator::VisitVariableProxy(VariableProxy* expr) { |
| 404 Variable* var = expr->AsVariable(); |
| 405 if (var != NULL && var->slot() != NULL) { |
| 406 Visit(var->slot()); |
| 407 } else { |
| 408 UNREACHABLE(); |
| 409 } |
| 410 } |
| 411 |
| 412 |
| 413 void SafeGenerator::VisitLiteral(Literal* expr) { |
| 414 // Check that literal is a number. |
| 415 if (expr->handle()->IsSmi()) { |
| 416 PushXMM(Handle<Smi>::cast(expr->handle())); |
| 417 } else if (expr->handle()->IsHeapNumber()) { |
| 418 PushXMM(Handle<HeapNumber>::cast(expr->handle())); |
| 419 } else { |
| 420 UNREACHABLE(); |
| 421 } |
| 422 } |
| 423 |
| 424 |
| 425 void SafeGenerator::VisitRegExpLiteral(RegExpLiteral* expr) { |
| 426 UNREACHABLE(); |
| 427 } |
| 428 |
| 429 |
| 430 void SafeGenerator::VisitObjectLiteral(ObjectLiteral* expr) { |
| 431 UNREACHABLE(); |
| 432 } |
| 433 |
| 434 |
| 435 void SafeGenerator::VisitArrayLiteral(ArrayLiteral* expr) { |
| 436 UNREACHABLE(); |
| 437 } |
| 438 |
| 439 |
| 440 void SafeGenerator::VisitCatchExtensionObject( |
| 441 CatchExtensionObject* expr) { |
| 442 UNREACHABLE(); |
| 443 } |
| 444 |
| 445 |
| 446 void SafeGenerator::VisitAssignment(Assignment* expr) { |
| 447 UNREACHABLE(); |
| 448 } |
| 449 |
| 450 |
| 451 void SafeGenerator::VisitThrow(Throw* expr) { |
| 452 UNREACHABLE(); |
| 453 } |
| 454 |
| 455 |
| 456 void SafeGenerator::VisitProperty(Property* expr) { |
| 457 UNREACHABLE(); |
| 458 } |
| 459 |
| 460 |
| 461 void SafeGenerator::VisitCall(Call* expr) { |
| 462 UNREACHABLE(); |
| 463 } |
| 464 |
| 465 |
| 466 void SafeGenerator::VisitCallNew(CallNew* expr) { |
| 467 UNREACHABLE(); |
| 468 } |
| 469 |
| 470 |
| 471 void SafeGenerator::VisitCallRuntime(CallRuntime* expr) { |
| 472 UNREACHABLE(); |
| 473 } |
| 474 |
| 475 |
| 476 void SafeGenerator::VisitUnaryOperation(UnaryOperation* expr) { |
| 477 switch (expr->op()) { |
| 478 case Token::ADD: |
| 479 Visit(expr->expression()); |
| 480 break; |
| 481 case Token::SUB: { |
| 482 Visit(expr->expression()); |
| 483 XMMRegister arg = XMMStackElement(0); |
| 484 XMMRegister tmp = AllocateStackElement(); |
| 485 // Load bit pattern 0x8000000000000000 to new XMM register, |
| 486 // and PXOR it with the result of expr to negate that. |
| 487 __ mov(Operand(scratch_->reg()), Immediate(0x80000000)); // -0 as float. |
| 488 __ movd(tmp, Operand(scratch_->reg())); |
| 489 __ cvtss2sd(tmp, tmp); |
| 490 __ pxor(arg, tmp); |
| 491 FreeStackTop(); |
| 492 break; |
| 493 } |
| 494 case Token::DELETE: |
| 495 case Token::TYPEOF: |
| 496 case Token::VOID: |
| 497 case Token::BIT_NOT: |
| 498 case Token::NOT: |
| 499 UNREACHABLE(); |
| 500 break; |
| 501 default: |
| 502 UNREACHABLE(); |
| 503 } |
| 504 } |
| 505 |
| 506 |
| 507 void SafeGenerator::VisitCountOperation(CountOperation* expr) { |
| 508 UNREACHABLE(); |
| 509 } |
| 510 |
| 511 |
| 512 void SafeGenerator::VisitBinaryOperation(BinaryOperation* expr) { |
| 513 Comment cmnt(masm_, "[ BinaryOperation"); |
| 514 Visit(expr->left()); |
| 515 Visit(expr->right()); |
| 516 ASSERT(xmm_stack_height_ >= 2); |
| 517 switch (expr->op()) { |
| 518 case Token::ADD: |
| 519 __ addsd(XMMStackElement(1), XMMStackElement(0)); |
| 520 break; |
| 521 case Token::SUB: |
| 522 __ subsd(XMMStackElement(1), XMMStackElement(0)); |
| 523 break; |
| 524 case Token::DIV: |
| 525 __ divsd(XMMStackElement(1), XMMStackElement(0)); |
| 526 break; |
| 527 case Token::MUL: |
| 528 __ mulsd(XMMStackElement(1), XMMStackElement(0)); |
| 529 break; |
| 530 case Token::MOD: |
| 531 case Token::BIT_OR: |
| 532 case Token::BIT_AND: |
| 533 case Token::BIT_XOR: |
| 534 case Token::SHL: |
| 535 case Token::SHR: |
| 536 case Token::SAR: |
| 537 case Token::COMMA: |
| 538 case Token::OR: |
| 539 case Token::AND: |
| 540 default: |
| 541 UNREACHABLE(); |
| 542 } |
| 543 FreeStackTop(); |
| 544 } |
| 545 |
| 546 |
| 547 void SafeGenerator::VisitCompareOperation(CompareOperation* expr) { |
| 548 UNREACHABLE(); |
| 549 } |
| 550 |
| 551 |
| 552 void SafeGenerator::VisitThisFunction(ThisFunction* expr) { |
| 553 UNREACHABLE(); |
| 554 } |
| 555 #undef __ |
| 556 |
| 557 } } // namespace v8::internal |
| OLD | NEW |