Browse Source

Upgrade v8 to 1.3.18

v0.7.4-release
Ryan Dahl 15 years ago
parent
commit
6959a1d6d1
  1. 7
      deps/v8/ChangeLog
  2. 9
      deps/v8/src/api.h
  3. 18
      deps/v8/src/arm/codegen-arm.cc
  4. 221
      deps/v8/src/arm/fast-codegen-arm.cc
  5. 15
      deps/v8/src/arm/frames-arm.cc
  6. 2
      deps/v8/src/arm/frames-arm.h
  7. 19
      deps/v8/src/arm/macro-assembler-arm.cc
  8. 8
      deps/v8/src/arm/macro-assembler-arm.h
  9. 25
      deps/v8/src/assembler.cc
  10. 8
      deps/v8/src/assembler.h
  11. 2
      deps/v8/src/ast.h
  12. 34
      deps/v8/src/code-stubs.cc
  13. 7
      deps/v8/src/code-stubs.h
  14. 16
      deps/v8/src/codegen.cc
  15. 28
      deps/v8/src/codegen.h
  16. 32
      deps/v8/src/compiler.cc
  17. 28
      deps/v8/src/fast-codegen.cc
  18. 5
      deps/v8/src/fast-codegen.h
  19. 18
      deps/v8/src/frames.cc
  20. 25
      deps/v8/src/frames.h
  21. 4
      deps/v8/src/globals.h
  22. 15
      deps/v8/src/handles.cc
  23. 10
      deps/v8/src/handles.h
  24. 91
      deps/v8/src/ia32/codegen-ia32.cc
  25. 220
      deps/v8/src/ia32/fast-codegen-ia32.cc
  26. 11
      deps/v8/src/ia32/frames-ia32.cc
  27. 2
      deps/v8/src/ia32/frames-ia32.h
  28. 96
      deps/v8/src/ia32/macro-assembler-ia32.cc
  29. 16
      deps/v8/src/ia32/macro-assembler-ia32.h
  30. 39
      deps/v8/src/ia32/stub-cache-ia32.cc
  31. 15
      deps/v8/src/location.h
  32. 1
      deps/v8/src/objects-debug.cc
  33. 1
      deps/v8/src/objects-inl.h
  34. 4
      deps/v8/src/objects.h
  35. 54
      deps/v8/src/runtime.cc
  36. 3
      deps/v8/src/runtime.h
  37. 9
      deps/v8/src/string.js
  38. 7
      deps/v8/src/stub-cache.cc
  39. 4
      deps/v8/src/top.h
  40. 2
      deps/v8/src/version.cc
  41. 23
      deps/v8/src/x64/codegen-x64.cc
  42. 222
      deps/v8/src/x64/fast-codegen-x64.cc
  43. 12
      deps/v8/src/x64/frames-x64.cc
  44. 2
      deps/v8/src/x64/frames-x64.h
  45. 19
      deps/v8/src/x64/macro-assembler-x64.cc
  46. 8
      deps/v8/src/x64/macro-assembler-x64.h
  47. 1
      deps/v8/test/cctest/SConscript
  48. 3
      deps/v8/test/cctest/cctest.cc
  49. 136
      deps/v8/test/cctest/cctest.h
  50. 424
      deps/v8/test/cctest/test-accessors.cc
  51. 348
      deps/v8/test/cctest/test-api.cc
  52. 6
      deps/v8/test/cctest/test-debug.cc
  53. 5
      deps/v8/test/cctest/test-log-stack-tracer.cc
  54. 4
      deps/v8/test/mjsunit/fuzz-natives.js

7
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.

9
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,

18
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);

221
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);
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());
}
ASSERT_EQ(destination.type(), right->location().type());
__ bind(&done);
}

15
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
}

2
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;

19
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);
}

8
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);

25
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() {

8
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

2
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; }

34
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,9 +79,6 @@ Handle<Code> CodeStub::GetCode() {
}
#endif
if (custom_cache) {
SetCustomCache(*code);
} else {
// Update the dictionary and the root in Heap.
Handle<NumberDictionary> dict =
Factory::DictionaryAtNumberPut(
@ -106,11 +86,11 @@ Handle<Code> CodeStub::GetCode() {
key,
code);
Heap::public_set_code_stubs(*dict);
index = Heap::code_stubs()->FindEntry(key);
}
result = *code;
}
ASSERT(index != NumberDictionary::kNotFound);
return Handle<Code>(result);
return Handle<Code>(Code::cast(Heap::code_stubs()->ValueAt(index)));
}

7
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;

16
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

28
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) { }

32
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");
}

28
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);
}
}

5
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_;

18
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;

25
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.

4
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;

15
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>(&current_.extensions);
}
Address HandleScope::current_next_address() {
return reinterpret_cast<Address>(&current_.next);
}
Address HandleScope::current_limit_address() {
return reinterpret_cast<Address>(&current_.limit);
}
Handle<FixedArray> AddKeysFromJSArray(Handle<FixedArray> content,
Handle<JSArray> array) {
CALL_HEAP_FUNCTION(content->AddKeysFromJSArray(*array), FixedArray);

10
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);

91
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);

220
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.
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());
}
ASSERT_EQ(destination.type(), right->location().type());
__ bind(&done);
}

11
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);
// 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.
}

2
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;

96
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));

16
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,

39
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);
Register tmp = other.is(eax) ? reg : other;
__ PopHandleScope(tmp);
__ LeaveInternalFrame();
__ push(scratch2); // restore return address
__ ret(0);
// Do tail-call to the runtime system.
ExternalReference load_callback_property =
ExternalReference(IC_Utility(IC::kLoadCallbackProperty));
__ TailCallRuntime(load_callback_property, 5, 1);
}

15
deps/v8/src/location.h

@ -35,13 +35,18 @@ namespace internal {
class Location BASE_EMBEDDED {
public:
enum Type { NOWHERE, TEMP };
enum Type {
kUninitialized,
kEffect,
kValue
};
static Location Temporary() { return Location(TEMP); }
static Location Nowhere() { return Location(NOWHERE); }
static Location Uninitialized() { return Location(kUninitialized); }
static Location Effect() { return Location(kEffect); }
static Location Value() { return Location(kValue); }
bool is_temporary() { return type_ == TEMP; }
bool is_nowhere() { return type_ == NOWHERE; }
bool is_effect() { return type_ == kEffect; }
bool is_value() { return type_ == kValue; }
Type type() { return type_; }

1
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() {

1
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)

4
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.

54
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());
}
}
} 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.

3
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)

9
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);
}
}

7
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;
{

4
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_;

2
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

23
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

222
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.
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());
}
ASSERT_EQ(destination.type(), right->location().type());
__ bind(&done);
}

12
deps/v8/src/x64/frames-x64.cc

@ -57,18 +57,22 @@ StackFrame::Type ExitFrame::GetStateForFramePointer(Address fp, State* state) {
state->sp = sp;
state->pc_address = reinterpret_cast<Address*>(sp - 1 * kPointerSize);
// Determine frame type.
if (Memory::Address_at(fp + ExitFrameConstants::kDebugMarkOffset) != 0) {
return EXIT_DEBUG;
} else {
return EXIT;
}
}
int JavaScriptFrame::GetProvidedParametersCount() const {
return ComputeParametersCount();
}
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 {

2
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;

19
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);
}

8
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);
// ---------------------------------------------------------------------------

1
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',

3
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;

136
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_

424
deps/v8/test/cctest/test-accessors.cc

@ -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();
}

348
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,10 +6209,8 @@ TEST(Threading2) {
void ApiTestFuzzer::CallTest() {
if (kLogThreading)
printf("Start test %d\n", test_number_);
CallTestNumber(test_number_);
if (kLogThreading)
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,

6
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);

5
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;

4
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 = {

Loading…
Cancel
Save