diff options
54 files changed, 1022 insertions, 1370 deletions
diff --git a/deps/v8/ChangeLog b/deps/v8/ChangeLog index e816f5833f..8ee83766a4 100644 --- a/deps/v8/ChangeLog +++ b/deps/v8/ChangeLog @@ -1,3 +1,10 @@ +2009-10-29: Version 1.3.18 + + Reverted a change which caused crashes in RegExp replace. + + Reverted a change which caused Chromium ui_tests failure. + + 2009-10-28: Version 1.3.17 Added API method to get simple heap statistics. diff --git a/deps/v8/src/api.h b/deps/v8/src/api.h index a28e1f0774..1221f352cc 100644 --- a/deps/v8/src/api.h +++ b/deps/v8/src/api.h @@ -125,15 +125,6 @@ static inline v8::internal::Handle<v8::internal::Object> FromCData(T obj) { } -class ApiFunction { - public: - explicit ApiFunction(v8::internal::Address addr) : addr_(addr) { } - v8::internal::Address address() { return addr_; } - private: - v8::internal::Address addr_; -}; - - v8::Arguments::Arguments(v8::Local<v8::Value> data, v8::Local<v8::Object> holder, v8::Local<v8::Function> callee, diff --git a/deps/v8/src/arm/codegen-arm.cc b/deps/v8/src/arm/codegen-arm.cc index 3292bdcff2..dd88515e7a 100644 --- a/deps/v8/src/arm/codegen-arm.cc +++ b/deps/v8/src/arm/codegen-arm.cc @@ -5795,7 +5795,7 @@ void CEntryStub::GenerateCore(MacroAssembler* masm, Label* throw_normal_exception, Label* throw_termination_exception, Label* throw_out_of_memory_exception, - ExitFrame::Mode mode, + StackFrame::Type frame_type, bool do_gc, bool always_allocate) { // r0: result parameter for PerformGC, if any @@ -5855,7 +5855,7 @@ void CEntryStub::GenerateCore(MacroAssembler* masm, // r0:r1: result // sp: stack pointer // fp: frame pointer - __ LeaveExitFrame(mode); + __ LeaveExitFrame(frame_type); // check if we should retry or throw exception Label retry; @@ -5901,12 +5901,12 @@ void CEntryStub::GenerateBody(MacroAssembler* masm, bool is_debug_break) { // this by performing a garbage collection and retrying the // builtin once. - ExitFrame::Mode mode = is_debug_break - ? ExitFrame::MODE_DEBUG - : ExitFrame::MODE_NORMAL; + StackFrame::Type frame_type = is_debug_break + ? StackFrame::EXIT_DEBUG + : StackFrame::EXIT; // Enter the exit frame that transitions from JavaScript to C++. - __ EnterExitFrame(mode); + __ EnterExitFrame(frame_type); // r4: number of arguments (C callee-saved) // r5: pointer to builtin function (C callee-saved) @@ -5921,7 +5921,7 @@ void CEntryStub::GenerateBody(MacroAssembler* masm, bool is_debug_break) { &throw_normal_exception, &throw_termination_exception, &throw_out_of_memory_exception, - mode, + frame_type, false, false); @@ -5930,7 +5930,7 @@ void CEntryStub::GenerateBody(MacroAssembler* masm, bool is_debug_break) { &throw_normal_exception, &throw_termination_exception, &throw_out_of_memory_exception, - mode, + frame_type, true, false); @@ -5941,7 +5941,7 @@ void CEntryStub::GenerateBody(MacroAssembler* masm, bool is_debug_break) { &throw_normal_exception, &throw_termination_exception, &throw_out_of_memory_exception, - mode, + frame_type, true, true); diff --git a/deps/v8/src/arm/fast-codegen-arm.cc b/deps/v8/src/arm/fast-codegen-arm.cc index 21ee6d7e02..6540d40165 100644 --- a/deps/v8/src/arm/fast-codegen-arm.cc +++ b/deps/v8/src/arm/fast-codegen-arm.cc @@ -119,9 +119,11 @@ void FastCodeGenerator::Generate(FunctionLiteral* fun) { void FastCodeGenerator::Move(Location destination, Slot* source) { switch (destination.type()) { - case Location::NOWHERE: + case Location::kUninitialized: + UNREACHABLE(); + case Location::kEffect: break; - case Location::TEMP: + case Location::kValue: __ ldr(ip, MemOperand(fp, SlotOffset(source))); __ push(ip); break; @@ -131,9 +133,11 @@ void FastCodeGenerator::Move(Location destination, Slot* source) { void FastCodeGenerator::Move(Location destination, Literal* expr) { switch (destination.type()) { - case Location::NOWHERE: + case Location::kUninitialized: + UNREACHABLE(); + case Location::kEffect: break; - case Location::TEMP: + case Location::kValue: __ mov(ip, Operand(expr->handle())); __ push(ip); break; @@ -143,9 +147,10 @@ void FastCodeGenerator::Move(Location destination, Literal* expr) { void FastCodeGenerator::Move(Slot* destination, Location source) { switch (source.type()) { - case Location::NOWHERE: + case Location::kUninitialized: // Fall through. + case Location::kEffect: UNREACHABLE(); - case Location::TEMP: + case Location::kValue: __ pop(ip); __ str(ip, MemOperand(fp, SlotOffset(destination))); break; @@ -155,10 +160,12 @@ void FastCodeGenerator::Move(Slot* destination, Location source) { void FastCodeGenerator::DropAndMove(Location destination, Register source) { switch (destination.type()) { - case Location::NOWHERE: + case Location::kUninitialized: + UNREACHABLE(); + case Location::kEffect: __ pop(); break; - case Location::TEMP: + case Location::kValue: __ str(source, MemOperand(sp)); break; } @@ -239,6 +246,33 @@ void FastCodeGenerator::VisitVariableProxy(VariableProxy* expr) { } +void FastCodeGenerator::VisitRegExpLiteral(RegExpLiteral* expr) { + Comment cmnt(masm_, "[ RegExp Literal"); + Label done; + // Registers will be used as follows: + // r4 = JS function, literals array + // r3 = literal index + // r2 = RegExp pattern + // r1 = RegExp flags + // r0 = temp + return value (RegExp literal) + __ ldr(r0, MemOperand(fp, JavaScriptFrameConstants::kFunctionOffset)); + __ ldr(r4, FieldMemOperand(r0, JSFunction::kLiteralsOffset)); + int literal_offset = + FixedArray::kHeaderSize + expr->literal_index() * kPointerSize; + __ ldr(r0, FieldMemOperand(r4, literal_offset)); + __ LoadRoot(ip, Heap::kUndefinedValueRootIndex); + __ cmp(r0, ip); + __ b(ne, &done); + __ mov(r3, Operand(Smi::FromInt(expr->literal_index()))); + __ mov(r2, Operand(expr->pattern())); + __ mov(r1, Operand(expr->flags())); + __ stm(db_w, sp, r4.bit() | r3.bit() | r2.bit() | r1.bit()); + __ CallRuntime(Runtime::kMaterializeRegExpLiteral, 4); + __ bind(&done); + Move(expr->location(), r0); +} + + void FastCodeGenerator::VisitObjectLiteral(ObjectLiteral* expr) { Comment cmnt(masm_, "[ ObjectLiteral"); Label boilerplate_exists; @@ -284,73 +318,62 @@ void FastCodeGenerator::VisitObjectLiteral(ObjectLiteral* expr) { result_saved = true; } switch (property->kind()) { - case ObjectLiteral::Property::MATERIALIZED_LITERAL: // fall through + case ObjectLiteral::Property::CONSTANT: + UNREACHABLE(); + + case ObjectLiteral::Property::MATERIALIZED_LITERAL: // Fall through. ASSERT(!CompileTimeValue::IsCompileTimeValue(property->value())); - case ObjectLiteral::Property::COMPUTED: // fall through + case ObjectLiteral::Property::COMPUTED: + if (key->handle()->IsSymbol()) { + Visit(value); + Move(r0, value->location()); + __ mov(r2, Operand(key->handle())); + Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Initialize)); + __ Call(ic, RelocInfo::CODE_TARGET); + // StoreIC leaves the receiver on the stack. + break; + } + // Fall through. + case ObjectLiteral::Property::PROTOTYPE: __ push(r0); Visit(key); - ASSERT(key->location().is_temporary()); + ASSERT(key->location().is_value()); Visit(value); - ASSERT(value->location().is_temporary()); + ASSERT(value->location().is_value()); __ CallRuntime(Runtime::kSetProperty, 3); __ ldr(r0, MemOperand(sp)); // Restore result into r0 break; - case ObjectLiteral::Property::SETTER: // fall through - case ObjectLiteral::Property::GETTER: + + case ObjectLiteral::Property::GETTER: // Fall through. + case ObjectLiteral::Property::SETTER: __ push(r0); Visit(key); - ASSERT(key->location().is_temporary()); + ASSERT(key->location().is_value()); __ mov(r1, Operand(property->kind() == ObjectLiteral::Property::SETTER ? Smi::FromInt(1) : Smi::FromInt(0))); __ push(r1); Visit(value); - ASSERT(value->location().is_temporary()); + ASSERT(value->location().is_value()); __ CallRuntime(Runtime::kDefineAccessor, 4); __ ldr(r0, MemOperand(sp)); // Restore result into r0 break; - default: UNREACHABLE(); } } switch (expr->location().type()) { - case Location::NOWHERE: + case Location::kUninitialized: + UNREACHABLE(); + case Location::kEffect: if (result_saved) __ pop(); break; - case Location::TEMP: + case Location::kValue: if (!result_saved) __ push(r0); break; } } -void FastCodeGenerator::VisitRegExpLiteral(RegExpLiteral* expr) { - Comment cmnt(masm_, "[ RegExp Literal"); - Label done; - // Registers will be used as follows: - // r4 = JS function, literals array - // r3 = literal index - // r2 = RegExp pattern - // r1 = RegExp flags - // r0 = temp + return value (RegExp literal) - __ ldr(r0, MemOperand(fp, JavaScriptFrameConstants::kFunctionOffset)); - __ ldr(r4, FieldMemOperand(r0, JSFunction::kLiteralsOffset)); - int literal_offset = - FixedArray::kHeaderSize + expr->literal_index() * kPointerSize; - __ ldr(r0, FieldMemOperand(r4, literal_offset)); - __ LoadRoot(ip, Heap::kUndefinedValueRootIndex); - __ cmp(r0, ip); - __ b(ne, &done); - __ mov(r3, Operand(Smi::FromInt(expr->literal_index()))); - __ mov(r2, Operand(expr->pattern())); - __ mov(r1, Operand(expr->flags())); - __ stm(db_w, sp, r4.bit() | r3.bit() | r2.bit() | r1.bit()); - __ CallRuntime(Runtime::kMaterializeRegExpLiteral, 4); - __ bind(&done); - Move(expr->location(), r0); -} - - void FastCodeGenerator::VisitArrayLiteral(ArrayLiteral* expr) { Comment cmnt(masm_, "[ ArrayLiteral"); Label make_clone; @@ -400,7 +423,7 @@ void FastCodeGenerator::VisitArrayLiteral(ArrayLiteral* expr) { result_saved = true; } Visit(subexpr); - ASSERT(subexpr->location().is_temporary()); + ASSERT(subexpr->location().is_value()); // Store the subexpression value in the array's elements. __ pop(r0); // Subexpression value. @@ -416,10 +439,12 @@ void FastCodeGenerator::VisitArrayLiteral(ArrayLiteral* expr) { } switch (expr->location().type()) { - case Location::NOWHERE: + case Location::kUninitialized: + UNREACHABLE(); + case Location::kEffect: if (result_saved) __ pop(); break; - case Location::TEMP: + case Location::kValue: if (!result_saved) __ push(r0); break; } @@ -446,7 +471,7 @@ void FastCodeGenerator::VisitAssignment(Assignment* expr) { if (rhs->AsLiteral() != NULL) { __ mov(r0, Operand(rhs->AsLiteral()->handle())); } else { - ASSERT(rhs->location().is_temporary()); + ASSERT(rhs->location().is_value()); Visit(rhs); __ pop(r0); } @@ -468,15 +493,17 @@ void FastCodeGenerator::VisitAssignment(Assignment* expr) { __ str(ip, MemOperand(fp, SlotOffset(var->slot()))); Move(expr->location(), ip); } else { - ASSERT(rhs->location().is_temporary()); + ASSERT(rhs->location().is_value()); Visit(rhs); // Load right-hand side into ip. switch (expr->location().type()) { - case Location::NOWHERE: + case Location::kUninitialized: + UNREACHABLE(); + case Location::kEffect: // Case 'var = temp'. Discard right-hand-side temporary. __ pop(ip); break; - case Location::TEMP: + case Location::kValue: // Case 'temp1 <- (var = temp0)'. Preserve right-hand-side // temporary on the stack. __ ldr(ip, MemOperand(sp)); @@ -522,10 +549,12 @@ void FastCodeGenerator::VisitProperty(Property* expr) { __ pop(); } switch (expr->location().type()) { - case Location::TEMP: + case Location::kUninitialized: + UNREACHABLE(); + case Location::kValue: __ str(r0, MemOperand(sp)); break; - case Location::NOWHERE: + case Location::kEffect: __ pop(); } } @@ -546,7 +575,7 @@ void FastCodeGenerator::VisitCall(Call* expr) { int arg_count = args->length(); for (int i = 0; i < arg_count; i++) { Visit(args->at(i)); - ASSERT(args->at(i)->location().is_temporary()); + ASSERT(args->at(i)->location().is_value()); } // Record source position for debugger SetSourcePosition(expr->position()); @@ -567,7 +596,7 @@ void FastCodeGenerator::VisitCallNew(CallNew* node) { // arguments. // Push function on the stack. Visit(node->expression()); - ASSERT(node->expression()->location().is_temporary()); + ASSERT(node->expression()->location().is_value()); // Push global object (receiver). __ ldr(r0, CodeGenerator::GlobalObject()); @@ -577,8 +606,8 @@ void FastCodeGenerator::VisitCallNew(CallNew* node) { int arg_count = args->length(); for (int i = 0; i < arg_count; i++) { Visit(args->at(i)); - ASSERT(args->at(i)->location().is_temporary()); - // If location is temporary, it is already on the stack, + ASSERT(args->at(i)->location().is_value()); + // If location is value, it is already on the stack, // so nothing to do here. } @@ -610,7 +639,7 @@ void FastCodeGenerator::VisitCallRuntime(CallRuntime* expr) { int arg_count = args->length(); for (int i = 0; i < arg_count; i++) { Visit(args->at(i)); - ASSERT(args->at(i)->location().is_temporary()); + ASSERT(args->at(i)->location().is_value()); } __ CallRuntime(function, arg_count); @@ -619,11 +648,57 @@ void FastCodeGenerator::VisitCallRuntime(CallRuntime* expr) { void FastCodeGenerator::VisitBinaryOperation(BinaryOperation* expr) { - // Compile a short-circuited boolean or operation in a non-test - // context. - ASSERT(expr->op() == Token::OR); + switch (expr->op()) { + case Token::COMMA: + ASSERT(expr->left()->location().is_effect()); + ASSERT_EQ(expr->right()->location().type(), expr->location().type()); + Visit(expr->left()); + Visit(expr->right()); + break; + + case Token::OR: + case Token::AND: + EmitLogicalOperation(expr); + break; + + case Token::ADD: + case Token::SUB: + case Token::DIV: + case Token::MOD: + case Token::MUL: + case Token::BIT_OR: + case Token::BIT_AND: + case Token::BIT_XOR: + case Token::SHL: + case Token::SHR: + case Token::SAR: { + ASSERT(expr->left()->location().is_value()); + ASSERT(expr->right()->location().is_value()); + + Visit(expr->left()); + Visit(expr->right()); + __ pop(r0); + __ pop(r1); + GenericBinaryOpStub stub(expr->op(), + NO_OVERWRITE); + __ CallStub(&stub); + Move(expr->location(), r0); + + break; + } + default: + UNREACHABLE(); + } +} + + +void FastCodeGenerator::EmitLogicalOperation(BinaryOperation* expr) { + // Compile a short-circuited boolean operation in a non-test context. + // Compile (e0 || e1) as if it were // (let (temp = e0) temp ? temp : e1). + // Compile (e0 && e1) as if it were + // (let (temp = e0) !temp ? temp : e1). Label done; Location destination = expr->location(); @@ -636,31 +711,31 @@ void FastCodeGenerator::VisitBinaryOperation(BinaryOperation* expr) { if (left->AsLiteral() != NULL) { __ mov(r0, Operand(left->AsLiteral()->handle())); __ push(r0); - if (destination.is_temporary()) __ push(r0); + if (destination.is_value()) __ push(r0); } else { Visit(left); - ASSERT(left->location().is_temporary()); - if (destination.is_temporary()) { + ASSERT(left->location().is_value()); + if (destination.is_value()) { __ ldr(r0, MemOperand(sp)); __ push(r0); } } // The left-hand value is in on top of the stack. It is duplicated on the - // stack iff the destination location is temporary. + // stack iff the destination location is value. __ CallRuntime(Runtime::kToBool, 1); - __ LoadRoot(ip, Heap::kTrueValueRootIndex); + if (expr->op() == Token::OR) { + __ LoadRoot(ip, Heap::kTrueValueRootIndex); + } else { + __ LoadRoot(ip, Heap::kFalseValueRootIndex); + } __ cmp(r0, ip); __ b(eq, &done); // Discard the left-hand value if present on the stack. - if (destination.is_temporary()) __ pop(); + if (destination.is_value()) __ pop(); // Save or discard the right-hand value as needed. - if (right->AsLiteral() != NULL) { - Move(destination, right->AsLiteral()); - } else { - Visit(right); - Move(destination, right->location()); - } + Visit(right); + ASSERT_EQ(destination.type(), right->location().type()); __ bind(&done); } diff --git a/deps/v8/src/arm/frames-arm.cc b/deps/v8/src/arm/frames-arm.cc index b0fa13a5a1..6fde4b73c0 100644 --- a/deps/v8/src/arm/frames-arm.cc +++ b/deps/v8/src/arm/frames-arm.cc @@ -54,24 +54,23 @@ StackFrame::Type ExitFrame::GetStateForFramePointer(Address fp, State* state) { if (fp == 0) return NONE; // Compute frame type and stack pointer. Address sp = fp + ExitFrameConstants::kSPDisplacement; - const int offset = ExitFrameConstants::kCodeOffset; - Object* code = Memory::Object_at(fp + offset); - bool is_debug_exit = code->IsSmi(); - if (is_debug_exit) { + Type type; + if (Memory::Address_at(fp + ExitFrameConstants::kDebugMarkOffset) != 0) { + type = EXIT_DEBUG; sp -= kNumJSCallerSaved * kPointerSize; + } else { + type = EXIT; } // Fill in the state. state->sp = sp; state->fp = fp; state->pc_address = reinterpret_cast<Address*>(sp - 1 * kPointerSize); - return EXIT; + return type; } void ExitFrame::Iterate(ObjectVisitor* v) const { - v->VisitPointer(&code_slot()); - // The arguments are traversed as part of the expression stack of - // the calling frame. + // Do nothing } diff --git a/deps/v8/src/arm/frames-arm.h b/deps/v8/src/arm/frames-arm.h index 4924c1aeb9..0874c09274 100644 --- a/deps/v8/src/arm/frames-arm.h +++ b/deps/v8/src/arm/frames-arm.h @@ -100,7 +100,7 @@ class ExitFrameConstants : public AllStatic { static const int kSPDisplacement = -1 * kPointerSize; // The debug marker is just above the frame pointer. - static const int kCodeOffset = -1 * kPointerSize; + static const int kDebugMarkOffset = -1 * kPointerSize; static const int kSavedRegistersOffset = 0 * kPointerSize; diff --git a/deps/v8/src/arm/macro-assembler-arm.cc b/deps/v8/src/arm/macro-assembler-arm.cc index dc73bad93f..45c6540eeb 100644 --- a/deps/v8/src/arm/macro-assembler-arm.cc +++ b/deps/v8/src/arm/macro-assembler-arm.cc @@ -274,7 +274,9 @@ void MacroAssembler::LeaveFrame(StackFrame::Type type) { } -void MacroAssembler::EnterExitFrame(ExitFrame::Mode mode) { +void MacroAssembler::EnterExitFrame(StackFrame::Type type) { + ASSERT(type == StackFrame::EXIT || type == StackFrame::EXIT_DEBUG); + // Compute the argv pointer and keep it in a callee-saved register. // r0 is argc. add(r6, sp, Operand(r0, LSL, kPointerSizeLog2)); @@ -296,11 +298,8 @@ void MacroAssembler::EnterExitFrame(ExitFrame::Mode mode) { stm(db_w, sp, fp.bit() | ip.bit() | lr.bit()); mov(fp, Operand(sp)); // setup new frame pointer - if (mode == ExitFrame::MODE_DEBUG) { - mov(ip, Operand(Smi::FromInt(0))); - } else { - mov(ip, Operand(CodeObject())); - } + // Push debug marker. + mov(ip, Operand(type == StackFrame::EXIT_DEBUG ? 1 : 0)); push(ip); // Save the frame pointer and the context in top. @@ -317,7 +316,7 @@ void MacroAssembler::EnterExitFrame(ExitFrame::Mode mode) { #ifdef ENABLE_DEBUGGER_SUPPORT // Save the state of all registers to the stack from the memory // location. This is needed to allow nested break points. - if (mode == ExitFrame::MODE_DEBUG) { + if (type == StackFrame::EXIT_DEBUG) { // Use sp as base to push. CopyRegistersFromMemoryToStack(sp, kJSCallerSaved); } @@ -349,14 +348,14 @@ void MacroAssembler::AlignStack(int offset) { } -void MacroAssembler::LeaveExitFrame(ExitFrame::Mode mode) { +void MacroAssembler::LeaveExitFrame(StackFrame::Type type) { #ifdef ENABLE_DEBUGGER_SUPPORT // Restore the memory copy of the registers by digging them out from // the stack. This is needed to allow nested break points. - if (mode == ExitFrame::MODE_DEBUG) { + if (type == StackFrame::EXIT_DEBUG) { // This code intentionally clobbers r2 and r3. const int kCallerSavedSize = kNumJSCallerSaved * kPointerSize; - const int kOffset = ExitFrameConstants::kCodeOffset - kCallerSavedSize; + const int kOffset = ExitFrameConstants::kDebugMarkOffset - kCallerSavedSize; add(r3, fp, Operand(kOffset)); CopyRegistersFromStackToMemory(r3, r2, kJSCallerSaved); } diff --git a/deps/v8/src/arm/macro-assembler-arm.h b/deps/v8/src/arm/macro-assembler-arm.h index 6dc2b7ae89..e37bb5e1c2 100644 --- a/deps/v8/src/arm/macro-assembler-arm.h +++ b/deps/v8/src/arm/macro-assembler-arm.h @@ -87,14 +87,14 @@ class MacroAssembler: public Assembler { void EnterConstructFrame() { EnterFrame(StackFrame::CONSTRUCT); } void LeaveConstructFrame() { LeaveFrame(StackFrame::CONSTRUCT); } - // Enter specific kind of exit frame; either normal or debug mode. - // Expects the number of arguments in register r0 and + // Enter specific kind of exit frame; either EXIT or + // EXIT_DEBUG. Expects the number of arguments in register r0 and // the builtin function to call in register r1. Exits with argc in // r4, argv in r6, and and the builtin function to call in r5. - void EnterExitFrame(ExitFrame::Mode mode); + void EnterExitFrame(StackFrame::Type type); // Leave the current exit frame. Expects the return value in r0. - void LeaveExitFrame(ExitFrame::Mode mode); + void LeaveExitFrame(StackFrame::Type type); // Align the stack by optionally pushing a Smi zero. void AlignStack(int offset); diff --git a/deps/v8/src/assembler.cc b/deps/v8/src/assembler.cc index 34346a9105..34595f83ff 100644 --- a/deps/v8/src/assembler.cc +++ b/deps/v8/src/assembler.cc @@ -522,10 +522,6 @@ ExternalReference::ExternalReference(Builtins::CFunctionId id) : address_(Redirect(Builtins::c_function_address(id))) {} -ExternalReference::ExternalReference(ApiFunction* fun) - : address_(Redirect(fun->address())) {} - - ExternalReference::ExternalReference(Builtins::Name name) : address_(Builtins::builtin_address(name)) {} @@ -612,27 +608,6 @@ ExternalReference ExternalReference::new_space_allocation_limit_address() { return ExternalReference(Heap::NewSpaceAllocationLimitAddress()); } - -ExternalReference ExternalReference::handle_scope_extensions_address() { - return ExternalReference(HandleScope::current_extensions_address()); -} - - -ExternalReference ExternalReference::handle_scope_next_address() { - return ExternalReference(HandleScope::current_next_address()); -} - - -ExternalReference ExternalReference::handle_scope_limit_address() { - return ExternalReference(HandleScope::current_limit_address()); -} - - -ExternalReference ExternalReference::scheduled_exception_address() { - return ExternalReference(Top::scheduled_exception_address()); -} - - #ifdef V8_NATIVE_REGEXP ExternalReference ExternalReference::re_check_stack_guard_state() { diff --git a/deps/v8/src/assembler.h b/deps/v8/src/assembler.h index 311dadd53c..21a66dd501 100644 --- a/deps/v8/src/assembler.h +++ b/deps/v8/src/assembler.h @@ -373,8 +373,6 @@ class ExternalReference BASE_EMBEDDED { public: explicit ExternalReference(Builtins::CFunctionId id); - explicit ExternalReference(ApiFunction* ptr); - explicit ExternalReference(Builtins::Name name); explicit ExternalReference(Runtime::FunctionId id); @@ -424,12 +422,6 @@ class ExternalReference BASE_EMBEDDED { static ExternalReference double_fp_operation(Token::Value operation); static ExternalReference compare_doubles(); - static ExternalReference handle_scope_extensions_address(); - static ExternalReference handle_scope_next_address(); - static ExternalReference handle_scope_limit_address(); - - static ExternalReference scheduled_exception_address(); - Address address() const {return reinterpret_cast<Address>(address_);} #ifdef ENABLE_DEBUGGER_SUPPORT diff --git a/deps/v8/src/ast.h b/deps/v8/src/ast.h index 9b7d9ddb05..be64dcb3c6 100644 --- a/deps/v8/src/ast.h +++ b/deps/v8/src/ast.h @@ -162,7 +162,7 @@ class Statement: public AstNode { class Expression: public AstNode { public: - Expression() : location_(Location::Temporary()) {} + Expression() : location_(Location::Uninitialized()) {} virtual Expression* AsExpression() { return this; } diff --git a/deps/v8/src/code-stubs.cc b/deps/v8/src/code-stubs.cc index 7a2f859459..73ff0115f2 100644 --- a/deps/v8/src/code-stubs.cc +++ b/deps/v8/src/code-stubs.cc @@ -36,27 +36,10 @@ namespace v8 { namespace internal { Handle<Code> CodeStub::GetCode() { - bool custom_cache = has_custom_cache(); - - int index = 0; - uint32_t key = 0; - if (custom_cache) { - Code* cached; - if (GetCustomCache(&cached)) { - return Handle<Code>(cached); - } else { - index = NumberDictionary::kNotFound; - } - } else { - key = GetKey(); - index = Heap::code_stubs()->FindEntry(key); - if (index != NumberDictionary::kNotFound) - return Handle<Code>(Code::cast(Heap::code_stubs()->ValueAt(index))); - } - - Code* result; - { - v8::HandleScope scope; + uint32_t key = GetKey(); + int index = Heap::code_stubs()->FindEntry(key); + if (index == NumberDictionary::kNotFound) { + HandleScope scope; // Update the static counter each time a new code stub is generated. Counters::code_stubs.Increment(); @@ -96,21 +79,18 @@ Handle<Code> CodeStub::GetCode() { } #endif - if (custom_cache) { - SetCustomCache(*code); - } else { - // Update the dictionary and the root in Heap. - Handle<NumberDictionary> dict = - Factory::DictionaryAtNumberPut( - Handle<NumberDictionary>(Heap::code_stubs()), - key, - code); - Heap::public_set_code_stubs(*dict); - } - result = *code; + // Update the dictionary and the root in Heap. + Handle<NumberDictionary> dict = + Factory::DictionaryAtNumberPut( + Handle<NumberDictionary>(Heap::code_stubs()), + key, + code); + Heap::public_set_code_stubs(*dict); + index = Heap::code_stubs()->FindEntry(key); } + ASSERT(index != NumberDictionary::kNotFound); - return Handle<Code>(result); + return Handle<Code>(Code::cast(Heap::code_stubs()->ValueAt(index))); } diff --git a/deps/v8/src/code-stubs.h b/deps/v8/src/code-stubs.h index 63461bc0c0..121140d1ba 100644 --- a/deps/v8/src/code-stubs.h +++ b/deps/v8/src/code-stubs.h @@ -75,7 +75,6 @@ class CodeStub BASE_EMBEDDED { #define DEF_ENUM(name) name, CODE_STUB_LIST(DEF_ENUM) #undef DEF_ENUM - NoCache, // marker for stubs that do custom caching NUMBER_OF_IDS }; @@ -92,12 +91,6 @@ class CodeStub BASE_EMBEDDED { virtual ~CodeStub() {} - // Override these methods to provide a custom caching mechanism for - // an individual type of code stub. - virtual bool GetCustomCache(Code** code_out) { return false; } - virtual void SetCustomCache(Code* value) { } - virtual bool has_custom_cache() { return false; } - protected: static const int kMajorBits = 5; static const int kMinorBits = kBitsPerInt - kSmiTagSize - kMajorBits; diff --git a/deps/v8/src/codegen.cc b/deps/v8/src/codegen.cc index f2788a8838..28c0ba5f9e 100644 --- a/deps/v8/src/codegen.cc +++ b/deps/v8/src/codegen.cc @@ -551,20 +551,4 @@ void ArgumentsAccessStub::Generate(MacroAssembler* masm) { } -bool ApiGetterEntryStub::GetCustomCache(Code** code_out) { - Object* cache = info()->load_stub_cache(); - if (cache->IsUndefined()) { - return false; - } else { - *code_out = Code::cast(cache); - return true; - } -} - - -void ApiGetterEntryStub::SetCustomCache(Code* value) { - info()->set_load_stub_cache(value); -} - - } } // namespace v8::internal diff --git a/deps/v8/src/codegen.h b/deps/v8/src/codegen.h index fc4a53b2e7..8c1b733675 100644 --- a/deps/v8/src/codegen.h +++ b/deps/v8/src/codegen.h @@ -301,7 +301,7 @@ class CEntryStub : public CodeStub { Label* throw_normal_exception, Label* throw_termination_exception, Label* throw_out_of_memory_exception, - ExitFrame::Mode mode, + StackFrame::Type frame_type, bool do_gc, bool always_allocate_scope); void GenerateThrowTOS(MacroAssembler* masm); @@ -320,32 +320,6 @@ class CEntryStub : public CodeStub { }; -class ApiGetterEntryStub : public CodeStub { - public: - ApiGetterEntryStub(Handle<AccessorInfo> info, - ApiFunction* fun) - : info_(info), - fun_(fun) { } - void Generate(MacroAssembler* masm); - virtual bool has_custom_cache() { return true; } - virtual bool GetCustomCache(Code** code_out); - virtual void SetCustomCache(Code* value); - - static const int kStackSpace = 6; - static const int kArgc = 4; - private: - Handle<AccessorInfo> info() { return info_; } - ApiFunction* fun() { return fun_; } - Major MajorKey() { return NoCache; } - int MinorKey() { return 0; } - const char* GetName() { return "ApiEntryStub"; } - // The accessor info associated with the function. - Handle<AccessorInfo> info_; - // The function to be called. - ApiFunction* fun_; -}; - - class CEntryDebugBreakStub : public CEntryStub { public: CEntryDebugBreakStub() : CEntryStub(1) { } diff --git a/deps/v8/src/compiler.cc b/deps/v8/src/compiler.cc index bad209e138..129f1aac15 100644 --- a/deps/v8/src/compiler.cc +++ b/deps/v8/src/compiler.cc @@ -48,7 +48,7 @@ class CodeGenSelector: public AstVisitor { CodeGenSelector() : has_supported_syntax_(true), - location_(Location::Nowhere()) { + location_(Location::Uninitialized()) { } CodeGenTag Select(FunctionLiteral* fun); @@ -514,11 +514,11 @@ void CodeGenSelector::VisitStatements(ZoneList<Statement*>* stmts) { void CodeGenSelector::VisitAsEffect(Expression* expr) { - if (location_.is_nowhere()) { + if (location_.is_effect()) { Visit(expr); } else { Location saved = location_; - location_ = Location::Nowhere(); + location_ = Location::Effect(); Visit(expr); location_ = saved; } @@ -526,11 +526,11 @@ void CodeGenSelector::VisitAsEffect(Expression* expr) { void CodeGenSelector::VisitAsValue(Expression* expr) { - if (location_.is_temporary()) { + if (location_.is_value()) { Visit(expr); } else { Location saved = location_; - location_ = Location::Temporary(); + location_ = Location::Value(); Visit(expr); location_ = saved; } @@ -849,6 +849,12 @@ void CodeGenSelector::VisitCountOperation(CountOperation* expr) { void CodeGenSelector::VisitBinaryOperation(BinaryOperation* expr) { switch (expr->op()) { + case Token::COMMA: + VisitAsEffect(expr->left()); + CHECK_BAILOUT; + Visit(expr->right()); // Location is the same as the parent location. + break; + case Token::OR: VisitAsValue(expr->left()); CHECK_BAILOUT; @@ -857,6 +863,22 @@ void CodeGenSelector::VisitBinaryOperation(BinaryOperation* expr) { Visit(expr->right()); break; + case Token::ADD: + case Token::SUB: + case Token::DIV: + case Token::MOD: + case Token::MUL: + case Token::BIT_OR: + case Token::BIT_AND: + case Token::BIT_XOR: + case Token::SHL: + case Token::SHR: + case Token::SAR: + VisitAsValue(expr->left()); + CHECK_BAILOUT; + VisitAsValue(expr->right()); + break; + default: BAILOUT("Unsupported binary operation"); } diff --git a/deps/v8/src/fast-codegen.cc b/deps/v8/src/fast-codegen.cc index 8655e97a86..2f6a27a5e8 100644 --- a/deps/v8/src/fast-codegen.cc +++ b/deps/v8/src/fast-codegen.cc @@ -71,30 +71,15 @@ int FastCodeGenerator::SlotOffset(Slot* slot) { } -void FastCodeGenerator::Move(Location destination, Location source) { - switch (destination.type()) { - case Location::NOWHERE: - break; - - case Location::TEMP: - switch (source.type()) { - case Location::NOWHERE: - UNREACHABLE(); - case Location::TEMP: - break; - } - break; - } -} - - // All platform macro assemblers in {ia32,x64,arm} have a push(Register) // function. void FastCodeGenerator::Move(Location destination, Register source) { switch (destination.type()) { - case Location::NOWHERE: + case Location::kUninitialized: + UNREACHABLE(); + case Location::kEffect: break; - case Location::TEMP: + case Location::kValue: masm_->push(source); break; } @@ -105,9 +90,10 @@ void FastCodeGenerator::Move(Location destination, Register source) { // function. void FastCodeGenerator::Move(Register destination, Location source) { switch (source.type()) { - case Location::NOWHERE: + case Location::kUninitialized: // Fall through. + case Location::kEffect: UNREACHABLE(); - case Location::TEMP: + case Location::kValue: masm_->pop(destination); } } diff --git a/deps/v8/src/fast-codegen.h b/deps/v8/src/fast-codegen.h index a718157b35..31bb41c4da 100644 --- a/deps/v8/src/fast-codegen.h +++ b/deps/v8/src/fast-codegen.h @@ -51,8 +51,6 @@ class FastCodeGenerator: public AstVisitor { private: int SlotOffset(Slot* slot); - void Move(Location destination, Location source); - void Move(Location destination, Register source); void Move(Location destination, Slot* source); void Move(Location destination, Literal* source); @@ -78,6 +76,9 @@ class FastCodeGenerator: public AstVisitor { AST_NODE_LIST(DECLARE_VISIT) #undef DECLARE_VISIT + // Handles the shortcutted logical binary operations in VisitBinaryOperation. + void EmitLogicalOperation(BinaryOperation* expr); + MacroAssembler* masm_; FunctionLiteral* function_; Handle<Script> script_; diff --git a/deps/v8/src/frames.cc b/deps/v8/src/frames.cc index d7302dea3d..5cd83324c6 100644 --- a/deps/v8/src/frames.cc +++ b/deps/v8/src/frames.cc @@ -393,19 +393,8 @@ Code* EntryConstructFrame::code() const { } -Object*& ExitFrame::code_slot() const { - const int offset = ExitFrameConstants::kCodeOffset; - return Memory::Object_at(fp() + offset); -} - - Code* ExitFrame::code() const { - Object* code = code_slot(); - if (code->IsSmi()) { - return Heap::c_entry_debug_break_code(); - } else { - return Code::cast(code); - } + return Heap::c_entry_code(); } @@ -423,6 +412,11 @@ Address ExitFrame::GetCallerStackPointer() const { } +Code* ExitDebugFrame::code() const { + return Heap::c_entry_debug_break_code(); +} + + Address StandardFrame::GetExpressionAddress(int n) const { const int offset = StandardFrameConstants::kExpressionsOffset; return fp() + offset - n * kPointerSize; diff --git a/deps/v8/src/frames.h b/deps/v8/src/frames.h index 024065abf7..768196d3c6 100644 --- a/deps/v8/src/frames.h +++ b/deps/v8/src/frames.h @@ -93,6 +93,7 @@ class StackHandler BASE_EMBEDDED { V(ENTRY, EntryFrame) \ V(ENTRY_CONSTRUCT, EntryConstructFrame) \ V(EXIT, ExitFrame) \ + V(EXIT_DEBUG, ExitDebugFrame) \ V(JAVA_SCRIPT, JavaScriptFrame) \ V(INTERNAL, InternalFrame) \ V(CONSTRUCT, ConstructFrame) \ @@ -118,6 +119,7 @@ class StackFrame BASE_EMBEDDED { bool is_entry() const { return type() == ENTRY; } bool is_entry_construct() const { return type() == ENTRY_CONSTRUCT; } bool is_exit() const { return type() == EXIT; } + bool is_exit_debug() const { return type() == EXIT_DEBUG; } bool is_java_script() const { return type() == JAVA_SCRIPT; } bool is_arguments_adaptor() const { return type() == ARGUMENTS_ADAPTOR; } bool is_internal() const { return type() == INTERNAL; } @@ -258,13 +260,10 @@ class EntryConstructFrame: public EntryFrame { // Exit frames are used to exit JavaScript execution and go to C. class ExitFrame: public StackFrame { public: - enum Mode { MODE_NORMAL, MODE_DEBUG }; virtual Type type() const { return EXIT; } virtual Code* code() const; - Object*& code_slot() const; - // Garbage collection support. virtual void Iterate(ObjectVisitor* v) const; @@ -290,6 +289,26 @@ class ExitFrame: public StackFrame { }; +class ExitDebugFrame: public ExitFrame { + public: + virtual Type type() const { return EXIT_DEBUG; } + + virtual Code* code() const; + + static ExitDebugFrame* cast(StackFrame* frame) { + ASSERT(frame->is_exit_debug()); + return static_cast<ExitDebugFrame*>(frame); + } + + protected: + explicit ExitDebugFrame(StackFrameIterator* iterator) + : ExitFrame(iterator) { } + + private: + friend class StackFrameIterator; +}; + + class StandardFrame: public StackFrame { public: // Testers. diff --git a/deps/v8/src/globals.h b/deps/v8/src/globals.h index ae10b72de7..fbb648f5b1 100644 --- a/deps/v8/src/globals.h +++ b/deps/v8/src/globals.h @@ -103,10 +103,6 @@ typedef byte* Address; #define V8PRIxPTR "lx" #endif -#if defined(__APPLE__) && defined(__MACH__) -#define USING_MAC_ABI -#endif - // Code-point values in Unicode 4.0 are 21 bits wide. typedef uint16_t uc16; typedef int32_t uc32; diff --git a/deps/v8/src/handles.cc b/deps/v8/src/handles.cc index 275fe6a7c1..b764334e83 100644 --- a/deps/v8/src/handles.cc +++ b/deps/v8/src/handles.cc @@ -105,21 +105,6 @@ void HandleScope::ZapRange(Object** start, Object** end) { } -Address HandleScope::current_extensions_address() { - return reinterpret_cast<Address>(¤t_.extensions); -} - - -Address HandleScope::current_next_address() { - return reinterpret_cast<Address>(¤t_.next); -} - - -Address HandleScope::current_limit_address() { - return reinterpret_cast<Address>(¤t_.limit); -} - - Handle<FixedArray> AddKeysFromJSArray(Handle<FixedArray> content, Handle<JSArray> array) { CALL_HEAP_FUNCTION(content->AddKeysFromJSArray(*array), FixedArray); diff --git a/deps/v8/src/handles.h b/deps/v8/src/handles.h index d3e9b788b5..5d574657c5 100644 --- a/deps/v8/src/handles.h +++ b/deps/v8/src/handles.h @@ -133,13 +133,6 @@ class HandleScope { return result; } - // Deallocates any extensions used by the current scope. - static void DeleteExtensions(); - - static Address current_extensions_address(); - static Address current_next_address(); - static Address current_limit_address(); - private: // Prevent heap allocation or illegal handle scopes. HandleScope(const HandleScope&); @@ -173,6 +166,9 @@ class HandleScope { // Extend the handle scope making room for more handles. static internal::Object** Extend(); + // Deallocates any extensions used by the current scope. + static void DeleteExtensions(); + // Zaps the handles in the half-open interval [start, end). static void ZapRange(internal::Object** start, internal::Object** end); diff --git a/deps/v8/src/ia32/codegen-ia32.cc b/deps/v8/src/ia32/codegen-ia32.cc index 8e8ff2e0b1..4ac5527699 100644 --- a/deps/v8/src/ia32/codegen-ia32.cc +++ b/deps/v8/src/ia32/codegen-ia32.cc @@ -7707,84 +7707,11 @@ void CEntryStub::GenerateThrowTOS(MacroAssembler* masm) { } -// If true, a Handle<T> passed by value is passed and returned by -// using the location_ field directly. If false, it is passed and -// returned as a pointer to a handle. -#ifdef USING_MAC_ABI -static const bool kPassHandlesDirectly = true; -#else -static const bool kPassHandlesDirectly = false; -#endif - - -void ApiGetterEntryStub::Generate(MacroAssembler* masm) { - Label get_result; - Label prologue; - Label promote_scheduled_exception; - __ EnterApiExitFrame(ExitFrame::MODE_NORMAL, kStackSpace, kArgc); - ASSERT_EQ(kArgc, 4); - if (kPassHandlesDirectly) { - // When handles as passed directly we don't have to allocate extra - // space for and pass an out parameter. - __ mov(Operand(esp, 0 * kPointerSize), ebx); // name. - __ mov(Operand(esp, 1 * kPointerSize), eax); // arguments pointer. - } else { - // The function expects three arguments to be passed but we allocate - // four to get space for the output cell. The argument slots are filled - // as follows: - // - // 3: output cell - // 2: arguments pointer - // 1: name - // 0: pointer to the output cell - // - // Note that this is one more "argument" than the function expects - // so the out cell will have to be popped explicitly after returning - // from the function. - __ mov(Operand(esp, 1 * kPointerSize), ebx); // name. - __ mov(Operand(esp, 2 * kPointerSize), eax); // arguments pointer. - __ mov(ebx, esp); - __ add(Operand(ebx), Immediate(3 * kPointerSize)); - __ mov(Operand(esp, 0 * kPointerSize), ebx); // output - __ mov(Operand(esp, 3 * kPointerSize), Immediate(0)); // out cell. - } - // Call the api function! - __ call(fun()->address(), RelocInfo::RUNTIME_ENTRY); - // Check if the function scheduled an exception. - ExternalReference scheduled_exception_address = - ExternalReference::scheduled_exception_address(); - __ cmp(Operand::StaticVariable(scheduled_exception_address), - Immediate(Factory::the_hole_value())); - __ j(not_equal, &promote_scheduled_exception, not_taken); - if (!kPassHandlesDirectly) { - // The returned value is a pointer to the handle holding the result. - // Dereference this to get to the location. - __ mov(eax, Operand(eax, 0)); - } - // Check if the result handle holds 0 - __ test(eax, Operand(eax)); - __ j(not_zero, &get_result, taken); - // It was zero; the result is undefined. - __ mov(eax, Factory::undefined_value()); - __ jmp(&prologue); - // It was non-zero. Dereference to get the result value. - __ bind(&get_result); - __ mov(eax, Operand(eax, 0)); - __ bind(&prologue); - __ LeaveExitFrame(ExitFrame::MODE_NORMAL); - __ ret(0); - __ bind(&promote_scheduled_exception); - __ TailCallRuntime(ExternalReference(Runtime::kPromoteScheduledException), - 0, - 1); -} - - void CEntryStub::GenerateCore(MacroAssembler* masm, Label* throw_normal_exception, Label* throw_termination_exception, Label* throw_out_of_memory_exception, - ExitFrame::Mode mode, + StackFrame::Type frame_type, bool do_gc, bool always_allocate_scope) { // eax: result parameter for PerformGC, if any @@ -7834,7 +7761,7 @@ void CEntryStub::GenerateCore(MacroAssembler* masm, __ j(zero, &failure_returned, not_taken); // Exit the JavaScript to C++ exit frame. - __ LeaveExitFrame(mode); + __ LeaveExitFrame(frame_type); __ ret(0); // Handling of failure. @@ -7933,12 +7860,12 @@ void CEntryStub::GenerateBody(MacroAssembler* masm, bool is_debug_break) { // of a proper result. The builtin entry handles this by performing // a garbage collection and retrying the builtin (twice). - ExitFrame::Mode mode = is_debug_break - ? ExitFrame::MODE_DEBUG - : ExitFrame::MODE_NORMAL; + StackFrame::Type frame_type = is_debug_break ? + StackFrame::EXIT_DEBUG : + StackFrame::EXIT; // Enter the exit frame that transitions from JavaScript to C++. - __ EnterExitFrame(mode); + __ EnterExitFrame(frame_type); // eax: result parameter for PerformGC, if any (setup below) // ebx: pointer to builtin function (C callee-saved) @@ -7956,7 +7883,7 @@ void CEntryStub::GenerateBody(MacroAssembler* masm, bool is_debug_break) { &throw_normal_exception, &throw_termination_exception, &throw_out_of_memory_exception, - mode, + frame_type, false, false); @@ -7965,7 +7892,7 @@ void CEntryStub::GenerateBody(MacroAssembler* masm, bool is_debug_break) { &throw_normal_exception, &throw_termination_exception, &throw_out_of_memory_exception, - mode, + frame_type, true, false); @@ -7976,7 +7903,7 @@ void CEntryStub::GenerateBody(MacroAssembler* masm, bool is_debug_break) { &throw_normal_exception, &throw_termination_exception, &throw_out_of_memory_exception, - mode, + frame_type, true, true); diff --git a/deps/v8/src/ia32/fast-codegen-ia32.cc b/deps/v8/src/ia32/fast-codegen-ia32.cc index 0d661c3b67..247f124962 100644 --- a/deps/v8/src/ia32/fast-codegen-ia32.cc +++ b/deps/v8/src/ia32/fast-codegen-ia32.cc @@ -110,9 +110,11 @@ void FastCodeGenerator::Generate(FunctionLiteral* fun) { void FastCodeGenerator::Move(Location destination, Slot* source) { switch (destination.type()) { - case Location::NOWHERE: + case Location::kUninitialized: + UNREACHABLE(); + case Location::kEffect: break; - case Location::TEMP: + case Location::kValue: __ push(Operand(ebp, SlotOffset(source))); break; } @@ -121,9 +123,11 @@ void FastCodeGenerator::Move(Location destination, Slot* source) { void FastCodeGenerator::Move(Location destination, Literal* expr) { switch (destination.type()) { - case Location::NOWHERE: + case Location::kUninitialized: + UNREACHABLE(); + case Location::kEffect: break; - case Location::TEMP: + case Location::kValue: __ push(Immediate(expr->handle())); break; } @@ -132,9 +136,10 @@ void FastCodeGenerator::Move(Location destination, Literal* expr) { void FastCodeGenerator::Move(Slot* destination, Location source) { switch (source.type()) { - case Location::NOWHERE: + case Location::kUninitialized: // Fall through. + case Location::kEffect: UNREACHABLE(); - case Location::TEMP: + case Location::kValue: __ pop(Operand(ebp, SlotOffset(destination))); break; } @@ -143,10 +148,12 @@ void FastCodeGenerator::Move(Slot* destination, Location source) { void FastCodeGenerator::DropAndMove(Location destination, Register source) { switch (destination.type()) { - case Location::NOWHERE: + case Location::kUninitialized: + UNREACHABLE(); + case Location::kEffect: __ add(Operand(esp), Immediate(kPointerSize)); break; - case Location::TEMP: + case Location::kValue: __ mov(Operand(esp, 0), source); break; } @@ -231,6 +238,33 @@ void FastCodeGenerator::VisitVariableProxy(VariableProxy* expr) { } +void FastCodeGenerator::VisitRegExpLiteral(RegExpLiteral* expr) { + Comment cmnt(masm_, "[ RegExp Literal"); + Label done; + // Registers will be used as follows: + // edi = JS function. + // ebx = literals array. + // eax = regexp literal. + __ mov(edi, Operand(ebp, JavaScriptFrameConstants::kFunctionOffset)); + __ mov(ebx, FieldOperand(edi, JSFunction::kLiteralsOffset)); + int literal_offset = + FixedArray::kHeaderSize + expr->literal_index() * kPointerSize; + __ mov(eax, FieldOperand(ebx, literal_offset)); + __ cmp(eax, Factory::undefined_value()); + __ j(not_equal, &done); + // Create regexp literal using runtime function + // Result will be in eax. + __ push(ebx); + __ push(Immediate(Smi::FromInt(expr->literal_index()))); + __ push(Immediate(expr->pattern())); + __ push(Immediate(expr->flags())); + __ CallRuntime(Runtime::kMaterializeRegExpLiteral, 4); + // Label done: + __ bind(&done); + Move(expr->location(), eax); +} + + void FastCodeGenerator::VisitObjectLiteral(ObjectLiteral* expr) { Comment cmnt(masm_, "[ ObjectLiteral"); Label exists; @@ -295,9 +329,9 @@ void FastCodeGenerator::VisitObjectLiteral(ObjectLiteral* expr) { case ObjectLiteral::Property::PROTOTYPE: __ push(eax); Visit(key); - ASSERT(key->location().is_temporary()); + ASSERT(key->location().is_value()); Visit(value); - ASSERT(value->location().is_temporary()); + ASSERT(value->location().is_value()); __ CallRuntime(Runtime::kSetProperty, 3); __ mov(eax, Operand(esp, 0)); // Restore result into eax. break; @@ -305,12 +339,12 @@ void FastCodeGenerator::VisitObjectLiteral(ObjectLiteral* expr) { case ObjectLiteral::Property::GETTER: __ push(eax); Visit(key); - ASSERT(key->location().is_temporary()); + ASSERT(key->location().is_value()); __ push(Immediate(property->kind() == ObjectLiteral::Property::SETTER ? Smi::FromInt(1) : Smi::FromInt(0))); Visit(value); - ASSERT(value->location().is_temporary()); + ASSERT(value->location().is_value()); __ CallRuntime(Runtime::kDefineAccessor, 4); __ mov(eax, Operand(esp, 0)); // Restore result into eax. break; @@ -318,43 +352,18 @@ void FastCodeGenerator::VisitObjectLiteral(ObjectLiteral* expr) { } } switch (expr->location().type()) { - case Location::NOWHERE: + case Location::kUninitialized: + UNREACHABLE(); + case Location::kEffect: if (result_saved) __ add(Operand(esp), Immediate(kPointerSize)); break; - case Location::TEMP: + case Location::kValue: if (!result_saved) __ push(eax); break; } } -void FastCodeGenerator::VisitRegExpLiteral(RegExpLiteral* expr) { - Comment cmnt(masm_, "[ RegExp Literal"); - Label done; - // Registers will be used as follows: - // edi = JS function. - // ebx = literals array. - // eax = regexp literal. - __ mov(edi, Operand(ebp, JavaScriptFrameConstants::kFunctionOffset)); - __ mov(ebx, FieldOperand(edi, JSFunction::kLiteralsOffset)); - int literal_offset = - FixedArray::kHeaderSize + expr->literal_index() * kPointerSize; - __ mov(eax, FieldOperand(ebx, literal_offset)); - __ cmp(eax, Factory::undefined_value()); - __ j(not_equal, &done); - // Create regexp literal using runtime function - // Result will be in eax. - __ push(ebx); - __ push(Immediate(Smi::FromInt(expr->literal_index()))); - __ push(Immediate(expr->pattern())); - __ push(Immediate(expr->flags())); - __ CallRuntime(Runtime::kMaterializeRegExpLiteral, 4); - // Label done: - __ bind(&done); - Move(expr->location(), eax); -} - - void FastCodeGenerator::VisitArrayLiteral(ArrayLiteral* expr) { Comment cmnt(masm_, "[ ArrayLiteral"); Label make_clone; @@ -403,7 +412,7 @@ void FastCodeGenerator::VisitArrayLiteral(ArrayLiteral* expr) { result_saved = true; } Visit(subexpr); - ASSERT(subexpr->location().is_temporary()); + ASSERT(subexpr->location().is_value()); // Store the subexpression value in the array's elements. __ pop(eax); // Subexpression value. @@ -417,10 +426,12 @@ void FastCodeGenerator::VisitArrayLiteral(ArrayLiteral* expr) { } switch (expr->location().type()) { - case Location::NOWHERE: + case Location::kUninitialized: + UNREACHABLE(); + case Location::kEffect: if (result_saved) __ add(Operand(esp), Immediate(kPointerSize)); break; - case Location::TEMP: + case Location::kValue: if (!result_saved) __ push(eax); break; } @@ -446,7 +457,7 @@ void FastCodeGenerator::VisitAssignment(Assignment* expr) { if (rhs->AsLiteral() != NULL) { __ mov(eax, rhs->AsLiteral()->handle()); } else { - ASSERT(rhs->location().is_temporary()); + ASSERT(rhs->location().is_value()); Visit(rhs); __ pop(eax); } @@ -467,14 +478,16 @@ void FastCodeGenerator::VisitAssignment(Assignment* expr) { __ mov(Operand(ebp, SlotOffset(var->slot())), eax); Move(expr->location(), eax); } else { - ASSERT(rhs->location().is_temporary()); + ASSERT(rhs->location().is_value()); Visit(rhs); switch (expr->location().type()) { - case Location::NOWHERE: + case Location::kUninitialized: + UNREACHABLE(); + case Location::kEffect: // Case 'var = temp'. Discard right-hand-side temporary. Move(var->slot(), rhs->location()); break; - case Location::TEMP: + case Location::kValue: // Case 'temp1 <- (var = temp0)'. Preserve right-hand-side // temporary on the stack. __ mov(eax, Operand(esp, 0)); @@ -519,10 +532,12 @@ void FastCodeGenerator::VisitProperty(Property* expr) { __ add(Operand(esp), Immediate(kPointerSize)); } switch (expr->location().type()) { - case Location::TEMP: + case Location::kUninitialized: + UNREACHABLE(); + case Location::kValue: __ mov(Operand(esp, 0), eax); break; - case Location::NOWHERE: + case Location::kEffect: __ add(Operand(esp), Immediate(kPointerSize)); break; } @@ -542,7 +557,7 @@ void FastCodeGenerator::VisitCall(Call* expr) { int arg_count = args->length(); for (int i = 0; i < arg_count; i++) { Visit(args->at(i)); - ASSERT(args->at(i)->location().is_temporary()); + ASSERT(args->at(i)->location().is_value()); } // Record source position for debugger SetSourcePosition(expr->position()); @@ -564,7 +579,7 @@ void FastCodeGenerator::VisitCallNew(CallNew* node) { // arguments. // Push function on the stack. Visit(node->expression()); - ASSERT(node->expression()->location().is_temporary()); + ASSERT(node->expression()->location().is_value()); // Push global object (receiver). __ push(CodeGenerator::GlobalObject()); @@ -574,8 +589,8 @@ void FastCodeGenerator::VisitCallNew(CallNew* node) { int arg_count = args->length(); for (int i = 0; i < arg_count; i++) { Visit(args->at(i)); - ASSERT(args->at(i)->location().is_temporary()); - // If location is temporary, it is already on the stack, + ASSERT(args->at(i)->location().is_value()); + // If location is value, it is already on the stack, // so nothing to do here. } @@ -607,7 +622,7 @@ void FastCodeGenerator::VisitCallRuntime(CallRuntime* expr) { int arg_count = args->length(); for (int i = 0; i < arg_count; i++) { Visit(args->at(i)); - ASSERT(args->at(i)->location().is_temporary()); + ASSERT(args->at(i)->location().is_value()); } __ CallRuntime(function, arg_count); @@ -616,13 +631,64 @@ void FastCodeGenerator::VisitCallRuntime(CallRuntime* expr) { void FastCodeGenerator::VisitBinaryOperation(BinaryOperation* expr) { - // Compile a short-circuited boolean or operation in a non-test - // context. - ASSERT(expr->op() == Token::OR); - // Compile (e0 || e1) as if it were - // (let (temp = e0) temp ? temp : e1). + switch (expr->op()) { + case Token::COMMA: + ASSERT(expr->left()->location().is_effect()); + ASSERT_EQ(expr->right()->location().type(), expr->location().type()); + Visit(expr->left()); + Visit(expr->right()); + break; + + case Token::OR: + case Token::AND: + EmitLogicalOperation(expr); + break; + + case Token::ADD: + case Token::SUB: + case Token::DIV: + case Token::MOD: + case Token::MUL: + case Token::BIT_OR: + case Token::BIT_AND: + case Token::BIT_XOR: + case Token::SHL: + case Token::SHR: + case Token::SAR: { + ASSERT(expr->left()->location().is_value()); + ASSERT(expr->right()->location().is_value()); + + Visit(expr->left()); + Visit(expr->right()); + GenericBinaryOpStub stub(expr->op(), + NO_OVERWRITE, + NO_GENERIC_BINARY_FLAGS); + __ CallStub(&stub); + Move(expr->location(), eax); + + break; + } + default: + UNREACHABLE(); + } +} + + +void FastCodeGenerator::EmitLogicalOperation(BinaryOperation* expr) { + // Compile a short-circuited boolean operation in a non-test context. + + // Compile (e0 || e1) or (e0 && e1) as if it were + // (let (temp = e0) temp [or !temp, for &&] ? temp : e1). Label eval_right, done; + Label *left_true, *left_false; // Where to branch to if lhs has that value. + if (expr->op() == Token::OR) { + left_true = &done; + left_false = &eval_right; + } else { + left_true = &eval_right; + left_false = &done; + } Location destination = expr->location(); Expression* left = expr->left(); Expression* right = expr->right(); @@ -635,17 +701,19 @@ void FastCodeGenerator::VisitBinaryOperation(BinaryOperation* expr) { // need it as the value of the whole expression. if (left->AsLiteral() != NULL) { __ mov(eax, left->AsLiteral()->handle()); - if (destination.is_temporary()) __ push(eax); + if (destination.is_value()) __ push(eax); } else { Visit(left); - ASSERT(left->location().is_temporary()); + ASSERT(left->location().is_value()); switch (destination.type()) { - case Location::NOWHERE: + case Location::kUninitialized: + UNREACHABLE(); + case Location::kEffect: // Pop the left-hand value into eax because we will not need it as the // final result. __ pop(eax); break; - case Location::TEMP: + case Location::kValue: // Copy the left-hand value into eax because we may need it as the // final result. __ mov(eax, Operand(esp, 0)); @@ -653,40 +721,40 @@ void FastCodeGenerator::VisitBinaryOperation(BinaryOperation* expr) { } } // The left-hand value is in eax. It is also on the stack iff the - // destination location is temporary. + // destination location is value. // Perform fast checks assumed by the stub. __ cmp(eax, Factory::undefined_value()); // The undefined value is false. - __ j(equal, &eval_right); + __ j(equal, left_false); __ cmp(eax, Factory::true_value()); // True is true. - __ j(equal, &done); + __ j(equal, left_true); __ cmp(eax, Factory::false_value()); // False is false. - __ j(equal, &eval_right); + __ j(equal, left_false); ASSERT(kSmiTag == 0); __ test(eax, Operand(eax)); // The smi zero is false. - __ j(zero, &eval_right); + __ j(zero, left_false); __ test(eax, Immediate(kSmiTagMask)); // All other smis are true. - __ j(zero, &done); + __ j(zero, left_true); // Call the stub for all other cases. __ push(eax); ToBooleanStub stub; __ CallStub(&stub); __ test(eax, Operand(eax)); // The stub returns nonzero for true. - __ j(not_zero, &done); + if (expr->op() == Token::OR) { + __ j(not_zero, &done); + } else { + __ j(zero, &done); + } __ bind(&eval_right); // Discard the left-hand value if present on the stack. - if (destination.is_temporary()) { + if (destination.is_value()) { __ add(Operand(esp), Immediate(kPointerSize)); } // Save or discard the right-hand value as needed. - if (right->AsLiteral() != NULL) { - Move(destination, right->AsLiteral()); - } else { - Visit(right); - Move(destination, right->location()); - } + Visit(right); + ASSERT_EQ(destination.type(), right->location().type()); __ bind(&done); } diff --git a/deps/v8/src/ia32/frames-ia32.cc b/deps/v8/src/ia32/frames-ia32.cc index 5c900bedd7..dea439f24b 100644 --- a/deps/v8/src/ia32/frames-ia32.cc +++ b/deps/v8/src/ia32/frames-ia32.cc @@ -56,14 +56,19 @@ StackFrame::Type ExitFrame::GetStateForFramePointer(Address fp, State* state) { state->fp = fp; state->sp = sp; state->pc_address = reinterpret_cast<Address*>(sp - 1 * kPointerSize); - return EXIT; + // Determine frame type. + if (Memory::Address_at(fp + ExitFrameConstants::kDebugMarkOffset) != 0) { + return EXIT_DEBUG; + } else { + return EXIT; + } } void ExitFrame::Iterate(ObjectVisitor* v) const { - v->VisitPointer(&code_slot()); - // The arguments are traversed as part of the expression stack of - // the calling frame. + // Exit frames on IA-32 do not contain any pointers. The arguments + // are traversed as part of the expression stack of the calling + // frame. } diff --git a/deps/v8/src/ia32/frames-ia32.h b/deps/v8/src/ia32/frames-ia32.h index c3fe6c748d..3a7c86bf73 100644 --- a/deps/v8/src/ia32/frames-ia32.h +++ b/deps/v8/src/ia32/frames-ia32.h @@ -76,7 +76,7 @@ class EntryFrameConstants : public AllStatic { class ExitFrameConstants : public AllStatic { public: - static const int kCodeOffset = -2 * kPointerSize; + static const int kDebugMarkOffset = -2 * kPointerSize; static const int kSPOffset = -1 * kPointerSize; static const int kCallerFPOffset = 0 * kPointerSize; diff --git a/deps/v8/src/ia32/macro-assembler-ia32.cc b/deps/v8/src/ia32/macro-assembler-ia32.cc index 34d4fd5f6d..08c4c0c51b 100644 --- a/deps/v8/src/ia32/macro-assembler-ia32.cc +++ b/deps/v8/src/ia32/macro-assembler-ia32.cc @@ -355,7 +355,10 @@ void MacroAssembler::LeaveFrame(StackFrame::Type type) { leave(); } -void MacroAssembler::EnterExitFramePrologue(ExitFrame::Mode mode) { + +void MacroAssembler::EnterExitFrame(StackFrame::Type type) { + ASSERT(type == StackFrame::EXIT || type == StackFrame::EXIT_DEBUG); + // Setup the frame structure on the stack. ASSERT(ExitFrameConstants::kCallerSPDisplacement == +2 * kPointerSize); ASSERT(ExitFrameConstants::kCallerPCOffset == +1 * kPointerSize); @@ -366,24 +369,23 @@ void MacroAssembler::EnterExitFramePrologue(ExitFrame::Mode mode) { // Reserve room for entry stack pointer and push the debug marker. ASSERT(ExitFrameConstants::kSPOffset == -1 * kPointerSize); push(Immediate(0)); // saved entry sp, patched before call - if (mode == ExitFrame::MODE_DEBUG) { - push(Immediate(0)); - } else { - push(Immediate(CodeObject())); - } + push(Immediate(type == StackFrame::EXIT_DEBUG ? 1 : 0)); // Save the frame pointer and the context in top. ExternalReference c_entry_fp_address(Top::k_c_entry_fp_address); ExternalReference context_address(Top::k_context_address); mov(Operand::StaticVariable(c_entry_fp_address), ebp); mov(Operand::StaticVariable(context_address), esi); -} -void MacroAssembler::EnterExitFrameEpilogue(ExitFrame::Mode mode, int argc) { + // Setup argc and argv in callee-saved registers. + int offset = StandardFrameConstants::kCallerSPOffset - kPointerSize; + mov(edi, Operand(eax)); + lea(esi, Operand(ebp, eax, times_4, offset)); + #ifdef ENABLE_DEBUGGER_SUPPORT // Save the state of all registers to the stack from the memory // location. This is needed to allow nested break points. - if (mode == ExitFrame::MODE_DEBUG) { + if (type == StackFrame::EXIT_DEBUG) { // TODO(1243899): This should be symmetric to // CopyRegistersFromStackToMemory() but it isn't! esp is assumed // correct here, but computed for the other call. Very error @@ -394,8 +396,8 @@ void MacroAssembler::EnterExitFrameEpilogue(ExitFrame::Mode mode, int argc) { } #endif - // Reserve space for arguments. - sub(Operand(esp), Immediate(argc * kPointerSize)); + // Reserve space for two arguments: argc and argv. + sub(Operand(esp), Immediate(2 * kPointerSize)); // Get the required frame alignment for the OS. static const int kFrameAlignment = OS::ActivationFrameAlignment(); @@ -409,39 +411,15 @@ void MacroAssembler::EnterExitFrameEpilogue(ExitFrame::Mode mode, int argc) { } -void MacroAssembler::EnterExitFrame(ExitFrame::Mode mode) { - EnterExitFramePrologue(mode); - - // Setup argc and argv in callee-saved registers. - int offset = StandardFrameConstants::kCallerSPOffset - kPointerSize; - mov(edi, Operand(eax)); - lea(esi, Operand(ebp, eax, times_4, offset)); - - EnterExitFrameEpilogue(mode, 2); -} - - -void MacroAssembler::EnterApiExitFrame(ExitFrame::Mode mode, - int stack_space, - int argc) { - EnterExitFramePrologue(mode); - - int offset = StandardFrameConstants::kCallerSPOffset - kPointerSize; - lea(esi, Operand(ebp, (stack_space * kPointerSize) + offset)); - - EnterExitFrameEpilogue(mode, argc); -} - - -void MacroAssembler::LeaveExitFrame(ExitFrame::Mode mode) { +void MacroAssembler::LeaveExitFrame(StackFrame::Type type) { #ifdef ENABLE_DEBUGGER_SUPPORT // Restore the memory copy of the registers by digging them out from // the stack. This is needed to allow nested break points. - if (mode == ExitFrame::MODE_DEBUG) { + if (type == StackFrame::EXIT_DEBUG) { // It's okay to clobber register ebx below because we don't need // the function pointer after this. const int kCallerSavedSize = kNumJSCallerSaved * kPointerSize; - int kOffset = ExitFrameConstants::kCodeOffset - kCallerSavedSize; + int kOffset = ExitFrameConstants::kDebugMarkOffset - kCallerSavedSize; lea(ebx, Operand(ebp, kOffset)); CopyRegistersFromStackToMemory(ebx, ecx, kJSCallerSaved); } @@ -953,48 +931,6 @@ void MacroAssembler::TailCallRuntime(const ExternalReference& ext, } -void MacroAssembler::PushHandleScope(Register scratch) { - // Push the number of extensions, smi-tagged so the gc will ignore it. - ExternalReference extensions_address = - ExternalReference::handle_scope_extensions_address(); - mov(scratch, Operand::StaticVariable(extensions_address)); - ASSERT_EQ(0, kSmiTag); - shl(scratch, kSmiTagSize); - push(scratch); - mov(Operand::StaticVariable(extensions_address), Immediate(0)); - // Push next and limit pointers which will be wordsize aligned and - // hence automatically smi tagged. - ExternalReference next_address = - ExternalReference::handle_scope_next_address(); - push(Operand::StaticVariable(next_address)); - ExternalReference limit_address = - ExternalReference::handle_scope_limit_address(); - push(Operand::StaticVariable(limit_address)); -} - - -void MacroAssembler::PopHandleScope(Register scratch) { - ExternalReference extensions_address = - ExternalReference::handle_scope_extensions_address(); - Label write_back; - mov(scratch, Operand::StaticVariable(extensions_address)); - cmp(Operand(scratch), Immediate(0)); - j(equal, &write_back); - CallRuntime(Runtime::kDeleteHandleScopeExtensions, 0); - - bind(&write_back); - ExternalReference limit_address = - ExternalReference::handle_scope_limit_address(); - pop(Operand::StaticVariable(limit_address)); - ExternalReference next_address = - ExternalReference::handle_scope_next_address(); - pop(Operand::StaticVariable(next_address)); - pop(scratch); - shr(scratch, kSmiTagSize); - mov(Operand::StaticVariable(extensions_address), scratch); -} - - void MacroAssembler::JumpToRuntime(const ExternalReference& ext) { // Set the entry point and jump to the C entry runtime stub. mov(ebx, Immediate(ext)); diff --git a/deps/v8/src/ia32/macro-assembler-ia32.h b/deps/v8/src/ia32/macro-assembler-ia32.h index 18d221c407..a0a242806b 100644 --- a/deps/v8/src/ia32/macro-assembler-ia32.h +++ b/deps/v8/src/ia32/macro-assembler-ia32.h @@ -77,18 +77,16 @@ class MacroAssembler: public Assembler { void EnterConstructFrame() { EnterFrame(StackFrame::CONSTRUCT); } void LeaveConstructFrame() { LeaveFrame(StackFrame::CONSTRUCT); } - // Enter specific kind of exit frame; either in normal or debug mode. - // Expects the number of arguments in register eax and + // Enter specific kind of exit frame; either EXIT or + // EXIT_DEBUG. Expects the number of arguments in register eax and // sets up the number of arguments in register edi and the pointer // to the first argument in register esi. - void EnterExitFrame(ExitFrame::Mode mode); - - void EnterApiExitFrame(ExitFrame::Mode mode, int stack_space, int argc); + void EnterExitFrame(StackFrame::Type type); // Leave the current exit frame. Expects the return value in // register eax:edx (untouched) and the pointer to the first // argument in register esi. - void LeaveExitFrame(ExitFrame::Mode mode); + void LeaveExitFrame(StackFrame::Type type); // --------------------------------------------------------------------------- @@ -271,9 +269,6 @@ class MacroAssembler: public Assembler { int num_arguments, int result_size); - void PushHandleScope(Register scratch); - void PopHandleScope(Register scratch); - // Jump to a runtime routine. void JumpToRuntime(const ExternalReference& ext); @@ -351,9 +346,6 @@ class MacroAssembler: public Assembler { void EnterFrame(StackFrame::Type type); void LeaveFrame(StackFrame::Type type); - void EnterExitFramePrologue(ExitFrame::Mode mode); - void EnterExitFrameEpilogue(ExitFrame::Mode mode, int argc); - // Allocation support helpers. void LoadAllocationTopHelper(Register result, Register result_end, diff --git a/deps/v8/src/ia32/stub-cache-ia32.cc b/deps/v8/src/ia32/stub-cache-ia32.cc index 3e5fc04794..ca4e142101 100644 --- a/deps/v8/src/ia32/stub-cache-ia32.cc +++ b/deps/v8/src/ia32/stub-cache-ia32.cc @@ -776,39 +776,20 @@ void StubCompiler::GenerateLoadCallback(JSObject* object, CheckPrototypes(object, receiver, holder, scratch1, scratch2, name, miss); - Handle<AccessorInfo> callback_handle(callback); - - Register other = reg.is(scratch1) ? scratch2 : scratch1; - __ EnterInternalFrame(); - __ PushHandleScope(other); - // Push the stack address where the list of arguments ends - __ mov(other, esp); - __ sub(Operand(other), Immediate(2 * kPointerSize)); - __ push(other); + // Push the arguments on the JS stack of the caller. + __ pop(scratch2); // remove return address __ push(receiver); // receiver __ push(reg); // holder - __ mov(other, Immediate(callback_handle)); - __ push(other); - __ push(FieldOperand(other, AccessorInfo::kDataOffset)); // data + __ mov(reg, Immediate(Handle<AccessorInfo>(callback))); // callback data + __ push(reg); + __ push(FieldOperand(reg, AccessorInfo::kDataOffset)); __ push(name_reg); // name - // Save a pointer to where we pushed the arguments pointer. - // This will be passed as the const Arguments& to the C++ callback. - __ mov(eax, esp); - __ add(Operand(eax), Immediate(5 * kPointerSize)); - __ mov(ebx, esp); - - // Do call through the api. - ASSERT_EQ(6, ApiGetterEntryStub::kStackSpace); - Address getter_address = v8::ToCData<Address>(callback->getter()); - ApiFunction fun(getter_address); - ApiGetterEntryStub stub(callback_handle, &fun); - __ CallStub(&stub); + __ push(scratch2); // restore return address - Register tmp = other.is(eax) ? reg : other; - __ PopHandleScope(tmp); - __ LeaveInternalFrame(); - - __ ret(0); + // Do tail-call to the runtime system. + ExternalReference load_callback_property = + ExternalReference(IC_Utility(IC::kLoadCallbackProperty)); + __ TailCallRuntime(load_callback_property, 5, 1); } diff --git a/deps/v8/src/location.h b/deps/v8/src/location.h index c4a77cb5d1..26b1a09e9c 100644 --- a/deps/v8/src/location.h +++ b/deps/v8/src/location.h @@ -35,13 +35,18 @@ namespace internal { class Location BASE_EMBEDDED { public: - enum Type { NOWHERE, TEMP }; - - static Location Temporary() { return Location(TEMP); } - static Location Nowhere() { return Location(NOWHERE); } - - bool is_temporary() { return type_ == TEMP; } - bool is_nowhere() { return type_ == NOWHERE; } + enum Type { + kUninitialized, + kEffect, + kValue + }; + + static Location Uninitialized() { return Location(kUninitialized); } + static Location Effect() { return Location(kEffect); } + static Location Value() { return Location(kValue); } + + bool is_effect() { return type_ == kEffect; } + bool is_value() { return type_ == kValue; } Type type() { return type_; } diff --git a/deps/v8/src/objects-debug.cc b/deps/v8/src/objects-debug.cc index 10ad2941a3..01881346e1 100644 --- a/deps/v8/src/objects-debug.cc +++ b/deps/v8/src/objects-debug.cc @@ -979,7 +979,6 @@ void AccessorInfo::AccessorInfoVerify() { VerifyPointer(name()); VerifyPointer(data()); VerifyPointer(flag()); - VerifyPointer(load_stub_cache()); } void AccessorInfo::AccessorInfoPrint() { diff --git a/deps/v8/src/objects-inl.h b/deps/v8/src/objects-inl.h index 5907a86f69..2350a35ba8 100644 --- a/deps/v8/src/objects-inl.h +++ b/deps/v8/src/objects-inl.h @@ -2436,7 +2436,6 @@ ACCESSORS(AccessorInfo, setter, Object, kSetterOffset) ACCESSORS(AccessorInfo, data, Object, kDataOffset) ACCESSORS(AccessorInfo, name, Object, kNameOffset) ACCESSORS(AccessorInfo, flag, Smi, kFlagOffset) -ACCESSORS(AccessorInfo, load_stub_cache, Object, kLoadStubCacheOffset) ACCESSORS(AccessCheckInfo, named_callback, Object, kNamedCallbackOffset) ACCESSORS(AccessCheckInfo, indexed_callback, Object, kIndexedCallbackOffset) diff --git a/deps/v8/src/objects.h b/deps/v8/src/objects.h index 61bdf44af1..89cbd44637 100644 --- a/deps/v8/src/objects.h +++ b/deps/v8/src/objects.h @@ -4719,7 +4719,6 @@ class AccessorInfo: public Struct { DECL_ACCESSORS(data, Object) DECL_ACCESSORS(name, Object) DECL_ACCESSORS(flag, Smi) - DECL_ACCESSORS(load_stub_cache, Object) inline bool all_can_read(); inline void set_all_can_read(bool value); @@ -4745,8 +4744,7 @@ class AccessorInfo: public Struct { static const int kDataOffset = kSetterOffset + kPointerSize; static const int kNameOffset = kDataOffset + kPointerSize; static const int kFlagOffset = kNameOffset + kPointerSize; - static const int kLoadStubCacheOffset = kFlagOffset + kPointerSize; - static const int kSize = kLoadStubCacheOffset + kPointerSize; + static const int kSize = kFlagOffset + kPointerSize; private: // Bit positions in flag. diff --git a/deps/v8/src/runtime.cc b/deps/v8/src/runtime.cc index 76520e3aad..8fd62c986c 100644 --- a/deps/v8/src/runtime.cc +++ b/deps/v8/src/runtime.cc @@ -1357,9 +1357,8 @@ class ReplacementStringBuilder { StringBuilderSubstringPosition::encode(from); AddElement(Smi::FromInt(encoded_slice)); } else { - // Otherwise encode as two smis. - AddElement(Smi::FromInt(-length)); - AddElement(Smi::FromInt(from)); + Handle<String> slice = Factory::NewStringSlice(subject_, from, to); + AddElement(*slice); } IncrementCharacterCount(length); } @@ -3767,21 +3766,9 @@ static inline void StringBuilderConcatHelper(String* special, for (int i = 0; i < array_length; i++) { Object* element = fixed_array->get(i); if (element->IsSmi()) { - // Smi encoding of position and length. int encoded_slice = Smi::cast(element)->value(); - int pos; - int len; - if (encoded_slice > 0) { - // Position and length encoded in one smi. - pos = StringBuilderSubstringPosition::decode(encoded_slice); - len = StringBuilderSubstringLength::decode(encoded_slice); - } else { - // Position and length encoded in two smis. - Object* obj = fixed_array->get(++i); - ASSERT(obj->IsSmi()); - pos = Smi::cast(obj)->value(); - len = -encoded_slice; - } + int pos = StringBuilderSubstringPosition::decode(encoded_slice); + int len = StringBuilderSubstringLength::decode(encoded_slice); String::WriteToFlat(special, sink + position, pos, @@ -3802,10 +3789,6 @@ static Object* Runtime_StringBuilderConcat(Arguments args) { ASSERT(args.length() == 2); CONVERT_CHECKED(JSArray, array, args[0]); CONVERT_CHECKED(String, special, args[1]); - - // This assumption is used by the slice encoding in one or two smis. - ASSERT(Smi::kMaxValue >= String::kMaxLength); - int special_length = special->length(); Object* smi_array_length = array->length(); if (!smi_array_length->IsSmi()) { @@ -3833,29 +3816,13 @@ static Object* Runtime_StringBuilderConcat(Arguments args) { for (int i = 0; i < array_length; i++) { Object* elt = fixed_array->get(i); if (elt->IsSmi()) { - // Smi encoding of position and length. int len = Smi::cast(elt)->value(); - if (len > 0) { - // Position and length encoded in one smi. - int pos = len >> 11; - len &= 0x7ff; - if (pos + len > special_length) { - return Top::Throw(Heap::illegal_argument_symbol()); - } - position += len; - } else { - // Position and length encoded in two smis. - position += (-len); - // Get the position and check that it is also a smi. - i++; - if (i >= array_length) { - return Top::Throw(Heap::illegal_argument_symbol()); - } - Object* pos = fixed_array->get(i); - if (!pos->IsSmi()) { - return Top::Throw(Heap::illegal_argument_symbol()); - } + int pos = len >> 11; + len &= 0x7ff; + if (pos + len > special_length) { + return Top::Throw(Heap::illegal_argument_symbol()); } + position += len; } else if (elt->IsString()) { String* element = String::cast(elt); int element_length = element->length(); @@ -4830,12 +4797,6 @@ static Object* Runtime_ReThrow(Arguments args) { } -static Object* Runtime_PromoteScheduledException(Arguments args) { - ASSERT_EQ(0, args.length()); - return Top::PromoteScheduledException(); -} - - static Object* Runtime_ThrowReferenceError(Arguments args) { HandleScope scope; ASSERT(args.length() == 1); @@ -7797,13 +7758,6 @@ static Object* Runtime_Abort(Arguments args) { } -static Object* Runtime_DeleteHandleScopeExtensions(Arguments args) { - ASSERT(args.length() == 0); - HandleScope::DeleteExtensions(); - return Heap::undefined_value(); -} - - #ifdef DEBUG // ListNatives is ONLY used by the fuzz-natives.js in debug mode // Exclude the code in release mode. diff --git a/deps/v8/src/runtime.h b/deps/v8/src/runtime.h index a55ef25011..6b1ce480b5 100644 --- a/deps/v8/src/runtime.h +++ b/deps/v8/src/runtime.h @@ -234,7 +234,6 @@ namespace internal { F(ReThrow, 1, 1) \ F(ThrowReferenceError, 1, 1) \ F(StackGuard, 1, 1) \ - F(PromoteScheduledException, 0, 1) \ \ /* Contexts */ \ F(NewContext, 1, 1) \ @@ -264,8 +263,6 @@ namespace internal { F(Log, 2, 1) \ /* ES5 */ \ F(LocalKeys, 1, 1) \ - /* Handle scopes */ \ - F(DeleteHandleScopeExtensions, 0, 1) \ \ /* Pseudo functions - handled as macros by parser */ \ F(IS_VAR, 1, 1) diff --git a/deps/v8/src/string.js b/deps/v8/src/string.js index bb2ad4f2a0..d2d6e969df 100644 --- a/deps/v8/src/string.js +++ b/deps/v8/src/string.js @@ -1,4 +1,4 @@ -// Copyright 2006-2009 the V8 project authors. All rights reserved. +// Copyright 2006-2008 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: @@ -810,13 +810,10 @@ ReplaceResultBuilder.prototype.addSpecialSlice = function(start, end) { var len = end - start; if (len == 0) return; var elements = this.elements; - if (start < 0x80000 && len < 0x800) { + if (start >= 0 && len >= 0 && start < 0x80000 && len < 0x800) { elements[elements.length] = (start << 11) + len; } else { - // 0 < len <= String::kMaxLength and Smi::kMaxValue >= String::kMaxLength, - // so -len is a smi. - elements[elements.length] = -len; - elements[elements.length] = start; + elements[elements.length] = SubString(this.special_string, start, end); } } diff --git a/deps/v8/src/stub-cache.cc b/deps/v8/src/stub-cache.cc index a399e4563e..e10dc61b2c 100644 --- a/deps/v8/src/stub-cache.cc +++ b/deps/v8/src/stub-cache.cc @@ -735,16 +735,11 @@ Handle<Code> ComputeCallMiss(int argc) { Object* LoadCallbackProperty(Arguments args) { - ASSERT(args[0]->IsJSObject()); - ASSERT(args[1]->IsJSObject()); AccessorInfo* callback = AccessorInfo::cast(args[2]); Address getter_address = v8::ToCData<Address>(callback->getter()); v8::AccessorGetter fun = FUNCTION_CAST<v8::AccessorGetter>(getter_address); ASSERT(fun != NULL); - CustomArguments custom_args(callback->data(), - JSObject::cast(args[0]), - JSObject::cast(args[1])); - v8::AccessorInfo info(custom_args.end()); + v8::AccessorInfo info(args.arguments()); HandleScope scope; v8::Handle<v8::Value> result; { diff --git a/deps/v8/src/top.h b/deps/v8/src/top.h index 0f5aa27b2b..ae94f08e3c 100644 --- a/deps/v8/src/top.h +++ b/deps/v8/src/top.h @@ -170,10 +170,6 @@ class Top { return &thread_local_.external_caught_exception_; } - static Object** scheduled_exception_address() { - return &thread_local_.scheduled_exception_; - } - static Object* scheduled_exception() { ASSERT(has_scheduled_exception()); return thread_local_.scheduled_exception_; diff --git a/deps/v8/src/version.cc b/deps/v8/src/version.cc index 7b8986cf28..944cd4e1c2 100644 --- a/deps/v8/src/version.cc +++ b/deps/v8/src/version.cc @@ -34,7 +34,7 @@ // cannot be changed without changing the SCons build script. #define MAJOR_VERSION 1 #define MINOR_VERSION 3 -#define BUILD_NUMBER 17 +#define BUILD_NUMBER 18 #define PATCH_LEVEL 0 #define CANDIDATE_VERSION false diff --git a/deps/v8/src/x64/codegen-x64.cc b/deps/v8/src/x64/codegen-x64.cc index 877cfdfb45..95f30d842d 100644 --- a/deps/v8/src/x64/codegen-x64.cc +++ b/deps/v8/src/x64/codegen-x64.cc @@ -6771,7 +6771,7 @@ void CEntryStub::GenerateCore(MacroAssembler* masm, Label* throw_normal_exception, Label* throw_termination_exception, Label* throw_out_of_memory_exception, - ExitFrame::Mode mode, + StackFrame::Type frame_type, bool do_gc, bool always_allocate_scope) { // rax: result parameter for PerformGC, if any. @@ -6854,7 +6854,7 @@ void CEntryStub::GenerateCore(MacroAssembler* masm, __ j(zero, &failure_returned); // Exit the JavaScript to C++ exit frame. - __ LeaveExitFrame(mode, result_size_); + __ LeaveExitFrame(frame_type, result_size_); __ ret(0); // Handling of failure. @@ -6984,12 +6984,12 @@ void CEntryStub::GenerateBody(MacroAssembler* masm, bool is_debug_break) { // this by performing a garbage collection and retrying the // builtin once. - ExitFrame::Mode mode = is_debug_break ? - ExitFrame::MODE_DEBUG : - ExitFrame::MODE_NORMAL; + StackFrame::Type frame_type = is_debug_break ? + StackFrame::EXIT_DEBUG : + StackFrame::EXIT; // Enter the exit frame that transitions from JavaScript to C++. - __ EnterExitFrame(mode, result_size_); + __ EnterExitFrame(frame_type, result_size_); // rax: Holds the context at this point, but should not be used. // On entry to code generated by GenerateCore, it must hold @@ -7012,7 +7012,7 @@ void CEntryStub::GenerateBody(MacroAssembler* masm, bool is_debug_break) { &throw_normal_exception, &throw_termination_exception, &throw_out_of_memory_exception, - mode, + frame_type, false, false); @@ -7021,7 +7021,7 @@ void CEntryStub::GenerateBody(MacroAssembler* masm, bool is_debug_break) { &throw_normal_exception, &throw_termination_exception, &throw_out_of_memory_exception, - mode, + frame_type, true, false); @@ -7032,7 +7032,7 @@ void CEntryStub::GenerateBody(MacroAssembler* masm, bool is_debug_break) { &throw_normal_exception, &throw_termination_exception, &throw_out_of_memory_exception, - mode, + frame_type, true, true); @@ -7047,11 +7047,6 @@ void CEntryStub::GenerateBody(MacroAssembler* masm, bool is_debug_break) { } -void ApiGetterEntryStub::Generate(MacroAssembler* masm) { - UNREACHABLE(); -} - - void JSEntryStub::GenerateBody(MacroAssembler* masm, bool is_construct) { Label invoke, exit; #ifdef ENABLE_LOGGING_AND_PROFILING diff --git a/deps/v8/src/x64/fast-codegen-x64.cc b/deps/v8/src/x64/fast-codegen-x64.cc index 53ee35758d..b938119cd3 100644 --- a/deps/v8/src/x64/fast-codegen-x64.cc +++ b/deps/v8/src/x64/fast-codegen-x64.cc @@ -118,9 +118,11 @@ void FastCodeGenerator::Generate(FunctionLiteral* fun) { void FastCodeGenerator::Move(Location destination, Slot* source) { switch (destination.type()) { - case Location::NOWHERE: + case Location::kUninitialized: + UNREACHABLE(); + case Location::kEffect: break; - case Location::TEMP: + case Location::kValue: __ push(Operand(rbp, SlotOffset(source))); break; } @@ -129,9 +131,11 @@ void FastCodeGenerator::Move(Location destination, Slot* source) { void FastCodeGenerator::Move(Location destination, Literal* expr) { switch (destination.type()) { - case Location::NOWHERE: + case Location::kUninitialized: + UNREACHABLE(); + case Location::kEffect: break; - case Location::TEMP: + case Location::kValue: __ Push(expr->handle()); break; } @@ -140,9 +144,10 @@ void FastCodeGenerator::Move(Location destination, Literal* expr) { void FastCodeGenerator::Move(Slot* destination, Location source) { switch (source.type()) { - case Location::NOWHERE: + case Location::kUninitialized: // Fall through. + case Location::kEffect: UNREACHABLE(); - case Location::TEMP: + case Location::kValue: __ pop(Operand(rbp, SlotOffset(destination))); break; } @@ -151,10 +156,12 @@ void FastCodeGenerator::Move(Slot* destination, Location source) { void FastCodeGenerator::DropAndMove(Location destination, Register source) { switch (destination.type()) { - case Location::NOWHERE: + case Location::kUninitialized: + UNREACHABLE(); + case Location::kEffect: __ addq(rsp, Immediate(kPointerSize)); break; - case Location::TEMP: + case Location::kValue: __ movq(Operand(rsp, 0), source); break; } @@ -246,6 +253,33 @@ void FastCodeGenerator::VisitVariableProxy(VariableProxy* expr) { } +void FastCodeGenerator::VisitRegExpLiteral(RegExpLiteral* expr) { + Comment cmnt(masm_, "[ RegExp Literal"); + Label done; + // Registers will be used as follows: + // rdi = JS function. + // rbx = literals array. + // rax = regexp literal. + __ movq(rdi, Operand(rbp, JavaScriptFrameConstants::kFunctionOffset)); + __ movq(rbx, FieldOperand(rdi, JSFunction::kLiteralsOffset)); + int literal_offset = + FixedArray::kHeaderSize + expr->literal_index() * kPointerSize; + __ movq(rax, FieldOperand(rbx, literal_offset)); + __ CompareRoot(rax, Heap::kUndefinedValueRootIndex); + __ j(not_equal, &done); + // Create regexp literal using runtime function + // Result will be in rax. + __ push(rbx); + __ Push(Smi::FromInt(expr->literal_index())); + __ Push(expr->pattern()); + __ Push(expr->flags()); + __ CallRuntime(Runtime::kMaterializeRegExpLiteral, 4); + // Label done: + __ bind(&done); + Move(expr->location(), rax); +} + + void FastCodeGenerator::VisitObjectLiteral(ObjectLiteral* expr) { Comment cmnt(masm_, "[ ObjectLiteral"); Label boilerplate_exists; @@ -295,7 +329,7 @@ void FastCodeGenerator::VisitObjectLiteral(ObjectLiteral* expr) { case ObjectLiteral::Property::COMPUTED: if (key->handle()->IsSymbol()) { Visit(value); - ASSERT(value->location().is_temporary()); + ASSERT(value->location().is_value()); __ pop(rax); __ Move(rcx, key->handle()); Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Initialize)); @@ -307,9 +341,9 @@ void FastCodeGenerator::VisitObjectLiteral(ObjectLiteral* expr) { case ObjectLiteral::Property::PROTOTYPE: __ push(rax); Visit(key); - ASSERT(key->location().is_temporary()); + ASSERT(key->location().is_value()); Visit(value); - ASSERT(value->location().is_temporary()); + ASSERT(value->location().is_value()); __ CallRuntime(Runtime::kSetProperty, 3); __ movq(rax, Operand(rsp, 0)); // Restore result into rax. break; @@ -317,12 +351,12 @@ void FastCodeGenerator::VisitObjectLiteral(ObjectLiteral* expr) { case ObjectLiteral::Property::GETTER: __ push(rax); Visit(key); - ASSERT(key->location().is_temporary()); + ASSERT(key->location().is_value()); __ Push(property->kind() == ObjectLiteral::Property::SETTER ? Smi::FromInt(1) : Smi::FromInt(0)); Visit(value); - ASSERT(value->location().is_temporary()); + ASSERT(value->location().is_value()); __ CallRuntime(Runtime::kDefineAccessor, 4); __ movq(rax, Operand(rsp, 0)); // Restore result into rax. break; @@ -330,43 +364,18 @@ void FastCodeGenerator::VisitObjectLiteral(ObjectLiteral* expr) { } } switch (expr->location().type()) { - case Location::NOWHERE: + case Location::kUninitialized: + UNREACHABLE(); + case Location::kEffect: if (result_saved) __ addq(rsp, Immediate(kPointerSize)); break; - case Location::TEMP: + case Location::kValue: if (!result_saved) __ push(rax); break; } } -void FastCodeGenerator::VisitRegExpLiteral(RegExpLiteral* expr) { - Comment cmnt(masm_, "[ RegExp Literal"); - Label done; - // Registers will be used as follows: - // rdi = JS function. - // rbx = literals array. - // rax = regexp literal. - __ movq(rdi, Operand(rbp, JavaScriptFrameConstants::kFunctionOffset)); - __ movq(rbx, FieldOperand(rdi, JSFunction::kLiteralsOffset)); - int literal_offset = - FixedArray::kHeaderSize + expr->literal_index() * kPointerSize; - __ movq(rax, FieldOperand(rbx, literal_offset)); - __ CompareRoot(rax, Heap::kUndefinedValueRootIndex); - __ j(not_equal, &done); - // Create regexp literal using runtime function - // Result will be in rax. - __ push(rbx); - __ Push(Smi::FromInt(expr->literal_index())); - __ Push(expr->pattern()); - __ Push(expr->flags()); - __ CallRuntime(Runtime::kMaterializeRegExpLiteral, 4); - // Label done: - __ bind(&done); - Move(expr->location(), rax); -} - - void FastCodeGenerator::VisitArrayLiteral(ArrayLiteral* expr) { Comment cmnt(masm_, "[ ArrayLiteral"); Label make_clone; @@ -415,7 +424,7 @@ void FastCodeGenerator::VisitArrayLiteral(ArrayLiteral* expr) { result_saved = true; } Visit(subexpr); - ASSERT(subexpr->location().is_temporary()); + ASSERT(subexpr->location().is_value()); // Store the subexpression value in the array's elements. __ pop(rax); // Subexpression value. @@ -429,10 +438,12 @@ void FastCodeGenerator::VisitArrayLiteral(ArrayLiteral* expr) { } switch (expr->location().type()) { - case Location::NOWHERE: + case Location::kUninitialized: + UNREACHABLE(); + case Location::kEffect: if (result_saved) __ addq(rsp, Immediate(kPointerSize)); break; - case Location::TEMP: + case Location::kValue: if (!result_saved) __ push(rax); break; } @@ -459,7 +470,7 @@ void FastCodeGenerator::VisitAssignment(Assignment* expr) { if (rhs->AsLiteral() != NULL) { __ Move(rax, rhs->AsLiteral()->handle()); } else { - ASSERT(rhs->location().is_temporary()); + ASSERT(rhs->location().is_value()); Visit(rhs); __ pop(rax); } @@ -480,14 +491,16 @@ void FastCodeGenerator::VisitAssignment(Assignment* expr) { __ movq(Operand(rbp, SlotOffset(var->slot())), kScratchRegister); Move(expr->location(), kScratchRegister); } else { - ASSERT(rhs->location().is_temporary()); + ASSERT(rhs->location().is_value()); Visit(rhs); switch (expr->location().type()) { - case Location::NOWHERE: + case Location::kUninitialized: + UNREACHABLE(); + case Location::kEffect: // Case 'var = temp'. Discard right-hand-side temporary. Move(var->slot(), rhs->location()); break; - case Location::TEMP: + case Location::kValue: // Case 'temp1 <- (var = temp0)'. Preserve right-hand-side // temporary on the stack. __ movq(kScratchRegister, Operand(rsp, 0)); @@ -532,10 +545,12 @@ void FastCodeGenerator::VisitProperty(Property* expr) { __ addq(rsp, Immediate(kPointerSize)); } switch (expr->location().type()) { - case Location::TEMP: + case Location::kUninitialized: + UNREACHABLE(); + case Location::kValue: __ movq(Operand(rsp, 0), rax); break; - case Location::NOWHERE: + case Location::kEffect: __ addq(rsp, Immediate(kPointerSize)); break; } @@ -555,7 +570,7 @@ void FastCodeGenerator::VisitCall(Call* expr) { int arg_count = args->length(); for (int i = 0; i < arg_count; i++) { Visit(args->at(i)); - ASSERT(args->at(i)->location().is_temporary()); + ASSERT(args->at(i)->location().is_value()); } // Record source position for debugger SetSourcePosition(expr->position()); @@ -577,8 +592,8 @@ void FastCodeGenerator::VisitCallNew(CallNew* node) { // arguments. // Push function on the stack. Visit(node->expression()); - ASSERT(node->expression()->location().is_temporary()); - // If location is temporary, already on the stack, + ASSERT(node->expression()->location().is_value()); + // If location is value, already on the stack, // Push global object (receiver). __ push(CodeGenerator::GlobalObject()); @@ -588,8 +603,8 @@ void FastCodeGenerator::VisitCallNew(CallNew* node) { int arg_count = args->length(); for (int i = 0; i < arg_count; i++) { Visit(args->at(i)); - ASSERT(args->at(i)->location().is_temporary()); - // If location is temporary, it is already on the stack, + ASSERT(args->at(i)->location().is_value()); + // If location is value, it is already on the stack, // so nothing to do here. } @@ -621,7 +636,7 @@ void FastCodeGenerator::VisitCallRuntime(CallRuntime* expr) { int arg_count = args->length(); for (int i = 0; i < arg_count; i++) { Visit(args->at(i)); - ASSERT(args->at(i)->location().is_temporary()); + ASSERT(args->at(i)->location().is_value()); } __ CallRuntime(function, arg_count); @@ -630,13 +645,66 @@ void FastCodeGenerator::VisitCallRuntime(CallRuntime* expr) { void FastCodeGenerator::VisitBinaryOperation(BinaryOperation* expr) { - // Compile a short-circuited boolean or operation in a non-test - // context. - ASSERT(expr->op() == Token::OR); + switch (expr->op()) { + case Token::COMMA: + ASSERT(expr->left()->location().is_effect()); + ASSERT_EQ(expr->right()->location().type(), expr->location().type()); + Visit(expr->left()); + Visit(expr->right()); + break; + + case Token::OR: + case Token::AND: + EmitLogicalOperation(expr); + break; + + case Token::ADD: + case Token::SUB: + case Token::DIV: + case Token::MOD: + case Token::MUL: + case Token::BIT_OR: + case Token::BIT_AND: + case Token::BIT_XOR: + case Token::SHL: + case Token::SHR: + case Token::SAR: { + ASSERT(expr->left()->location().is_value()); + ASSERT(expr->right()->location().is_value()); + + Visit(expr->left()); + Visit(expr->right()); + GenericBinaryOpStub stub(expr->op(), + NO_OVERWRITE, + NO_GENERIC_BINARY_FLAGS); + __ CallStub(&stub); + Move(expr->location(), rax); + + break; + } + default: + UNREACHABLE(); + } +} + + +void FastCodeGenerator::EmitLogicalOperation(BinaryOperation* expr) { + // Compile a short-circuited boolean operation in a non-test context. + // Compile (e0 || e1) as if it were // (let (temp = e0) temp ? temp : e1). + // Compile (e0 && e1) as if it were + // (let (temp = e0) !temp ? temp : e1). Label eval_right, done; + Label *left_true, *left_false; // Where to branch to if lhs has that value. + if (expr->op() == Token::OR) { + left_true = &done; + left_false = &eval_right; + } else { + left_true = &eval_right; + left_false = &done; + } Location destination = expr->location(); Expression* left = expr->left(); Expression* right = expr->right(); @@ -649,17 +717,19 @@ void FastCodeGenerator::VisitBinaryOperation(BinaryOperation* expr) { // need it as the value of the whole expression. if (left->AsLiteral() != NULL) { __ Move(rax, left->AsLiteral()->handle()); - if (destination.is_temporary()) __ push(rax); + if (destination.is_value()) __ push(rax); } else { Visit(left); - ASSERT(left->location().is_temporary()); + ASSERT(left->location().is_value()); switch (destination.type()) { - case Location::NOWHERE: + case Location::kUninitialized: + UNREACHABLE(); + case Location::kEffect: // Pop the left-hand value into rax because we will not need it as the // final result. __ pop(rax); break; - case Location::TEMP: + case Location::kValue: // Copy the left-hand value into rax because we may need it as the // final result. __ movq(rax, Operand(rsp, 0)); @@ -667,41 +737,41 @@ void FastCodeGenerator::VisitBinaryOperation(BinaryOperation* expr) { } } // The left-hand value is in rax. It is also on the stack iff the - // destination location is temporary. + // destination location is value. // Perform fast checks assumed by the stub. // The undefined value is false. __ CompareRoot(rax, Heap::kUndefinedValueRootIndex); - __ j(equal, &eval_right); + __ j(equal, left_false); __ CompareRoot(rax, Heap::kTrueValueRootIndex); // True is true. - __ j(equal, &done); + __ j(equal, left_true); __ CompareRoot(rax, Heap::kFalseValueRootIndex); // False is false. - __ j(equal, &eval_right); + __ j(equal, left_false); ASSERT(kSmiTag == 0); __ SmiCompare(rax, Smi::FromInt(0)); // The smi zero is false. - __ j(equal, &eval_right); + __ j(equal, left_false); Condition is_smi = masm_->CheckSmi(rax); // All other smis are true. - __ j(is_smi, &done); + __ j(is_smi, left_true); // Call the stub for all other cases. __ push(rax); ToBooleanStub stub; __ CallStub(&stub); __ testq(rax, rax); // The stub returns nonzero for true. - __ j(not_zero, &done); + if (expr->op() == Token::OR) { + __ j(not_zero, &done); + } else { + __ j(zero, &done); + } __ bind(&eval_right); // Discard the left-hand value if present on the stack. - if (destination.is_temporary()) { + if (destination.is_value()) { __ addq(rsp, Immediate(kPointerSize)); } // Save or discard the right-hand value as needed. - if (right->AsLiteral() != NULL) { - Move(destination, right->AsLiteral()); - } else { - Visit(right); - Move(destination, right->location()); - } + Visit(right); + ASSERT_EQ(destination.type(), right->location().type()); __ bind(&done); } diff --git a/deps/v8/src/x64/frames-x64.cc b/deps/v8/src/x64/frames-x64.cc index 6a0527cf6d..fe224ad998 100644 --- a/deps/v8/src/x64/frames-x64.cc +++ b/deps/v8/src/x64/frames-x64.cc @@ -57,7 +57,11 @@ StackFrame::Type ExitFrame::GetStateForFramePointer(Address fp, State* state) { state->sp = sp; state->pc_address = reinterpret_cast<Address*>(sp - 1 * kPointerSize); // Determine frame type. - return EXIT; + if (Memory::Address_at(fp + ExitFrameConstants::kDebugMarkOffset) != 0) { + return EXIT_DEBUG; + } else { + return EXIT; + } } int JavaScriptFrame::GetProvidedParametersCount() const { @@ -65,10 +69,10 @@ int JavaScriptFrame::GetProvidedParametersCount() const { } -void ExitFrame::Iterate(ObjectVisitor* v) const { - v->VisitPointer(&code_slot()); - // The arguments are traversed as part of the expression stack of - // the calling frame. +void ExitFrame::Iterate(ObjectVisitor* a) const { + // Exit frames on X64 do not contain any pointers. The arguments + // are traversed as part of the expression stack of the calling + // frame. } byte* InternalFrame::GetCallerStackPointer() const { diff --git a/deps/v8/src/x64/frames-x64.h b/deps/v8/src/x64/frames-x64.h index a92b248d88..eefaa0aeb5 100644 --- a/deps/v8/src/x64/frames-x64.h +++ b/deps/v8/src/x64/frames-x64.h @@ -63,7 +63,7 @@ class EntryFrameConstants : public AllStatic { class ExitFrameConstants : public AllStatic { public: - static const int kCodeOffset = -2 * kPointerSize; + static const int kDebugMarkOffset = -2 * kPointerSize; static const int kSPOffset = -1 * kPointerSize; static const int kCallerFPOffset = +0 * kPointerSize; diff --git a/deps/v8/src/x64/macro-assembler-x64.cc b/deps/v8/src/x64/macro-assembler-x64.cc index 6bf6e6a712..b2f69bb7a9 100644 --- a/deps/v8/src/x64/macro-assembler-x64.cc +++ b/deps/v8/src/x64/macro-assembler-x64.cc @@ -1787,7 +1787,9 @@ void MacroAssembler::LeaveFrame(StackFrame::Type type) { } -void MacroAssembler::EnterExitFrame(ExitFrame::Mode mode, int result_size) { +void MacroAssembler::EnterExitFrame(StackFrame::Type type, int result_size) { + ASSERT(type == StackFrame::EXIT || type == StackFrame::EXIT_DEBUG); + // Setup the frame structure on the stack. // All constants are relative to the frame pointer of the exit frame. ASSERT(ExitFrameConstants::kCallerSPDisplacement == +2 * kPointerSize); @@ -1799,12 +1801,7 @@ void MacroAssembler::EnterExitFrame(ExitFrame::Mode mode, int result_size) { // Reserve room for entry stack pointer and push the debug marker. ASSERT(ExitFrameConstants::kSPOffset == -1 * kPointerSize); push(Immediate(0)); // saved entry sp, patched before call - if (mode == ExitFrame::MODE_DEBUG) { - push(Immediate(0)); - } else { - movq(kScratchRegister, CodeObject(), RelocInfo::EMBEDDED_OBJECT); - push(kScratchRegister); - } + push(Immediate(type == StackFrame::EXIT_DEBUG ? 1 : 0)); // Save the frame pointer and the context in top. ExternalReference c_entry_fp_address(Top::k_c_entry_fp_address); @@ -1824,7 +1821,7 @@ void MacroAssembler::EnterExitFrame(ExitFrame::Mode mode, int result_size) { #ifdef ENABLE_DEBUGGER_SUPPORT // Save the state of all registers to the stack from the memory // location. This is needed to allow nested break points. - if (mode == ExitFrame::MODE_DEBUG) { + if (type == StackFrame::EXIT_DEBUG) { // TODO(1243899): This should be symmetric to // CopyRegistersFromStackToMemory() but it isn't! esp is assumed // correct here, but computed for the other call. Very error @@ -1863,17 +1860,17 @@ void MacroAssembler::EnterExitFrame(ExitFrame::Mode mode, int result_size) { } -void MacroAssembler::LeaveExitFrame(ExitFrame::Mode mode, int result_size) { +void MacroAssembler::LeaveExitFrame(StackFrame::Type type, int result_size) { // Registers: // r15 : argv #ifdef ENABLE_DEBUGGER_SUPPORT // Restore the memory copy of the registers by digging them out from // the stack. This is needed to allow nested break points. - if (mode == ExitFrame::MODE_DEBUG) { + if (type == StackFrame::EXIT_DEBUG) { // It's okay to clobber register rbx below because we don't need // the function pointer after this. const int kCallerSavedSize = kNumJSCallerSaved * kPointerSize; - int kOffset = ExitFrameConstants::kCodeOffset - kCallerSavedSize; + int kOffset = ExitFrameConstants::kDebugMarkOffset - kCallerSavedSize; lea(rbx, Operand(rbp, kOffset)); CopyRegistersFromStackToMemory(rbx, rcx, kJSCallerSaved); } diff --git a/deps/v8/src/x64/macro-assembler-x64.h b/deps/v8/src/x64/macro-assembler-x64.h index 11cdfc3c4c..4c2f35bd9c 100644 --- a/deps/v8/src/x64/macro-assembler-x64.h +++ b/deps/v8/src/x64/macro-assembler-x64.h @@ -106,16 +106,16 @@ class MacroAssembler: public Assembler { void EnterConstructFrame() { EnterFrame(StackFrame::CONSTRUCT); } void LeaveConstructFrame() { LeaveFrame(StackFrame::CONSTRUCT); } - // Enter specific kind of exit frame; either in normal or - // debug mode. Expects the number of arguments in register rax and + // Enter specific kind of exit frame; either EXIT or + // EXIT_DEBUG. Expects the number of arguments in register rax and // sets up the number of arguments in register rdi and the pointer // to the first argument in register rsi. - void EnterExitFrame(ExitFrame::Mode mode, int result_size = 1); + void EnterExitFrame(StackFrame::Type type, int result_size = 1); // Leave the current exit frame. Expects/provides the return value in // register rax:rdx (untouched) and the pointer to the first // argument in register rsi. - void LeaveExitFrame(ExitFrame::Mode mode, int result_size = 1); + void LeaveExitFrame(StackFrame::Type type, int result_size = 1); // --------------------------------------------------------------------------- diff --git a/deps/v8/test/cctest/SConscript b/deps/v8/test/cctest/SConscript index 9deefa5542..f041041c11 100644 --- a/deps/v8/test/cctest/SConscript +++ b/deps/v8/test/cctest/SConscript @@ -34,7 +34,6 @@ Import('context object_files') SOURCES = { 'all': [ - 'test-accessors.cc', 'test-alloc.cc', 'test-api.cc', 'test-ast.cc', diff --git a/deps/v8/test/cctest/cctest.cc b/deps/v8/test/cctest/cctest.cc index f638ed480f..82a33e6da5 100644 --- a/deps/v8/test/cctest/cctest.cc +++ b/deps/v8/test/cctest/cctest.cc @@ -121,6 +121,3 @@ int main(int argc, char* argv[]) { v8::V8::Dispose(); return 0; } - -RegisterThreadedTest *RegisterThreadedTest::first_ = NULL; -int RegisterThreadedTest::count_ = 0; diff --git a/deps/v8/test/cctest/cctest.h b/deps/v8/test/cctest/cctest.h index 404b692b27..a95645e010 100644 --- a/deps/v8/test/cctest/cctest.h +++ b/deps/v8/test/cctest/cctest.h @@ -28,8 +28,6 @@ #ifndef CCTEST_H_ #define CCTEST_H_ -#include "v8.h" - #ifndef TEST #define TEST(Name) \ static void Test##Name(); \ @@ -74,138 +72,4 @@ class CcTest { CcTest* prev_; }; -// Switches between all the Api tests using the threading support. -// In order to get a surprising but repeatable pattern of thread -// switching it has extra semaphores to control the order in which -// the tests alternate, not relying solely on the big V8 lock. -// -// A test is augmented with calls to ApiTestFuzzer::Fuzz() in its -// callbacks. This will have no effect when we are not running the -// thread fuzzing test. In the thread fuzzing test it will -// pseudorandomly select a successor thread and switch execution -// to that thread, suspending the current test. -class ApiTestFuzzer: public v8::internal::Thread { - public: - void CallTest(); - explicit ApiTestFuzzer(int num) - : test_number_(num), - gate_(v8::internal::OS::CreateSemaphore(0)), - active_(true) { - } - ~ApiTestFuzzer() { delete gate_; } - - // The ApiTestFuzzer is also a Thread, so it has a Run method. - virtual void Run(); - - enum PartOfTest { FIRST_PART, SECOND_PART }; - - static void Setup(PartOfTest part); - static void RunAllTests(); - static void TearDown(); - // This method switches threads if we are running the Threading test. - // Otherwise it does nothing. - static void Fuzz(); - private: - static bool fuzzing_; - static int tests_being_run_; - static int current_; - static int active_tests_; - static bool NextThread(); - int test_number_; - v8::internal::Semaphore* gate_; - bool active_; - void ContextSwitch(); - static int GetNextTestNumber(); - static v8::internal::Semaphore* all_tests_done_; -}; - - -#define THREADED_TEST(Name) \ - static void Test##Name(); \ - RegisterThreadedTest register_##Name(Test##Name, #Name); \ - /* */ TEST(Name) - - -class RegisterThreadedTest { - public: - explicit RegisterThreadedTest(CcTest::TestFunction* callback, - const char* name) - : fuzzer_(NULL), callback_(callback), name_(name) { - prev_ = first_; - first_ = this; - count_++; - } - static int count() { return count_; } - static RegisterThreadedTest* nth(int i) { - CHECK(i < count()); - RegisterThreadedTest* current = first_; - while (i > 0) { - i--; - current = current->prev_; - } - return current; - } - CcTest::TestFunction* callback() { return callback_; } - ApiTestFuzzer* fuzzer_; - const char* name() { return name_; } - - private: - static RegisterThreadedTest* first_; - static int count_; - CcTest::TestFunction* callback_; - RegisterThreadedTest* prev_; - const char* name_; -}; - - -// A LocalContext holds a reference to a v8::Context. -class LocalContext { - public: - LocalContext(v8::ExtensionConfiguration* extensions = 0, - v8::Handle<v8::ObjectTemplate> global_template = - v8::Handle<v8::ObjectTemplate>(), - v8::Handle<v8::Value> global_object = v8::Handle<v8::Value>()) - : context_(v8::Context::New(extensions, global_template, global_object)) { - context_->Enter(); - } - - virtual ~LocalContext() { - context_->Exit(); - context_.Dispose(); - } - - v8::Context* operator->() { return *context_; } - v8::Context* operator*() { return *context_; } - bool IsReady() { return !context_.IsEmpty(); } - - v8::Local<v8::Context> local() { - return v8::Local<v8::Context>::New(context_); - } - - private: - v8::Persistent<v8::Context> context_; -}; - - -static inline v8::Local<v8::Value> v8_num(double x) { - return v8::Number::New(x); -} - - -static inline v8::Local<v8::String> v8_str(const char* x) { - return v8::String::New(x); -} - - -static inline v8::Local<v8::Script> v8_compile(const char* x) { - return v8::Script::Compile(v8_str(x)); -} - - -// Helper function that compiles and runs the source. -static inline v8::Local<v8::Value> CompileRun(const char* source) { - return v8::Script::Compile(v8::String::New(source))->Run(); -} - - #endif // ifndef CCTEST_H_ diff --git a/deps/v8/test/cctest/test-accessors.cc b/deps/v8/test/cctest/test-accessors.cc deleted file mode 100644 index b56238ad69..0000000000 --- a/deps/v8/test/cctest/test-accessors.cc +++ /dev/null @@ -1,424 +0,0 @@ -// 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. - -#include <stdlib.h> - -#include "v8.h" - -#include "api.h" -#include "cctest.h" -#include "frames-inl.h" -#include "string-stream.h" - -using ::v8::ObjectTemplate; -using ::v8::Value; -using ::v8::Context; -using ::v8::Local; -using ::v8::String; -using ::v8::Script; -using ::v8::Function; -using ::v8::AccessorInfo; -using ::v8::Extension; - -namespace i = ::v8::internal; - -static v8::Handle<Value> handle_property(Local<String> name, - const AccessorInfo&) { - ApiTestFuzzer::Fuzz(); - return v8_num(900); -} - - -THREADED_TEST(PropertyHandler) { - v8::HandleScope scope; - Local<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New(); - fun_templ->InstanceTemplate()->SetAccessor(v8_str("foo"), handle_property); - LocalContext env; - Local<Function> fun = fun_templ->GetFunction(); - env->Global()->Set(v8_str("Fun"), fun); - Local<Script> getter = v8_compile("var obj = new Fun(); obj.foo;"); - CHECK_EQ(900, getter->Run()->Int32Value()); - Local<Script> setter = v8_compile("obj.foo = 901;"); - CHECK_EQ(901, setter->Run()->Int32Value()); -} - - -static v8::Handle<Value> GetIntValue(Local<String> property, - const AccessorInfo& info) { - ApiTestFuzzer::Fuzz(); - int* value = - static_cast<int*>(v8::Handle<v8::External>::Cast(info.Data())->Value()); - return v8_num(*value); -} - - -static void SetIntValue(Local<String> property, - Local<Value> value, - const AccessorInfo& info) { - int* field = - static_cast<int*>(v8::Handle<v8::External>::Cast(info.Data())->Value()); - *field = value->Int32Value(); -} - -int foo, bar, baz; - -THREADED_TEST(GlobalVariableAccess) { - foo = 0; - bar = -4; - baz = 10; - v8::HandleScope scope; - v8::Handle<v8::FunctionTemplate> templ = v8::FunctionTemplate::New(); - templ->InstanceTemplate()->SetAccessor(v8_str("foo"), - GetIntValue, - SetIntValue, - v8::External::New(&foo)); - templ->InstanceTemplate()->SetAccessor(v8_str("bar"), - GetIntValue, - SetIntValue, - v8::External::New(&bar)); - templ->InstanceTemplate()->SetAccessor(v8_str("baz"), - GetIntValue, - SetIntValue, - v8::External::New(&baz)); - LocalContext env(0, templ->InstanceTemplate()); - v8_compile("foo = (++bar) + baz")->Run(); - CHECK_EQ(bar, -3); - CHECK_EQ(foo, 7); -} - - -static int x_register = 0; -static v8::Handle<v8::Object> x_receiver; -static v8::Handle<v8::Object> x_holder; - - -static v8::Handle<Value> XGetter(Local<String> name, const AccessorInfo& info) { - ApiTestFuzzer::Fuzz(); - CHECK_EQ(x_receiver, info.This()); - CHECK_EQ(x_holder, info.Holder()); - return v8_num(x_register); -} - - -static void XSetter(Local<String> name, - Local<Value> value, - const AccessorInfo& info) { - CHECK_EQ(x_holder, info.This()); - CHECK_EQ(x_holder, info.Holder()); - x_register = value->Int32Value(); -} - - -THREADED_TEST(AccessorIC) { - v8::HandleScope scope; - v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New(); - obj->SetAccessor(v8_str("x"), XGetter, XSetter); - LocalContext context; - x_holder = obj->NewInstance(); - context->Global()->Set(v8_str("holder"), x_holder); - x_receiver = v8::Object::New(); - context->Global()->Set(v8_str("obj"), x_receiver); - v8::Handle<v8::Array> array = v8::Handle<v8::Array>::Cast(CompileRun( - "obj.__proto__ = holder;" - "var result = [];" - "for (var i = 0; i < 10; i++) {" - " holder.x = i;" - " result.push(obj.x);" - "}" - "result")); - CHECK_EQ(10, array->Length()); - for (int i = 0; i < 10; i++) { - v8::Handle<Value> entry = array->Get(v8::Integer::New(i)); - CHECK_EQ(v8::Integer::New(i), entry); - } -} - - -static v8::Handle<Value> AccessorProhibitsOverwritingGetter( - Local<String> name, - const AccessorInfo& info) { - ApiTestFuzzer::Fuzz(); - return v8::True(); -} - - -THREADED_TEST(AccessorProhibitsOverwriting) { - v8::HandleScope scope; - LocalContext context; - Local<ObjectTemplate> templ = ObjectTemplate::New(); - templ->SetAccessor(v8_str("x"), - AccessorProhibitsOverwritingGetter, - 0, - v8::Handle<Value>(), - v8::PROHIBITS_OVERWRITING, - v8::ReadOnly); - Local<v8::Object> instance = templ->NewInstance(); - context->Global()->Set(v8_str("obj"), instance); - Local<Value> value = CompileRun( - "obj.__defineGetter__('x', function() { return false; });" - "obj.x"); - CHECK(value->BooleanValue()); - value = CompileRun( - "var setter_called = false;" - "obj.__defineSetter__('x', function() { setter_called = true; });" - "obj.x = 42;" - "setter_called"); - CHECK(!value->BooleanValue()); - value = CompileRun( - "obj2 = {};" - "obj2.__proto__ = obj;" - "obj2.__defineGetter__('x', function() { return false; });" - "obj2.x"); - CHECK(value->BooleanValue()); - value = CompileRun( - "var setter_called = false;" - "obj2 = {};" - "obj2.__proto__ = obj;" - "obj2.__defineSetter__('x', function() { setter_called = true; });" - "obj2.x = 42;" - "setter_called"); - CHECK(!value->BooleanValue()); -} - - -template <int C> -static v8::Handle<Value> HandleAllocatingGetter(Local<String> name, - const AccessorInfo& info) { - ApiTestFuzzer::Fuzz(); - for (int i = 0; i < C; i++) - v8::String::New("foo"); - return v8::String::New("foo"); -} - - -THREADED_TEST(HandleScopePop) { - v8::HandleScope scope; - v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New(); - obj->SetAccessor(v8_str("one"), HandleAllocatingGetter<1>); - obj->SetAccessor(v8_str("many"), HandleAllocatingGetter<1024>); - LocalContext context; - v8::Handle<v8::Object> inst = obj->NewInstance(); - context->Global()->Set(v8::String::New("obj"), inst); - int count_before = i::HandleScope::NumberOfHandles(); - { - v8::HandleScope scope; - CompileRun( - "for (var i = 0; i < 1000; i++) {" - " obj.one;" - " obj.many;" - "}"); - } - int count_after = i::HandleScope::NumberOfHandles(); - CHECK_EQ(count_before, count_after); -} - -static v8::Handle<Value> CheckAccessorArgsCorrect(Local<String> name, - const AccessorInfo& info) { - CHECK(info.This() == info.Holder()); - CHECK(info.Data()->Equals(v8::String::New("data"))); - ApiTestFuzzer::Fuzz(); - CHECK(info.This() == info.Holder()); - CHECK(info.Data()->Equals(v8::String::New("data"))); - i::Heap::CollectAllGarbage(true); - CHECK(info.This() == info.Holder()); - CHECK(info.Data()->Equals(v8::String::New("data"))); - return v8::Integer::New(17); -} - -THREADED_TEST(DirectCall) { - v8::HandleScope scope; - v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New(); - obj->SetAccessor(v8_str("xxx"), - CheckAccessorArgsCorrect, - NULL, - v8::String::New("data")); - LocalContext context; - v8::Handle<v8::Object> inst = obj->NewInstance(); - context->Global()->Set(v8::String::New("obj"), inst); - Local<Script> scr = v8::Script::Compile(v8::String::New("obj.xxx")); - for (int i = 0; i < 10; i++) { - Local<Value> result = scr->Run(); - CHECK(!result.IsEmpty()); - CHECK_EQ(17, result->Int32Value()); - } -} - -static v8::Handle<Value> EmptyGetter(Local<String> name, - const AccessorInfo& info) { - CheckAccessorArgsCorrect(name, info); - ApiTestFuzzer::Fuzz(); - CheckAccessorArgsCorrect(name, info); - return v8::Handle<v8::Value>(); -} - -THREADED_TEST(EmptyResult) { - v8::HandleScope scope; - v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New(); - obj->SetAccessor(v8_str("xxx"), EmptyGetter, NULL, v8::String::New("data")); - LocalContext context; - v8::Handle<v8::Object> inst = obj->NewInstance(); - context->Global()->Set(v8::String::New("obj"), inst); - Local<Script> scr = v8::Script::Compile(v8::String::New("obj.xxx")); - for (int i = 0; i < 10; i++) { - Local<Value> result = scr->Run(); - CHECK(result == v8::Undefined()); - } -} - - -THREADED_TEST(NoReuseRegress) { - // Check that the IC generated for the one test doesn't get reused - // for the other. - v8::HandleScope scope; - { - v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New(); - obj->SetAccessor(v8_str("xxx"), EmptyGetter, NULL, v8::String::New("data")); - LocalContext context; - v8::Handle<v8::Object> inst = obj->NewInstance(); - context->Global()->Set(v8::String::New("obj"), inst); - Local<Script> scr = v8::Script::Compile(v8::String::New("obj.xxx")); - for (int i = 0; i < 2; i++) { - Local<Value> result = scr->Run(); - CHECK(result == v8::Undefined()); - } - } - { - v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New(); - obj->SetAccessor(v8_str("xxx"), - CheckAccessorArgsCorrect, - NULL, - v8::String::New("data")); - LocalContext context; - v8::Handle<v8::Object> inst = obj->NewInstance(); - context->Global()->Set(v8::String::New("obj"), inst); - Local<Script> scr = v8::Script::Compile(v8::String::New("obj.xxx")); - for (int i = 0; i < 10; i++) { - Local<Value> result = scr->Run(); - CHECK(!result.IsEmpty()); - CHECK_EQ(17, result->Int32Value()); - } - } -} - -static v8::Handle<Value> ThrowingGetAccessor(Local<String> name, - const AccessorInfo& info) { - ApiTestFuzzer::Fuzz(); - return v8::ThrowException(v8_str("g")); -} - - -static void ThrowingSetAccessor(Local<String> name, - Local<Value> value, - const AccessorInfo& info) { - v8::ThrowException(value); -} - - -THREADED_TEST(Regress1054726) { - v8::HandleScope scope; - v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New(); - obj->SetAccessor(v8_str("x"), - ThrowingGetAccessor, - ThrowingSetAccessor, - Local<Value>()); - - LocalContext env; - env->Global()->Set(v8_str("obj"), obj->NewInstance()); - - // Use the throwing property setter/getter in a loop to force - // the accessor ICs to be initialized. - v8::Handle<Value> result; - result = Script::Compile(v8_str( - "var result = '';" - "for (var i = 0; i < 5; i++) {" - " try { obj.x; } catch (e) { result += e; }" - "}; result"))->Run(); - CHECK_EQ(v8_str("ggggg"), result); - - result = Script::Compile(String::New( - "var result = '';" - "for (var i = 0; i < 5; i++) {" - " try { obj.x = i; } catch (e) { result += e; }" - "}; result"))->Run(); - CHECK_EQ(v8_str("01234"), result); -} - - -static v8::Handle<Value> AllocGetter(Local<String> name, - const AccessorInfo& info) { - ApiTestFuzzer::Fuzz(); - return v8::Array::New(1000); -} - - -THREADED_TEST(Gc) { - v8::HandleScope scope; - v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New(); - obj->SetAccessor(v8_str("xxx"), AllocGetter); - LocalContext env; - env->Global()->Set(v8_str("obj"), obj->NewInstance()); - Script::Compile(String::New( - "var last = [];" - "for (var i = 0; i < 2048; i++) {" - " var result = obj.xxx;" - " result[0] = last;" - " last = result;" - "}"))->Run(); -} - - -static v8::Handle<Value> StackCheck(Local<String> name, - const AccessorInfo& info) { - i::StackFrameIterator iter; - for (int i = 0; !iter.done(); i++) { - i::StackFrame* frame = iter.frame(); - CHECK(i != 0 || (frame->type() == i::StackFrame::EXIT)); - CHECK(frame->code()->IsCode()); - i::Address pc = frame->pc(); - i::Code* code = frame->code(); - CHECK(code->contains(pc)); - iter.Advance(); - } - return v8::Undefined(); -} - - -THREADED_TEST(StackIteration) { - v8::HandleScope scope; - v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New(); - i::StringStream::ClearMentionedObjectCache(); - obj->SetAccessor(v8_str("xxx"), StackCheck); - LocalContext env; - env->Global()->Set(v8_str("obj"), obj->NewInstance()); - Script::Compile(String::New( - "function foo() {" - " return obj.xxx;" - "}" - "for (var i = 0; i < 100; i++) {" - " foo();" - "}"))->Run(); -} diff --git a/deps/v8/test/cctest/test-api.cc b/deps/v8/test/cctest/test-api.cc index 83038ae1a7..1d4b2c34c3 100644 --- a/deps/v8/test/cctest/test-api.cc +++ b/deps/v8/test/cctest/test-api.cc @@ -38,8 +38,6 @@ #include "utils.h" #include "cctest.h" -static const bool kLogThreading = false; - static bool IsNaN(double x) { #ifdef WIN32 return _isnan(x); @@ -60,6 +58,131 @@ using ::v8::Extension; namespace i = ::v8::internal; +static Local<Value> v8_num(double x) { + return v8::Number::New(x); +} + + +static Local<String> v8_str(const char* x) { + return String::New(x); +} + + +static Local<Script> v8_compile(const char* x) { + return Script::Compile(v8_str(x)); +} + + +// A LocalContext holds a reference to a v8::Context. +class LocalContext { + public: + LocalContext(v8::ExtensionConfiguration* extensions = 0, + v8::Handle<ObjectTemplate> global_template = + v8::Handle<ObjectTemplate>(), + v8::Handle<Value> global_object = v8::Handle<Value>()) + : context_(Context::New(extensions, global_template, global_object)) { + context_->Enter(); + } + + virtual ~LocalContext() { + context_->Exit(); + context_.Dispose(); + } + + Context* operator->() { return *context_; } + Context* operator*() { return *context_; } + Local<Context> local() { return Local<Context>::New(context_); } + bool IsReady() { return !context_.IsEmpty(); } + + private: + v8::Persistent<Context> context_; +}; + + +// Switches between all the Api tests using the threading support. +// In order to get a surprising but repeatable pattern of thread +// switching it has extra semaphores to control the order in which +// the tests alternate, not relying solely on the big V8 lock. +// +// A test is augmented with calls to ApiTestFuzzer::Fuzz() in its +// callbacks. This will have no effect when we are not running the +// thread fuzzing test. In the thread fuzzing test it will +// pseudorandomly select a successor thread and switch execution +// to that thread, suspending the current test. +class ApiTestFuzzer: public v8::internal::Thread { + public: + void CallTest(); + explicit ApiTestFuzzer(int num) + : test_number_(num), + gate_(v8::internal::OS::CreateSemaphore(0)), + active_(true) { + } + ~ApiTestFuzzer() { delete gate_; } + + // The ApiTestFuzzer is also a Thread, so it has a Run method. + virtual void Run(); + + enum PartOfTest { FIRST_PART, SECOND_PART }; + + static void Setup(PartOfTest part); + static void RunAllTests(); + static void TearDown(); + // This method switches threads if we are running the Threading test. + // Otherwise it does nothing. + static void Fuzz(); + private: + static bool fuzzing_; + static int tests_being_run_; + static int current_; + static int active_tests_; + static bool NextThread(); + int test_number_; + v8::internal::Semaphore* gate_; + bool active_; + void ContextSwitch(); + static int GetNextTestNumber(); + static v8::internal::Semaphore* all_tests_done_; +}; + + +#define THREADED_TEST(Name) \ + static void Test##Name(); \ + RegisterThreadedTest register_##Name(Test##Name); \ + /* */ TEST(Name) + + +class RegisterThreadedTest { + public: + explicit RegisterThreadedTest(CcTest::TestFunction* callback) + : fuzzer_(NULL), callback_(callback) { + prev_ = first_; + first_ = this; + count_++; + } + static int count() { return count_; } + static RegisterThreadedTest* nth(int i) { + CHECK(i < count()); + RegisterThreadedTest* current = first_; + while (i > 0) { + i--; + current = current->prev_; + } + return current; + } + CcTest::TestFunction* callback() { return callback_; } + ApiTestFuzzer* fuzzer_; + + private: + static RegisterThreadedTest* first_; + static int count_; + CcTest::TestFunction* callback_; + RegisterThreadedTest* prev_; +}; + + +RegisterThreadedTest *RegisterThreadedTest::first_ = NULL; +int RegisterThreadedTest::count_ = 0; + static int signature_callback_count; static v8::Handle<Value> IncrementingSignatureCallback( @@ -108,6 +231,11 @@ THREADED_TEST(Handles) { } +// Helper function that compiles and runs the source. +static Local<Value> CompileRun(const char* source) { + return Script::Compile(String::New(source))->Run(); +} + THREADED_TEST(ReceiverSignature) { v8::HandleScope scope; LocalContext env; @@ -592,6 +720,27 @@ THREADED_TEST(FindInstanceInPrototypeChain) { } +static v8::Handle<Value> handle_property(Local<String> name, + const AccessorInfo&) { + ApiTestFuzzer::Fuzz(); + return v8_num(900); +} + + +THREADED_TEST(PropertyHandler) { + v8::HandleScope scope; + Local<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New(); + fun_templ->InstanceTemplate()->SetAccessor(v8_str("foo"), handle_property); + LocalContext env; + Local<Function> fun = fun_templ->GetFunction(); + env->Global()->Set(v8_str("Fun"), fun); + Local<Script> getter = v8_compile("var obj = new Fun(); obj.foo;"); + CHECK_EQ(900, getter->Run()->Int32Value()); + Local<Script> setter = v8_compile("obj.foo = 901;"); + CHECK_EQ(901, setter->Run()->Int32Value()); +} + + THREADED_TEST(TinyInteger) { v8::HandleScope scope; LocalContext env; @@ -758,6 +907,49 @@ THREADED_TEST(GlobalPrototype) { } +static v8::Handle<Value> GetIntValue(Local<String> property, + const AccessorInfo& info) { + ApiTestFuzzer::Fuzz(); + int* value = + static_cast<int*>(v8::Handle<v8::External>::Cast(info.Data())->Value()); + return v8_num(*value); +} + +static void SetIntValue(Local<String> property, + Local<Value> value, + const AccessorInfo& info) { + int* field = + static_cast<int*>(v8::Handle<v8::External>::Cast(info.Data())->Value()); + *field = value->Int32Value(); +} + +int foo, bar, baz; + +THREADED_TEST(GlobalVariableAccess) { + foo = 0; + bar = -4; + baz = 10; + v8::HandleScope scope; + v8::Handle<v8::FunctionTemplate> templ = v8::FunctionTemplate::New(); + templ->InstanceTemplate()->SetAccessor(v8_str("foo"), + GetIntValue, + SetIntValue, + v8::External::New(&foo)); + templ->InstanceTemplate()->SetAccessor(v8_str("bar"), + GetIntValue, + SetIntValue, + v8::External::New(&bar)); + templ->InstanceTemplate()->SetAccessor(v8_str("baz"), + GetIntValue, + SetIntValue, + v8::External::New(&baz)); + LocalContext env(0, templ->InstanceTemplate()); + v8_compile("foo = (++bar) + baz")->Run(); + CHECK_EQ(bar, -3); + CHECK_EQ(foo, 7); +} + + THREADED_TEST(ObjectTemplate) { v8::HandleScope scope; Local<ObjectTemplate> templ1 = ObjectTemplate::New(); @@ -1173,6 +1365,50 @@ THREADED_TEST(CallbackExceptionRegression) { } +static v8::Handle<Value> ThrowingGetAccessor(Local<String> name, + const AccessorInfo& info) { + ApiTestFuzzer::Fuzz(); + return v8::ThrowException(v8_str("g")); +} + + +static void ThrowingSetAccessor(Local<String> name, + Local<Value> value, + const AccessorInfo& info) { + v8::ThrowException(value); +} + + +THREADED_TEST(Regress1054726) { + v8::HandleScope scope; + v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New(); + obj->SetAccessor(v8_str("x"), + ThrowingGetAccessor, + ThrowingSetAccessor, + Local<Value>()); + + LocalContext env; + env->Global()->Set(v8_str("obj"), obj->NewInstance()); + + // Use the throwing property setter/getter in a loop to force + // the accessor ICs to be initialized. + v8::Handle<Value> result; + result = Script::Compile(v8_str( + "var result = '';" + "for (var i = 0; i < 5; i++) {" + " try { obj.x; } catch (e) { result += e; }" + "}; result"))->Run(); + CHECK_EQ(v8_str("ggggg"), result); + + result = Script::Compile(String::New( + "var result = '';" + "for (var i = 0; i < 5; i++) {" + " try { obj.x = i; } catch (e) { result += e; }" + "}; result"))->Run(); + CHECK_EQ(v8_str("01234"), result); +} + + THREADED_TEST(FunctionPrototype) { v8::HandleScope scope; Local<v8::FunctionTemplate> Foo = v8::FunctionTemplate::New(); @@ -2948,6 +3184,53 @@ THREADED_TEST(Arguments) { } +static int x_register = 0; +static v8::Handle<v8::Object> x_receiver; +static v8::Handle<v8::Object> x_holder; + + +static v8::Handle<Value> XGetter(Local<String> name, const AccessorInfo& info) { + ApiTestFuzzer::Fuzz(); + CHECK_EQ(x_receiver, info.This()); + CHECK_EQ(x_holder, info.Holder()); + return v8_num(x_register); +} + + +static void XSetter(Local<String> name, + Local<Value> value, + const AccessorInfo& info) { + CHECK_EQ(x_holder, info.This()); + CHECK_EQ(x_holder, info.Holder()); + x_register = value->Int32Value(); +} + + +THREADED_TEST(AccessorIC) { + v8::HandleScope scope; + v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New(); + obj->SetAccessor(v8_str("x"), XGetter, XSetter); + LocalContext context; + x_holder = obj->NewInstance(); + context->Global()->Set(v8_str("holder"), x_holder); + x_receiver = v8::Object::New(); + context->Global()->Set(v8_str("obj"), x_receiver); + v8::Handle<v8::Array> array = v8::Handle<v8::Array>::Cast(CompileRun( + "obj.__proto__ = holder;" + "var result = [];" + "for (var i = 0; i < 10; i++) {" + " holder.x = i;" + " result.push(obj.x);" + "}" + "result")); + CHECK_EQ(10, array->Length()); + for (int i = 0; i < 10; i++) { + v8::Handle<Value> entry = array->Get(v8::Integer::New(i)); + CHECK_EQ(v8::Integer::New(i), entry); + } +} + + static v8::Handle<Value> NoBlockGetterX(Local<String> name, const AccessorInfo&) { return v8::Handle<Value>(); @@ -5811,17 +6094,13 @@ void ApiTestFuzzer::Fuzz() { // not start immediately. bool ApiTestFuzzer::NextThread() { int test_position = GetNextTestNumber(); - const char* test_name = RegisterThreadedTest::nth(current_)->name(); + int test_number = RegisterThreadedTest::nth(current_)->fuzzer_->test_number_; if (test_position == current_) { - if (kLogThreading) - printf("Stay with %s\n", test_name); + printf("Stay with %d\n", test_number); return false; } - if (kLogThreading) { - printf("Switch from %s to %s\n", - test_name, - RegisterThreadedTest::nth(test_position)->name()); - } + printf("Switch from %d to %d\n", + current_ < 0 ? 0 : test_number, test_position < 0 ? 0 : test_number); current_ = test_position; RegisterThreadedTest::nth(current_)->fuzzer_->gate_->Signal(); return true; @@ -5930,11 +6209,9 @@ TEST(Threading2) { void ApiTestFuzzer::CallTest() { - if (kLogThreading) - printf("Start test %d\n", test_number_); + printf("Start test %d\n", test_number_); CallTestNumber(test_number_); - if (kLogThreading) - printf("End test %d\n", test_number_); + printf("End test %d\n", test_number_); } @@ -6422,6 +6699,53 @@ THREADED_TEST(PropertyEnumeration) { } +static v8::Handle<Value> AccessorProhibitsOverwritingGetter( + Local<String> name, + const AccessorInfo& info) { + ApiTestFuzzer::Fuzz(); + return v8::True(); +} + + +THREADED_TEST(AccessorProhibitsOverwriting) { + v8::HandleScope scope; + LocalContext context; + Local<ObjectTemplate> templ = ObjectTemplate::New(); + templ->SetAccessor(v8_str("x"), + AccessorProhibitsOverwritingGetter, + 0, + v8::Handle<Value>(), + v8::PROHIBITS_OVERWRITING, + v8::ReadOnly); + Local<v8::Object> instance = templ->NewInstance(); + context->Global()->Set(v8_str("obj"), instance); + Local<Value> value = CompileRun( + "obj.__defineGetter__('x', function() { return false; });" + "obj.x"); + CHECK(value->BooleanValue()); + value = CompileRun( + "var setter_called = false;" + "obj.__defineSetter__('x', function() { setter_called = true; });" + "obj.x = 42;" + "setter_called"); + CHECK(!value->BooleanValue()); + value = CompileRun( + "obj2 = {};" + "obj2.__proto__ = obj;" + "obj2.__defineGetter__('x', function() { return false; });" + "obj2.x"); + CHECK(value->BooleanValue()); + value = CompileRun( + "var setter_called = false;" + "obj2 = {};" + "obj2.__proto__ = obj;" + "obj2.__defineSetter__('x', function() { setter_called = true; });" + "obj2.x = 42;" + "setter_called"); + CHECK(!value->BooleanValue()); +} + + static bool NamedSetAccessBlocker(Local<v8::Object> obj, Local<Value> name, v8::AccessType type, diff --git a/deps/v8/test/cctest/test-debug.cc b/deps/v8/test/cctest/test-debug.cc index 656a456faa..4ffcee3dbf 100644 --- a/deps/v8/test/cctest/test-debug.cc +++ b/deps/v8/test/cctest/test-debug.cc @@ -178,6 +178,12 @@ static v8::Local<v8::Function> CompileFunction(const char* source, } +// Helper function that compiles and runs the source. +static v8::Local<v8::Value> CompileRun(const char* source) { + return v8::Script::Compile(v8::String::New(source))->Run(); +} + + // Is there any debug info for the function? static bool HasDebugInfo(v8::Handle<v8::Function> fun) { Handle<v8::internal::JSFunction> f = v8::Utils::OpenHandle(*fun); diff --git a/deps/v8/test/cctest/test-log-stack-tracer.cc b/deps/v8/test/cctest/test-log-stack-tracer.cc index 68cbc26191..39f90647e3 100644 --- a/deps/v8/test/cctest/test-log-stack-tracer.cc +++ b/deps/v8/test/cctest/test-log-stack-tracer.cc @@ -163,6 +163,11 @@ v8::Handle<v8::Value> TraceExtension::JSEntrySP(const v8::Arguments& args) { } +static void CompileRun(const char* source) { + Script::Compile(String::New(source))->Run(); +} + + v8::Handle<v8::Value> TraceExtension::JSEntrySPLevel2( const v8::Arguments& args) { v8::HandleScope scope; diff --git a/deps/v8/test/mjsunit/fuzz-natives.js b/deps/v8/test/mjsunit/fuzz-natives.js index f495c72787..cdf58a559a 100644 --- a/deps/v8/test/mjsunit/fuzz-natives.js +++ b/deps/v8/test/mjsunit/fuzz-natives.js @@ -129,9 +129,7 @@ var knownProblems = { "Log": true, "DeclareGlobals": true, - "CollectStackTrace": true, - "PromoteScheduledException": true, - "DeleteHandleScopeExtensions": true + "CollectStackTrace": true }; var currentlyUncallable = { |