Browse Source

Merge branch 'master' into net2

v0.7.4-release
Ryan Dahl 15 years ago
parent
commit
c6cc386819
  1. 9
      Makefile
  2. 2
      benchmark/http_simple.js
  3. 2
      benchmark/static_http_server.js
  4. 5
      deps/evcom/evcom.c
  5. 8
      deps/v8/ChangeLog
  6. 4
      deps/v8/src/SConscript
  7. 29
      deps/v8/src/arm/codegen-arm.cc
  8. 12
      deps/v8/src/arm/codegen-arm.h
  9. 35
      deps/v8/src/arm/fast-codegen-arm.cc
  10. 11
      deps/v8/src/ast.h
  11. 3
      deps/v8/src/codegen.cc
  12. 6
      deps/v8/src/codegen.h
  13. 53
      deps/v8/src/compiler.h
  14. 15
      deps/v8/src/debug-delay.js
  15. 3
      deps/v8/src/fast-codegen.cc
  16. 9
      deps/v8/src/fast-codegen.h
  17. 5
      deps/v8/src/frame-element.h
  18. 2
      deps/v8/src/heap.cc
  19. 4
      deps/v8/src/heap.h
  20. 123
      deps/v8/src/ia32/codegen-ia32.cc
  21. 17
      deps/v8/src/ia32/codegen-ia32.h
  22. 748
      deps/v8/src/ia32/fast-codegen-ia32.cc
  23. 155
      deps/v8/src/ia32/fast-codegen-ia32.h
  24. 76
      deps/v8/src/ia32/virtual-frame-ia32.cc
  25. 12
      deps/v8/src/ia32/virtual-frame-ia32.h
  26. 2
      deps/v8/src/jump-target-inl.h
  27. 2
      deps/v8/src/jump-target.cc
  28. 14
      deps/v8/src/macros.py
  29. 11
      deps/v8/src/mips/codegen-mips.cc
  30. 4
      deps/v8/src/mips/codegen-mips.h
  31. 33
      deps/v8/src/mirror-delay.js
  32. 2
      deps/v8/src/objects.h
  33. 2
      deps/v8/src/register-allocator.h
  34. 128
      deps/v8/src/runtime.cc
  35. 7
      deps/v8/src/runtime.js
  36. 2
      deps/v8/src/scopeinfo.cc
  37. 4
      deps/v8/src/serialize.cc
  38. 2
      deps/v8/src/spaces-inl.h
  39. 120
      deps/v8/src/string.js
  40. 14
      deps/v8/src/stub-cache.cc
  41. 6
      deps/v8/src/utils.h
  42. 4
      deps/v8/src/version.cc
  43. 40
      deps/v8/src/x64/assembler-x64.cc
  44. 94
      deps/v8/src/x64/assembler-x64.h
  45. 26
      deps/v8/src/x64/codegen-x64.cc
  46. 12
      deps/v8/src/x64/codegen-x64.h
  47. 38
      deps/v8/src/x64/fast-codegen-x64.cc
  48. 2
      deps/v8/src/x64/macro-assembler-x64.h
  49. 62
      deps/v8/test/mjsunit/bugs/bug-619.js
  50. 37
      deps/v8/test/mjsunit/debug-evaluate.js
  51. 4
      deps/v8/tools/gyp/v8.gyp
  52. 2
      deps/v8/tools/visual_studio/v8_base.vcproj
  53. 98
      doc/api.txt
  54. 2
      doc/index.html
  55. 7
      lib/http.js
  56. 63
      lib/sys.js
  57. 34
      src/node.cc
  58. 28
      src/node.js
  59. 75
      src/node_file.cc
  60. 3
      src/node_signal_handler.cc
  61. 2
      test/common.js
  62. 0
      test/disabled/test-cat.js
  63. 0
      test/disabled/test-dns.js
  64. 0
      test/disabled/test-eio-race3.js
  65. 0
      test/disabled/test-fs-sendfile.js
  66. 0
      test/disabled/test-http-stress.js
  67. 0
      test/fixtures/a.js
  68. 0
      test/fixtures/b/c.js
  69. 0
      test/fixtures/b/d.js
  70. 0
      test/fixtures/b/package/index.js
  71. 0
      test/fixtures/cycles/folder/foo.js
  72. 0
      test/fixtures/cycles/root.js
  73. 0
      test/fixtures/echo.js
  74. 0
      test/fixtures/multipart.js
  75. 0
      test/fixtures/nested-index/one/hello.js
  76. 0
      test/fixtures/nested-index/one/index.js
  77. 0
      test/fixtures/nested-index/two/hello.js
  78. 0
      test/fixtures/nested-index/two/index.js
  79. 0
      test/fixtures/print-chars.js
  80. 0
      test/fixtures/readdir/are
  81. 0
      test/fixtures/readdir/dir/empty
  82. 0
      test/fixtures/readdir/empty
  83. 0
      test/fixtures/readdir/files
  84. 0
      test/fixtures/readdir/for
  85. 0
      test/fixtures/readdir/just
  86. 0
      test/fixtures/readdir/testing.js
  87. 0
      test/fixtures/readdir/these
  88. 0
      test/fixtures/test_ca.pem
  89. 0
      test/fixtures/test_cert.pem
  90. 0
      test/fixtures/test_key.pem
  91. 0
      test/fixtures/throws_error.js
  92. 0
      test/fixtures/x.txt
  93. 1
      test/internet/internet.status
  94. 21
      test/internet/testcfg.py
  95. 40
      test/mjsunit/test-readdir.js
  96. 5
      test/mjsunit/test-sync-fileread.js
  97. 1
      test/pummel/pummel.status
  98. 2
      test/pummel/test-http-client-reconnect-bug.js
  99. 4
      test/pummel/test-keep-alive.js
  100. 8
      test/pummel/test-multipart.js

9
Makefile

@ -24,6 +24,15 @@ test-all: all
test-debug: all test-debug: all
python tools/test.py --mode=debug python tools/test.py --mode=debug
test-simple: all
python tools/test.py simple
test-pummel: all
python tools/test.py pummel
test-internet: all
python tools/test.py internet
benchmark: all benchmark: all
build/default/node benchmark/run.js build/default/node benchmark/run.js

2
benchmark/http_simple.js

@ -47,7 +47,7 @@ http.createServer(function (req, res) {
var content_length = body.length.toString(); var content_length = body.length.toString();
res.writeHeader( status res.writeHead( status
, { "Content-Type": "text/plain" , { "Content-Type": "text/plain"
, "Content-Length": content_length , "Content-Length": content_length
} }

2
benchmark/static_http_server.js

@ -16,7 +16,7 @@ for (var i = 0; i < bytes; i++) {
} }
var server = http.createServer(function (req, res) { var server = http.createServer(function (req, res) {
res.writeHeader(200, { res.writeHead(200, {
"Content-Type": "text/plain", "Content-Type": "text/plain",
"Content-Length": body.length "Content-Length": body.length
}); });

5
deps/evcom/evcom.c

@ -1018,6 +1018,11 @@ on_timeout (EV_P_ ev_timer *watcher, int revents)
if (stream->on_timeout) stream->on_timeout(stream); if (stream->on_timeout) stream->on_timeout(stream);
// Hack to get error in Node on 'close' event.
// should probably be made into a proper error code.
stream->errorno = 1;
ev_timer_stop(EV_A_ watcher);
evcom_stream_force_close(stream); evcom_stream_force_close(stream);
if (stream->on_close) stream->on_close(stream); if (stream->on_close) stream->on_close(stream);

8
deps/v8/ChangeLog

@ -1,3 +1,11 @@
2010-02-23: Version 2.1.2
Fix a crash bug caused by wrong assert.
Fix a bug with register names on 64-bit V8 (issue 615).
Performance improvements on all platforms.
2010-02-19: Version 2.1.1 2010-02-19: Version 2.1.1
[ES5] Implemented Object.defineProperty. [ES5] Implemented Object.defineProperty.

4
deps/v8/src/SConscript

@ -57,7 +57,6 @@ SOURCES = {
disassembler.cc disassembler.cc
execution.cc execution.cc
factory.cc factory.cc
fast-codegen.cc
flags.cc flags.cc
frame-element.cc frame-element.cc
frames.cc frames.cc
@ -109,6 +108,7 @@ SOURCES = {
zone.cc zone.cc
"""), """),
'arch:arm': Split(""" 'arch:arm': Split("""
fast-codegen.cc
arm/builtins-arm.cc arm/builtins-arm.cc
arm/codegen-arm.cc arm/codegen-arm.cc
arm/constants-arm.cc arm/constants-arm.cc
@ -133,6 +133,7 @@ SOURCES = {
arm/assembler-thumb2.cc arm/assembler-thumb2.cc
"""), """),
'arch:mips': Split(""" 'arch:mips': Split("""
fast-codegen.cc
mips/assembler-mips.cc mips/assembler-mips.cc
mips/builtins-mips.cc mips/builtins-mips.cc
mips/codegen-mips.cc mips/codegen-mips.cc
@ -169,6 +170,7 @@ SOURCES = {
ia32/virtual-frame-ia32.cc ia32/virtual-frame-ia32.cc
"""), """),
'arch:x64': Split(""" 'arch:x64': Split("""
fast-codegen.cc
x64/assembler-x64.cc x64/assembler-x64.cc
x64/builtins-x64.cc x64/builtins-x64.cc
x64/codegen-x64.cc x64/codegen-x64.cc

29
deps/v8/src/arm/codegen-arm.cc

@ -142,7 +142,7 @@ Scope* CodeGenerator::scope() { return info_->function()->scope(); }
// r1: called JS function // r1: called JS function
// cp: callee's context // cp: callee's context
void CodeGenerator::Generate(CompilationInfo* info, Mode mode) { void CodeGenerator::Generate(CompilationInfo* info) {
// Record the position for debugging purposes. // Record the position for debugging purposes.
CodeForFunctionPosition(info->function()); CodeForFunctionPosition(info->function());
@ -174,7 +174,7 @@ void CodeGenerator::Generate(CompilationInfo* info, Mode mode) {
} }
#endif #endif
if (mode == PRIMARY) { if (info->mode() == CompilationInfo::PRIMARY) {
frame_->Enter(); frame_->Enter();
// tos: code slot // tos: code slot
@ -277,6 +277,12 @@ void CodeGenerator::Generate(CompilationInfo* info, Mode mode) {
frame_->Adjust(4); frame_->Adjust(4);
allocator_->Unuse(r1); allocator_->Unuse(r1);
allocator_->Unuse(lr); allocator_->Unuse(lr);
// Bind all the bailout labels to the beginning of the function.
List<CompilationInfo::Bailout*>* bailouts = info->bailouts();
for (int i = 0; i < bailouts->length(); i++) {
__ bind(bailouts->at(i)->label());
}
} }
// Initialize the function return target after the locals are set // Initialize the function return target after the locals are set
@ -3420,6 +3426,25 @@ void CodeGenerator::GenerateIsArray(ZoneList<Expression*>* args) {
} }
void CodeGenerator::GenerateIsRegExp(ZoneList<Expression*>* args) {
VirtualFrame::SpilledScope spilled_scope;
ASSERT(args->length() == 1);
LoadAndSpill(args->at(0));
JumpTarget answer;
// We need the CC bits to come out as not_equal in the case where the
// object is a smi. This can't be done with the usual test opcode so
// we use XOR to get the right CC bits.
frame_->EmitPop(r0);
__ and_(r1, r0, Operand(kSmiTagMask));
__ eor(r1, r1, Operand(kSmiTagMask), SetCC);
answer.Branch(ne);
// It is a heap object - get the map. Check if the object is a regexp.
__ CompareObjectType(r0, r1, r1, JS_REGEXP_TYPE);
answer.Bind();
cc_reg_ = eq;
}
void CodeGenerator::GenerateIsObject(ZoneList<Expression*>* args) { void CodeGenerator::GenerateIsObject(ZoneList<Expression*>* args) {
// This generates a fast version of: // This generates a fast version of:
// (typeof(arg) === 'object' || %_ClassOf(arg) == 'RegExp') // (typeof(arg) === 'object' || %_ClassOf(arg) == 'RegExp')

12
deps/v8/src/arm/codegen-arm.h

@ -150,15 +150,6 @@ class CodeGenState BASE_EMBEDDED {
class CodeGenerator: public AstVisitor { class CodeGenerator: public AstVisitor {
public: public:
// Compilation mode. Either the compiler is used as the primary
// compiler and needs to setup everything or the compiler is used as
// the secondary compiler for split compilation and has to handle
// bailouts.
enum Mode {
PRIMARY,
SECONDARY
};
// Takes a function literal, generates code for it. This function should only // Takes a function literal, generates code for it. This function should only
// be called by compiler.cc. // be called by compiler.cc.
static Handle<Code> MakeCode(CompilationInfo* info); static Handle<Code> MakeCode(CompilationInfo* info);
@ -244,7 +235,7 @@ class CodeGenerator: public AstVisitor {
inline void VisitStatementsAndSpill(ZoneList<Statement*>* statements); inline void VisitStatementsAndSpill(ZoneList<Statement*>* statements);
// Main code generation function // Main code generation function
void Generate(CompilationInfo* info, Mode mode); void Generate(CompilationInfo* info);
// The following are used by class Reference. // The following are used by class Reference.
void LoadReference(Reference* ref); void LoadReference(Reference* ref);
@ -359,6 +350,7 @@ class CodeGenerator: public AstVisitor {
void GenerateIsSmi(ZoneList<Expression*>* args); void GenerateIsSmi(ZoneList<Expression*>* args);
void GenerateIsNonNegativeSmi(ZoneList<Expression*>* args); void GenerateIsNonNegativeSmi(ZoneList<Expression*>* args);
void GenerateIsArray(ZoneList<Expression*>* args); void GenerateIsArray(ZoneList<Expression*>* args);
void GenerateIsRegExp(ZoneList<Expression*>* args);
void GenerateIsObject(ZoneList<Expression*>* args); void GenerateIsObject(ZoneList<Expression*>* args);
void GenerateIsFunction(ZoneList<Expression*>* args); void GenerateIsFunction(ZoneList<Expression*>* args);
void GenerateIsUndetectableObject(ZoneList<Expression*>* args); void GenerateIsUndetectableObject(ZoneList<Expression*>* args);

35
deps/v8/src/arm/fast-codegen-arm.cc

@ -148,17 +148,25 @@ void FastCodeGenerator::EmitBitOr() {
if (!destination().is(no_reg)) { if (!destination().is(no_reg)) {
__ orr(destination(), accumulator1(), Operand(accumulator0())); __ orr(destination(), accumulator1(), Operand(accumulator0()));
} }
} else if (destination().is(no_reg)) {
// Result is not needed but do not clobber the operands in case of
// bailout.
__ orr(scratch0(), accumulator1(), Operand(accumulator0()));
__ BranchOnNotSmi(scratch0(), bailout());
} else { } else {
// Preserve the destination operand in a scratch register in case of // Left is in accumulator1, right in accumulator0.
// bailout. if (destination().is(accumulator0())) {
__ mov(scratch0(), destination()); __ mov(scratch0(), accumulator0());
__ orr(destination(), accumulator1(), Operand(accumulator0())); __ orr(destination(), accumulator1(), Operand(accumulator1()));
__ BranchOnNotSmi(destination(), bailout()); Label* bailout =
info()->AddBailout(accumulator1(), scratch0()); // Left, right.
__ BranchOnNotSmi(destination(), bailout);
} else if (destination().is(accumulator1())) {
__ mov(scratch0(), accumulator1());
__ orr(destination(), accumulator1(), Operand(accumulator0()));
Label* bailout = info()->AddBailout(scratch0(), accumulator0());
__ BranchOnNotSmi(destination(), bailout);
} else {
ASSERT(destination().is(no_reg));
__ orr(scratch0(), accumulator1(), Operand(accumulator0()));
Label* bailout = info()->AddBailout(accumulator1(), accumulator0());
__ BranchOnNotSmi(scratch0(), bailout);
}
} }
// If we didn't bailout, the result (in fact, both inputs too) is known to // If we didn't bailout, the result (in fact, both inputs too) is known to
@ -179,6 +187,7 @@ void FastCodeGenerator::Generate(CompilationInfo* compilation_info) {
// Note that we keep a live register reference to cp (context) at // Note that we keep a live register reference to cp (context) at
// this point. // this point.
Label* bailout_to_beginning = info()->AddBailout();
// Receiver (this) is allocated to a fixed register. // Receiver (this) is allocated to a fixed register.
if (info()->has_this_properties()) { if (info()->has_this_properties()) {
Comment cmnt(masm(), ";; MapCheck(this)"); Comment cmnt(masm(), ";; MapCheck(this)");
@ -189,7 +198,7 @@ void FastCodeGenerator::Generate(CompilationInfo* compilation_info) {
Handle<HeapObject> object = Handle<HeapObject>::cast(info()->receiver()); Handle<HeapObject> object = Handle<HeapObject>::cast(info()->receiver());
Handle<Map> map(object->map()); Handle<Map> map(object->map());
EmitLoadReceiver(); EmitLoadReceiver();
__ CheckMap(receiver_reg(), scratch0(), map, bailout(), false); __ CheckMap(receiver_reg(), scratch0(), map, bailout_to_beginning, false);
} }
// If there is a global variable access check if the global object is the // If there is a global variable access check if the global object is the
@ -202,7 +211,7 @@ void FastCodeGenerator::Generate(CompilationInfo* compilation_info) {
ASSERT(info()->has_global_object()); ASSERT(info()->has_global_object());
Handle<Map> map(info()->global_object()->map()); Handle<Map> map(info()->global_object()->map());
__ ldr(scratch0(), CodeGenerator::GlobalObject()); __ ldr(scratch0(), CodeGenerator::GlobalObject());
__ CheckMap(scratch0(), scratch1(), map, bailout(), true); __ CheckMap(scratch0(), scratch1(), map, bailout_to_beginning, true);
} }
VisitStatements(function()->body()); VisitStatements(function()->body());
@ -217,8 +226,6 @@ void FastCodeGenerator::Generate(CompilationInfo* compilation_info) {
int32_t sp_delta = (scope()->num_parameters() + 1) * kPointerSize; int32_t sp_delta = (scope()->num_parameters() + 1) * kPointerSize;
__ add(sp, sp, Operand(sp_delta)); __ add(sp, sp, Operand(sp_delta));
__ Jump(lr); __ Jump(lr);
__ bind(&bailout_);
} }

11
deps/v8/src/ast.h

@ -1,4 +1,4 @@
// Copyright 2006-2008 the V8 project authors. All rights reserved. // Copyright 2010 the V8 project authors. All rights reserved.
// Redistribution and use in source and binary forms, with or without // Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are // modification, are permitted provided that the following conditions are
// met: // met:
@ -199,6 +199,10 @@ class Expression: public AstNode {
// evaluated. // evaluated.
virtual bool IsLeaf() { return false; } virtual bool IsLeaf() { return false; }
// True if the expression has no side effects and is safe to
// evaluate out of order.
virtual bool IsTrivial() { return false; }
// Mark the expression as being compiled as an expression // Mark the expression as being compiled as an expression
// statement. This is used to transform postfix increments to // statement. This is used to transform postfix increments to
// (faster) prefix increments. // (faster) prefix increments.
@ -738,6 +742,7 @@ class Literal: public Expression {
} }
virtual bool IsLeaf() { return true; } virtual bool IsLeaf() { return true; }
virtual bool IsTrivial() { return true; }
// Identity testers. // Identity testers.
bool IsNull() const { return handle_.is_identical_to(Factory::null_value()); } bool IsNull() const { return handle_.is_identical_to(Factory::null_value()); }
@ -926,6 +931,10 @@ class VariableProxy: public Expression {
return var()->is_global() || var()->rewrite()->IsLeaf(); return var()->is_global() || var()->rewrite()->IsLeaf();
} }
// Reading from a mutable variable is a side effect, but 'this' is
// immutable.
virtual bool IsTrivial() { return is_this(); }
bool IsVariable(Handle<String> n) { bool IsVariable(Handle<String> n) {
return !is_this() && name().is_identical_to(n); return !is_this() && name().is_identical_to(n);
} }

3
deps/v8/src/codegen.cc

@ -248,7 +248,7 @@ Handle<Code> CodeGenerator::MakeCode(CompilationInfo* info) {
CodeGenerator cgen(&masm); CodeGenerator cgen(&masm);
CodeGeneratorScope scope(&cgen); CodeGeneratorScope scope(&cgen);
live_edit_tracker.RecordFunctionScope(info->function()->scope()); live_edit_tracker.RecordFunctionScope(info->function()->scope());
cgen.Generate(info, PRIMARY); cgen.Generate(info);
if (cgen.HasStackOverflow()) { if (cgen.HasStackOverflow()) {
ASSERT(!Top::has_pending_exception()); ASSERT(!Top::has_pending_exception());
return Handle<Code>::null(); return Handle<Code>::null();
@ -360,6 +360,7 @@ CodeGenerator::InlineRuntimeLUT CodeGenerator::kInlineRuntimeLUT[] = {
{&CodeGenerator::GenerateIsSmi, "_IsSmi"}, {&CodeGenerator::GenerateIsSmi, "_IsSmi"},
{&CodeGenerator::GenerateIsNonNegativeSmi, "_IsNonNegativeSmi"}, {&CodeGenerator::GenerateIsNonNegativeSmi, "_IsNonNegativeSmi"},
{&CodeGenerator::GenerateIsArray, "_IsArray"}, {&CodeGenerator::GenerateIsArray, "_IsArray"},
{&CodeGenerator::GenerateIsRegExp, "_IsRegExp"},
{&CodeGenerator::GenerateIsConstructCall, "_IsConstructCall"}, {&CodeGenerator::GenerateIsConstructCall, "_IsConstructCall"},
{&CodeGenerator::GenerateArgumentsLength, "_ArgumentsLength"}, {&CodeGenerator::GenerateArgumentsLength, "_ArgumentsLength"},
{&CodeGenerator::GenerateArgumentsAccess, "_Arguments"}, {&CodeGenerator::GenerateArgumentsAccess, "_Arguments"},

6
deps/v8/src/codegen.h

@ -518,14 +518,14 @@ class CallFunctionStub: public CodeStub {
} }
#endif #endif
// Minor key encoding in 31 bits AAAAAAAAAAAAAAAAAAAAAFI A(rgs)F(lag)I(nloop). // Minor key encoding in 32 bits with Bitfield <Type, shift, size>.
class InLoopBits: public BitField<InLoopFlag, 0, 1> {}; class InLoopBits: public BitField<InLoopFlag, 0, 1> {};
class FlagBits: public BitField<CallFunctionFlags, 1, 1> {}; class FlagBits: public BitField<CallFunctionFlags, 1, 1> {};
class ArgcBits: public BitField<int, 2, 29> {}; class ArgcBits: public BitField<int, 2, 32 - 2> {};
Major MajorKey() { return CallFunction; } Major MajorKey() { return CallFunction; }
int MinorKey() { int MinorKey() {
// Encode the parameters in a unique 31 bit value. // Encode the parameters in a unique 32 bit value.
return InLoopBits::encode(in_loop_) return InLoopBits::encode(in_loop_)
| FlagBits::encode(flags_) | FlagBits::encode(flags_)
| ArgcBits::encode(argc_); | ArgcBits::encode(argc_);

53
deps/v8/src/compiler.h

@ -41,6 +41,37 @@ namespace internal {
// is constructed based on the resources available at compile-time. // is constructed based on the resources available at compile-time.
class CompilationInfo BASE_EMBEDDED { class CompilationInfo BASE_EMBEDDED {
public: public:
// Compilation mode. Either the compiler is used as the primary
// compiler and needs to setup everything or the compiler is used as
// the secondary compiler for split compilation and has to handle
// bailouts.
enum Mode {
PRIMARY,
SECONDARY
};
// A description of the compilation state at a bailout to the secondary
// code generator.
//
// The state is currently simple: there are no parameters or local
// variables to worry about ('this' can be found in the stack frame).
// There are at most two live values.
//
// There is a label that should be bound to the beginning of the bailout
// stub code.
class Bailout : public ZoneObject {
public:
Bailout(Register left, Register right) : left_(left), right_(right) {}
Label* label() { return &label_; }
private:
Register left_;
Register right_;
Label label_;
};
// Lazy compilation of a JSFunction. // Lazy compilation of a JSFunction.
CompilationInfo(Handle<JSFunction> closure, CompilationInfo(Handle<JSFunction> closure,
int loop_nesting, int loop_nesting,
@ -117,9 +148,13 @@ class CompilationInfo BASE_EMBEDDED {
int loop_nesting() { return loop_nesting_; } int loop_nesting() { return loop_nesting_; }
bool has_receiver() { return !receiver_.is_null(); } bool has_receiver() { return !receiver_.is_null(); }
Handle<Object> receiver() { return receiver_; } Handle<Object> receiver() { return receiver_; }
List<Bailout*>* bailouts() { return &bailouts_; }
// Accessors for mutable fields, possibly set by analysis passes with // Accessors for mutable fields (possibly set by analysis passes) with
// default values given by Initialize. // default values given by Initialize.
Mode mode() { return mode_; }
void set_mode(Mode mode) { mode_ = mode; }
bool has_this_properties() { return has_this_properties_; } bool has_this_properties() { return has_this_properties_; }
void set_has_this_properties(bool flag) { has_this_properties_ = flag; } void set_has_this_properties(bool flag) { has_this_properties_ = flag; }
@ -137,8 +172,19 @@ class CompilationInfo BASE_EMBEDDED {
// Derived accessors. // Derived accessors.
Scope* scope() { return function()->scope(); } Scope* scope() { return function()->scope(); }
// Add a bailout with two live values.
Label* AddBailout(Register left, Register right) {
Bailout* bailout = new Bailout(left, right);
bailouts_.Add(bailout);
return bailout->label();
}
// Add a bailout with no live values.
Label* AddBailout() { return AddBailout(no_reg, no_reg); }
private: private:
void Initialize() { void Initialize() {
mode_ = PRIMARY;
has_this_properties_ = false; has_this_properties_ = false;
has_globals_ = false; has_globals_ = false;
} }
@ -148,6 +194,7 @@ class CompilationInfo BASE_EMBEDDED {
Handle<Script> script_; Handle<Script> script_;
FunctionLiteral* function_; FunctionLiteral* function_;
Mode mode_;
bool is_eval_; bool is_eval_;
int loop_nesting_; int loop_nesting_;
@ -157,6 +204,10 @@ class CompilationInfo BASE_EMBEDDED {
bool has_this_properties_; bool has_this_properties_;
bool has_globals_; bool has_globals_;
// An ordered list of bailout points encountered during fast-path
// compilation.
List<Bailout*> bailouts_;
DISALLOW_COPY_AND_ASSIGN(CompilationInfo); DISALLOW_COPY_AND_ASSIGN(CompilationInfo);
}; };

15
deps/v8/src/debug-delay.js

@ -1202,11 +1202,16 @@ DebugCommandProcessor.prototype.processDebugJSONRequest = function(json_request)
throw new Error('Command not specified'); throw new Error('Command not specified');
} }
// TODO(yurys): remove request.arguments.compactFormat check once if (request.arguments) {
// ChromeDevTools are switched to 'inlineRefs' var args = request.arguments;
if (request.arguments && (request.arguments.inlineRefs || // TODO(yurys): remove request.arguments.compactFormat check once
request.arguments.compactFormat)) { // ChromeDevTools are switched to 'inlineRefs'
response.setOption('inlineRefs', true); if (args.inlineRefs || args.compactFormat) {
response.setOption('inlineRefs', true);
}
if (!IS_UNDEFINED(args.maxStringLength)) {
response.setOption('maxStringLength', args.maxStringLength);
}
} }
if (request.command == 'continue') { if (request.command == 'continue') {

3
deps/v8/src/fast-codegen.cc

@ -456,7 +456,8 @@ Handle<Code> FastCodeGenerator::MakeCode(CompilationInfo* info) {
// macro assembler. // macro assembler.
CodeGenerator cgen(&masm); CodeGenerator cgen(&masm);
CodeGeneratorScope scope(&cgen); CodeGeneratorScope scope(&cgen);
cgen.Generate(info, CodeGenerator::SECONDARY); info->set_mode(CompilationInfo::SECONDARY);
cgen.Generate(info);
if (cgen.HasStackOverflow()) { if (cgen.HasStackOverflow()) {
ASSERT(!Top::has_pending_exception()); ASSERT(!Top::has_pending_exception());
return Handle<Code>::null(); return Handle<Code>::null();

9
deps/v8/src/fast-codegen.h

@ -28,10 +28,15 @@
#ifndef V8_FAST_CODEGEN_H_ #ifndef V8_FAST_CODEGEN_H_
#define V8_FAST_CODEGEN_H_ #define V8_FAST_CODEGEN_H_
#if V8_TARGET_ARCH_IA32
#include "ia32/fast-codegen-ia32.h"
#else
#include "v8.h" #include "v8.h"
#include "ast.h" #include "ast.h"
#include "compiler.h" #include "compiler.h"
#include "list.h"
namespace v8 { namespace v8 {
namespace internal { namespace internal {
@ -76,7 +81,6 @@ class FastCodeGenerator: public AstVisitor {
private: private:
MacroAssembler* masm() { return masm_; } MacroAssembler* masm() { return masm_; }
CompilationInfo* info() { return info_; } CompilationInfo* info() { return info_; }
Label* bailout() { return &bailout_; }
Register destination() { return destination_; } Register destination() { return destination_; }
void set_destination(Register reg) { destination_ = reg; } void set_destination(Register reg) { destination_ = reg; }
@ -142,7 +146,6 @@ class FastCodeGenerator: public AstVisitor {
MacroAssembler* masm_; MacroAssembler* masm_;
CompilationInfo* info_; CompilationInfo* info_;
Label bailout_;
Register destination_; Register destination_;
uint32_t smi_bits_; uint32_t smi_bits_;
@ -152,4 +155,6 @@ class FastCodeGenerator: public AstVisitor {
} } // namespace v8::internal } } // namespace v8::internal
#endif // V8_TARGET_ARCH_IA32
#endif // V8_FAST_CODEGEN_H_ #endif // V8_FAST_CODEGEN_H_

5
deps/v8/src/frame-element.h

@ -65,6 +65,9 @@ class FrameElement BASE_EMBEDDED {
} }
inline void set_number_info(NumberInfo::Type info) { inline void set_number_info(NumberInfo::Type info) {
// Copied elements do not have number info. Instead
// we have to inspect their backing element in the frame.
ASSERT(!is_copy());
value_ = value_ & ~NumberInfoField::mask(); value_ = value_ & ~NumberInfoField::mask();
value_ = value_ | NumberInfoField::encode(info); value_ = value_ | NumberInfoField::encode(info);
} }
@ -250,7 +253,7 @@ class FrameElement BASE_EMBEDDED {
class CopiedField: public BitField<bool, 3, 1> {}; class CopiedField: public BitField<bool, 3, 1> {};
class SyncedField: public BitField<bool, 4, 1> {}; class SyncedField: public BitField<bool, 4, 1> {};
class NumberInfoField: public BitField<NumberInfo::Type, 5, 3> {}; class NumberInfoField: public BitField<NumberInfo::Type, 5, 3> {};
class DataField: public BitField<uint32_t, 8, 32 - 9> {}; class DataField: public BitField<uint32_t, 8, 32 - 8> {};
friend class VirtualFrame; friend class VirtualFrame;
}; };

2
deps/v8/src/heap.cc

@ -4111,7 +4111,7 @@ int KeyedLookupCache::Hash(Map* map, String* name) {
// Uses only lower 32 bits if pointers are larger. // Uses only lower 32 bits if pointers are larger.
uintptr_t addr_hash = uintptr_t addr_hash =
static_cast<uint32_t>(reinterpret_cast<uintptr_t>(map)) >> kMapHashShift; static_cast<uint32_t>(reinterpret_cast<uintptr_t>(map)) >> kMapHashShift;
return (addr_hash ^ name->Hash()) & kCapacityMask; return static_cast<uint32_t>((addr_hash ^ name->Hash()) & kCapacityMask);
} }

4
deps/v8/src/heap.h

@ -1383,9 +1383,9 @@ class DescriptorLookupCache {
private: private:
static int Hash(DescriptorArray* array, String* name) { static int Hash(DescriptorArray* array, String* name) {
// Uses only lower 32 bits if pointers are larger. // Uses only lower 32 bits if pointers are larger.
uintptr_t array_hash = uint32_t array_hash =
static_cast<uint32_t>(reinterpret_cast<uintptr_t>(array)) >> 2; static_cast<uint32_t>(reinterpret_cast<uintptr_t>(array)) >> 2;
uintptr_t name_hash = uint32_t name_hash =
static_cast<uint32_t>(reinterpret_cast<uintptr_t>(name)) >> 2; static_cast<uint32_t>(reinterpret_cast<uintptr_t>(name)) >> 2;
return (array_hash ^ name_hash) % kLength; return (array_hash ^ name_hash) % kLength;
} }

123
deps/v8/src/ia32/codegen-ia32.cc

@ -125,7 +125,7 @@ Scope* CodeGenerator::scope() { return info_->function()->scope(); }
// edi: called JS function // edi: called JS function
// esi: callee's context // esi: callee's context
void CodeGenerator::Generate(CompilationInfo* info, Mode mode) { void CodeGenerator::Generate(CompilationInfo* info) {
// Record the position for debugging purposes. // Record the position for debugging purposes.
CodeForFunctionPosition(info->function()); CodeForFunctionPosition(info->function());
@ -164,7 +164,7 @@ void CodeGenerator::Generate(CompilationInfo* info, Mode mode) {
// esi: callee's context // esi: callee's context
allocator_->Initialize(); allocator_->Initialize();
if (mode == PRIMARY) { if (info->mode() == CompilationInfo::PRIMARY) {
frame_->Enter(); frame_->Enter();
// Allocate space for locals and initialize them. // Allocate space for locals and initialize them.
@ -255,6 +255,12 @@ void CodeGenerator::Generate(CompilationInfo* info, Mode mode) {
// frame to match this state. // frame to match this state.
frame_->Adjust(3); frame_->Adjust(3);
allocator_->Unuse(edi); allocator_->Unuse(edi);
// Bind all the bailout labels to the beginning of the function.
List<CompilationInfo::Bailout*>* bailouts = info->bailouts();
for (int i = 0; i < bailouts->length(); i++) {
__ bind(bailouts->at(i)->label());
}
} }
// Initialize the function return target after the locals are set // Initialize the function return target after the locals are set
@ -689,6 +695,11 @@ void CodeGenerator::LoadReference(Reference* ref) {
// The expression is a variable proxy that does not rewrite to a // The expression is a variable proxy that does not rewrite to a
// property. Global variables are treated as named property references. // property. Global variables are treated as named property references.
if (var->is_global()) { if (var->is_global()) {
// If eax is free, the register allocator prefers it. Thus the code
// generator will load the global object into eax, which is where
// LoadIC wants it. Most uses of Reference call LoadIC directly
// after the reference is created.
frame_->Spill(eax);
LoadGlobal(); LoadGlobal();
ref->set_type(Reference::NAMED); ref->set_type(Reference::NAMED);
} else { } else {
@ -4307,6 +4318,10 @@ Result CodeGenerator::LoadFromGlobalSlotCheckExtensions(
// All extension objects were empty and it is safe to use a global // All extension objects were empty and it is safe to use a global
// load IC call. // load IC call.
// The register allocator prefers eax if it is free, so the code generator
// will load the global object directly into eax, which is where the LoadIC
// expects it.
frame_->Spill(eax);
LoadGlobal(); LoadGlobal();
frame_->Push(slot->var()->name()); frame_->Push(slot->var()->name());
RelocInfo::Mode mode = (typeof_state == INSIDE_TYPEOF) RelocInfo::Mode mode = (typeof_state == INSIDE_TYPEOF)
@ -4592,8 +4607,8 @@ void CodeGenerator::VisitObjectLiteral(ObjectLiteral* node) {
// Duplicate the object as the IC receiver. // Duplicate the object as the IC receiver.
frame_->Dup(); frame_->Dup();
Load(property->value()); Load(property->value());
frame_->Push(key); Result dummy = frame_->CallStoreIC(Handle<String>::cast(key), false);
Result ignored = frame_->CallStoreIC(); dummy.Unuse();
break; break;
} }
// Fall through // Fall through
@ -4762,26 +4777,33 @@ void CodeGenerator::EmitNamedPropertyAssignment(Assignment* node) {
Property* prop = node->target()->AsProperty(); Property* prop = node->target()->AsProperty();
ASSERT(var == NULL || (prop == NULL && var->is_global())); ASSERT(var == NULL || (prop == NULL && var->is_global()));
// Initialize name and evaluate the receiver subexpression. // Initialize name and evaluate the receiver subexpression if necessary.
Handle<String> name; Handle<String> name;
bool is_trivial_receiver = false;
if (var != NULL) { if (var != NULL) {
name = var->name(); name = var->name();
LoadGlobal();
} else { } else {
Literal* lit = prop->key()->AsLiteral(); Literal* lit = prop->key()->AsLiteral();
ASSERT(lit != NULL); ASSERT_NOT_NULL(lit);
name = Handle<String>::cast(lit->handle()); name = Handle<String>::cast(lit->handle());
Load(prop->obj()); // Do not materialize the receiver on the frame if it is trivial.
is_trivial_receiver = prop->obj()->IsTrivial();
if (!is_trivial_receiver) Load(prop->obj());
} }
if (node->starts_initialization_block()) { if (node->starts_initialization_block()) {
ASSERT_EQ(NULL, var);
// Change to slow case in the beginning of an initialization block to // Change to slow case in the beginning of an initialization block to
// avoid the quadratic behavior of repeatedly adding fast properties. // avoid the quadratic behavior of repeatedly adding fast properties.
frame()->Dup(); if (is_trivial_receiver) {
frame()->Push(prop->obj());
} else {
frame()->Dup();
}
Result ignored = frame()->CallRuntime(Runtime::kToSlowProperties, 1); Result ignored = frame()->CallRuntime(Runtime::kToSlowProperties, 1);
} }
if (node->ends_initialization_block()) { if (node->ends_initialization_block() && !is_trivial_receiver) {
// Add an extra copy of the receiver to the frame, so that it can be // Add an extra copy of the receiver to the frame, so that it can be
// converted back to fast case after the assignment. // converted back to fast case after the assignment.
frame()->Dup(); frame()->Dup();
@ -4789,7 +4811,16 @@ void CodeGenerator::EmitNamedPropertyAssignment(Assignment* node) {
// Evaluate the right-hand side. // Evaluate the right-hand side.
if (node->is_compound()) { if (node->is_compound()) {
frame()->Dup(); if (is_trivial_receiver) {
frame()->Push(prop->obj());
} else if (var != NULL) {
// The LoadIC stub expects the object in eax.
// Freeing eax causes the code generator to load the global into it.
frame_->Spill(eax);
LoadGlobal();
} else {
frame()->Dup();
}
Result value = EmitNamedLoad(name, var != NULL); Result value = EmitNamedLoad(name, var != NULL);
frame()->Push(&value); frame()->Push(&value);
Load(node->value()); Load(node->value());
@ -4806,23 +4837,34 @@ void CodeGenerator::EmitNamedPropertyAssignment(Assignment* node) {
// Perform the assignment. It is safe to ignore constants here. // Perform the assignment. It is safe to ignore constants here.
ASSERT(var == NULL || var->mode() != Variable::CONST); ASSERT(var == NULL || var->mode() != Variable::CONST);
ASSERT(node->op() != Token::INIT_CONST); ASSERT_NE(Token::INIT_CONST, node->op());
if (is_trivial_receiver) {
Result value = frame()->Pop();
frame()->Push(prop->obj());
frame()->Push(&value);
}
CodeForSourcePosition(node->position()); CodeForSourcePosition(node->position());
Result answer = EmitNamedStore(name); bool is_contextual = (var != NULL);
Result answer = EmitNamedStore(name, is_contextual);
frame()->Push(&answer); frame()->Push(&answer);
if (node->ends_initialization_block()) { if (node->ends_initialization_block()) {
// The argument to the runtime call is the extra copy of the receiver, ASSERT_EQ(NULL, var);
// which is below the value of the assignment. Swap the receiver and // The argument to the runtime call is the receiver.
// the value of the assignment expression. if (is_trivial_receiver) {
Result result = frame()->Pop(); frame()->Push(prop->obj());
Result receiver = frame()->Pop(); } else {
frame()->Push(&result); // A copy of the receiver is below the value of the assignment. Swap
frame()->Push(&receiver); // the receiver and the value of the assignment expression.
Result result = frame()->Pop();
Result receiver = frame()->Pop();
frame()->Push(&result);
frame()->Push(&receiver);
}
Result ignored = frame_->CallRuntime(Runtime::kToFastProperties, 1); Result ignored = frame_->CallRuntime(Runtime::kToFastProperties, 1);
} }
ASSERT(frame()->height() == original_height + 1); ASSERT_EQ(frame()->height(), original_height + 1);
} }
@ -4832,7 +4874,7 @@ void CodeGenerator::EmitKeyedPropertyAssignment(Assignment* node) {
#endif #endif
Comment cmnt(masm_, "[ Named Property Assignment"); Comment cmnt(masm_, "[ Named Property Assignment");
Property* prop = node->target()->AsProperty(); Property* prop = node->target()->AsProperty();
ASSERT(prop != NULL); ASSERT_NOT_NULL(prop);
// Evaluate the receiver subexpression. // Evaluate the receiver subexpression.
Load(prop->obj()); Load(prop->obj());
@ -5399,6 +5441,25 @@ void CodeGenerator::GenerateIsArray(ZoneList<Expression*>* args) {
} }
void CodeGenerator::GenerateIsRegExp(ZoneList<Expression*>* args) {
ASSERT(args->length() == 1);
Load(args->at(0));
Result value = frame_->Pop();
value.ToRegister();
ASSERT(value.is_valid());
__ test(value.reg(), Immediate(kSmiTagMask));
destination()->false_target()->Branch(equal);
// It is a heap object - get map.
Result temp = allocator()->Allocate();
ASSERT(temp.is_valid());
// Check if the object is a regexp.
__ CmpObjectType(value.reg(), JS_REGEXP_TYPE, temp.reg());
value.Unuse();
temp.Unuse();
destination()->Split(equal);
}
void CodeGenerator::GenerateIsObject(ZoneList<Expression*>* args) { void CodeGenerator::GenerateIsObject(ZoneList<Expression*>* args) {
// This generates a fast version of: // This generates a fast version of:
// (typeof(arg) === 'object' || %_ClassOf(arg) == 'RegExp') // (typeof(arg) === 'object' || %_ClassOf(arg) == 'RegExp')
@ -6347,13 +6408,10 @@ void CodeGenerator::VisitCompareOperation(CompareOperation* node) {
__ movzx_b(temp.reg(), FieldOperand(temp.reg(), Map::kBitFieldOffset)); __ movzx_b(temp.reg(), FieldOperand(temp.reg(), Map::kBitFieldOffset));
__ test(temp.reg(), Immediate(1 << Map::kIsUndetectable)); __ test(temp.reg(), Immediate(1 << Map::kIsUndetectable));
destination()->false_target()->Branch(not_zero); destination()->false_target()->Branch(not_zero);
__ mov(temp.reg(), FieldOperand(answer.reg(), HeapObject::kMapOffset)); __ CmpObjectType(answer.reg(), FIRST_NONSTRING_TYPE, temp.reg());
__ movzx_b(temp.reg(),
FieldOperand(temp.reg(), Map::kInstanceTypeOffset));
__ cmp(temp.reg(), FIRST_NONSTRING_TYPE);
temp.Unuse(); temp.Unuse();
answer.Unuse(); answer.Unuse();
destination()->Split(less); destination()->Split(below);
} else if (check->Equals(Heap::boolean_symbol())) { } else if (check->Equals(Heap::boolean_symbol())) {
__ cmp(answer.reg(), Factory::true_value()); __ cmp(answer.reg(), Factory::true_value());
@ -6734,14 +6792,13 @@ Result CodeGenerator::EmitNamedLoad(Handle<String> name, bool is_contextual) {
} }
Result CodeGenerator::EmitNamedStore(Handle<String> name) { Result CodeGenerator::EmitNamedStore(Handle<String> name, bool is_contextual) {
#ifdef DEBUG #ifdef DEBUG
int original_height = frame()->height(); int expected_height = frame()->height() - (is_contextual ? 1 : 2);
#endif #endif
frame()->Push(name); Result result = frame()->CallStoreIC(name, is_contextual);
Result result = frame()->CallStoreIC();
ASSERT(frame()->height() == original_height - 2); ASSERT_EQ(expected_height, frame()->height());
return result; return result;
} }
@ -7058,7 +7115,7 @@ void Reference::SetValue(InitState init_state) {
case NAMED: { case NAMED: {
Comment cmnt(masm, "[ Store to named Property"); Comment cmnt(masm, "[ Store to named Property");
Result answer = cgen_->EmitNamedStore(GetName()); Result answer = cgen_->EmitNamedStore(GetName(), false);
cgen_->frame()->Push(&answer); cgen_->frame()->Push(&answer);
set_unloaded(); set_unloaded();
break; break;

17
deps/v8/src/ia32/codegen-ia32.h

@ -294,15 +294,6 @@ enum ArgumentsAllocationMode {
class CodeGenerator: public AstVisitor { class CodeGenerator: public AstVisitor {
public: public:
// Compilation mode. Either the compiler is used as the primary
// compiler and needs to setup everything or the compiler is used as
// the secondary compiler for split compilation and has to handle
// bailouts.
enum Mode {
PRIMARY,
SECONDARY
};
// Takes a function literal, generates code for it. This function should only // Takes a function literal, generates code for it. This function should only
// be called by compiler.cc. // be called by compiler.cc.
static Handle<Code> MakeCode(CompilationInfo* info); static Handle<Code> MakeCode(CompilationInfo* info);
@ -384,7 +375,7 @@ class CodeGenerator: public AstVisitor {
void VisitStatementsAndSpill(ZoneList<Statement*>* statements); void VisitStatementsAndSpill(ZoneList<Statement*>* statements);
// Main code generation function // Main code generation function
void Generate(CompilationInfo* info, Mode mode); void Generate(CompilationInfo* info);
// Generate the return sequence code. Should be called no more than // Generate the return sequence code. Should be called no more than
// once per compiled function, immediately after binding the return // once per compiled function, immediately after binding the return
@ -447,8 +438,9 @@ class CodeGenerator: public AstVisitor {
// Receiver is passed on the frame and consumed. // Receiver is passed on the frame and consumed.
Result EmitNamedLoad(Handle<String> name, bool is_contextual); Result EmitNamedLoad(Handle<String> name, bool is_contextual);
// Reciever and value are passed on the frame and consumed. // If the store is contextual, value is passed on the frame and consumed.
Result EmitNamedStore(Handle<String> name); // Otherwise, receiver and value are passed on the frame and consumed.
Result EmitNamedStore(Handle<String> name, bool is_contextual);
// Receiver and key are passed on the frame and consumed. // Receiver and key are passed on the frame and consumed.
Result EmitKeyedLoad(); Result EmitKeyedLoad();
@ -551,6 +543,7 @@ class CodeGenerator: public AstVisitor {
void GenerateIsSmi(ZoneList<Expression*>* args); void GenerateIsSmi(ZoneList<Expression*>* args);
void GenerateIsNonNegativeSmi(ZoneList<Expression*>* args); void GenerateIsNonNegativeSmi(ZoneList<Expression*>* args);
void GenerateIsArray(ZoneList<Expression*>* args); void GenerateIsArray(ZoneList<Expression*>* args);
void GenerateIsRegExp(ZoneList<Expression*>* args);
void GenerateIsObject(ZoneList<Expression*>* args); void GenerateIsObject(ZoneList<Expression*>* args);
void GenerateIsFunction(ZoneList<Expression*>* args); void GenerateIsFunction(ZoneList<Expression*>* args);
void GenerateIsUndetectableObject(ZoneList<Expression*>* args); void GenerateIsUndetectableObject(ZoneList<Expression*>* args);

748
deps/v8/src/ia32/fast-codegen-ia32.cc

@ -29,12 +29,445 @@
#include "codegen-inl.h" #include "codegen-inl.h"
#include "fast-codegen.h" #include "fast-codegen.h"
#include "data-flow.h"
#include "scopes.h"
namespace v8 { namespace v8 {
namespace internal { namespace internal {
#define BAILOUT(reason) \
do { \
if (FLAG_trace_bailout) { \
PrintF("%s\n", reason); \
} \
has_supported_syntax_ = false; \
return; \
} while (false)
#define CHECK_BAILOUT \
do { \
if (!has_supported_syntax_) return; \
} while (false)
void FastCodeGenSyntaxChecker::Check(CompilationInfo* info) {
info_ = info;
// We do not specialize if we do not have a receiver or if it is not a
// JS object with fast mode properties.
if (!info->has_receiver()) BAILOUT("No receiver");
if (!info->receiver()->IsJSObject()) BAILOUT("Receiver is not an object");
Handle<JSObject> object = Handle<JSObject>::cast(info->receiver());
if (!object->HasFastProperties()) BAILOUT("Receiver is in dictionary mode");
// We do not support stack or heap slots (both of which require
// allocation).
Scope* scope = info->scope();
if (scope->num_stack_slots() > 0) {
BAILOUT("Function has stack-allocated locals");
}
if (scope->num_heap_slots() > 0) {
BAILOUT("Function has context-allocated locals");
}
VisitDeclarations(scope->declarations());
CHECK_BAILOUT;
// We do not support empty function bodies.
if (info->function()->body()->is_empty()) {
BAILOUT("Function has an empty body");
}
VisitStatements(info->function()->body());
}
void FastCodeGenSyntaxChecker::VisitDeclarations(
ZoneList<Declaration*>* decls) {
if (!decls->is_empty()) BAILOUT("Function has declarations");
}
void FastCodeGenSyntaxChecker::VisitStatements(ZoneList<Statement*>* stmts) {
if (stmts->length() != 1) {
BAILOUT("Function body is not a singleton statement.");
}
Visit(stmts->at(0));
}
void FastCodeGenSyntaxChecker::VisitDeclaration(Declaration* decl) {
UNREACHABLE();
}
void FastCodeGenSyntaxChecker::VisitBlock(Block* stmt) {
VisitStatements(stmt->statements());
}
void FastCodeGenSyntaxChecker::VisitExpressionStatement(
ExpressionStatement* stmt) {
Visit(stmt->expression());
}
void FastCodeGenSyntaxChecker::VisitEmptyStatement(EmptyStatement* stmt) {
// Supported.
}
void FastCodeGenSyntaxChecker::VisitIfStatement(IfStatement* stmt) {
BAILOUT("IfStatement");
}
void FastCodeGenSyntaxChecker::VisitContinueStatement(ContinueStatement* stmt) {
BAILOUT("Continuestatement");
}
void FastCodeGenSyntaxChecker::VisitBreakStatement(BreakStatement* stmt) {
BAILOUT("BreakStatement");
}
void FastCodeGenSyntaxChecker::VisitReturnStatement(ReturnStatement* stmt) {
BAILOUT("ReturnStatement");
}
void FastCodeGenSyntaxChecker::VisitWithEnterStatement(
WithEnterStatement* stmt) {
BAILOUT("WithEnterStatement");
}
void FastCodeGenSyntaxChecker::VisitWithExitStatement(WithExitStatement* stmt) {
BAILOUT("WithExitStatement");
}
void FastCodeGenSyntaxChecker::VisitSwitchStatement(SwitchStatement* stmt) {
BAILOUT("SwitchStatement");
}
void FastCodeGenSyntaxChecker::VisitDoWhileStatement(DoWhileStatement* stmt) {
BAILOUT("DoWhileStatement");
}
void FastCodeGenSyntaxChecker::VisitWhileStatement(WhileStatement* stmt) {
BAILOUT("WhileStatement");
}
void FastCodeGenSyntaxChecker::VisitForStatement(ForStatement* stmt) {
BAILOUT("ForStatement");
}
void FastCodeGenSyntaxChecker::VisitForInStatement(ForInStatement* stmt) {
BAILOUT("ForInStatement");
}
void FastCodeGenSyntaxChecker::VisitTryCatchStatement(TryCatchStatement* stmt) {
BAILOUT("TryCatchStatement");
}
void FastCodeGenSyntaxChecker::VisitTryFinallyStatement(
TryFinallyStatement* stmt) {
BAILOUT("TryFinallyStatement");
}
void FastCodeGenSyntaxChecker::VisitDebuggerStatement(
DebuggerStatement* stmt) {
BAILOUT("DebuggerStatement");
}
void FastCodeGenSyntaxChecker::VisitFunctionLiteral(FunctionLiteral* expr) {
BAILOUT("FunctionLiteral");
}
void FastCodeGenSyntaxChecker::VisitFunctionBoilerplateLiteral(
FunctionBoilerplateLiteral* expr) {
BAILOUT("FunctionBoilerplateLiteral");
}
void FastCodeGenSyntaxChecker::VisitConditional(Conditional* expr) {
BAILOUT("Conditional");
}
void FastCodeGenSyntaxChecker::VisitSlot(Slot* expr) {
UNREACHABLE();
}
void FastCodeGenSyntaxChecker::VisitVariableProxy(VariableProxy* expr) {
// Only global variable references are supported.
Variable* var = expr->var();
if (!var->is_global() || var->is_this()) BAILOUT("Non-global variable");
// Check if the global variable is existing and non-deletable.
if (info()->has_global_object()) {
LookupResult lookup;
info()->global_object()->Lookup(*expr->name(), &lookup);
if (!lookup.IsProperty()) {
BAILOUT("Non-existing global variable");
}
// We do not handle global variables with accessors or interceptors.
if (lookup.type() != NORMAL) {
BAILOUT("Global variable with accessors or interceptors.");
}
// We do not handle deletable global variables.
if (!lookup.IsDontDelete()) {
BAILOUT("Deletable global variable");
}
}
}
void FastCodeGenSyntaxChecker::VisitLiteral(Literal* expr) {
BAILOUT("Literal");
}
void FastCodeGenSyntaxChecker::VisitRegExpLiteral(RegExpLiteral* expr) {
BAILOUT("RegExpLiteral");
}
void FastCodeGenSyntaxChecker::VisitObjectLiteral(ObjectLiteral* expr) {
BAILOUT("ObjectLiteral");
}
void FastCodeGenSyntaxChecker::VisitArrayLiteral(ArrayLiteral* expr) {
BAILOUT("ArrayLiteral");
}
void FastCodeGenSyntaxChecker::VisitCatchExtensionObject(
CatchExtensionObject* expr) {
BAILOUT("CatchExtensionObject");
}
void FastCodeGenSyntaxChecker::VisitAssignment(Assignment* expr) {
// Simple assignments to (named) this properties are supported.
if (expr->op() != Token::ASSIGN) BAILOUT("Non-simple assignment");
Property* prop = expr->target()->AsProperty();
if (prop == NULL) BAILOUT("Non-property assignment");
VariableProxy* proxy = prop->obj()->AsVariableProxy();
if (proxy == NULL || !proxy->var()->is_this()) {
BAILOUT("Non-this-property assignment");
}
if (!prop->key()->IsPropertyName()) {
BAILOUT("Non-named-property assignment");
}
// We will only specialize for fields on the object itself.
// Expression::IsPropertyName implies that the name is a literal
// symbol but we do not assume that.
Literal* key = prop->key()->AsLiteral();
if (key != NULL && key->handle()->IsString()) {
Handle<Object> receiver = info()->receiver();
Handle<String> name = Handle<String>::cast(key->handle());
LookupResult lookup;
receiver->Lookup(*name, &lookup);
if (!lookup.IsProperty()) {
BAILOUT("Assigned property not found at compile time");
}
if (lookup.holder() != *receiver) BAILOUT("Non-own property assignment");
if (!lookup.type() == FIELD) BAILOUT("Non-field property assignment");
} else {
UNREACHABLE();
BAILOUT("Unexpected non-string-literal property key");
}
Visit(expr->value());
}
void FastCodeGenSyntaxChecker::VisitThrow(Throw* expr) {
BAILOUT("Throw");
}
void FastCodeGenSyntaxChecker::VisitProperty(Property* expr) {
// We support named this property references.
VariableProxy* proxy = expr->obj()->AsVariableProxy();
if (proxy == NULL || !proxy->var()->is_this()) {
BAILOUT("Non-this-property reference");
}
if (!expr->key()->IsPropertyName()) {
BAILOUT("Non-named-property reference");
}
// We will only specialize for fields on the object itself.
// Expression::IsPropertyName implies that the name is a literal
// symbol but we do not assume that.
Literal* key = expr->key()->AsLiteral();
if (key != NULL && key->handle()->IsString()) {
Handle<Object> receiver = info()->receiver();
Handle<String> name = Handle<String>::cast(key->handle());
LookupResult lookup;
receiver->Lookup(*name, &lookup);
if (!lookup.IsProperty()) {
BAILOUT("Referenced property not found at compile time");
}
if (lookup.holder() != *receiver) BAILOUT("Non-own property reference");
if (!lookup.type() == FIELD) BAILOUT("Non-field property reference");
} else {
UNREACHABLE();
BAILOUT("Unexpected non-string-literal property key");
}
}
void FastCodeGenSyntaxChecker::VisitCall(Call* expr) {
BAILOUT("Call");
}
void FastCodeGenSyntaxChecker::VisitCallNew(CallNew* expr) {
BAILOUT("CallNew");
}
void FastCodeGenSyntaxChecker::VisitCallRuntime(CallRuntime* expr) {
BAILOUT("CallRuntime");
}
void FastCodeGenSyntaxChecker::VisitUnaryOperation(UnaryOperation* expr) {
BAILOUT("UnaryOperation");
}
void FastCodeGenSyntaxChecker::VisitCountOperation(CountOperation* expr) {
BAILOUT("CountOperation");
}
void FastCodeGenSyntaxChecker::VisitBinaryOperation(BinaryOperation* expr) {
// We support bitwise OR.
switch (expr->op()) {
case Token::COMMA:
BAILOUT("BinaryOperation COMMA");
case Token::OR:
BAILOUT("BinaryOperation OR");
case Token::AND:
BAILOUT("BinaryOperation AND");
case Token::BIT_OR:
// We support expressions nested on the left because they only require
// a pair of registers to keep all intermediate values in registers
// (i.e., the expression stack has height no more than two).
if (!expr->right()->IsLeaf()) BAILOUT("expression nested on right");
// We do not allow subexpressions with side effects because we
// (currently) bail out to the beginning of the full function. The
// only expressions with side effects that we would otherwise handle
// are assignments.
if (expr->left()->AsAssignment() != NULL ||
expr->right()->AsAssignment() != NULL) {
BAILOUT("subexpression of binary operation has side effects");
}
Visit(expr->left());
CHECK_BAILOUT;
Visit(expr->right());
break;
case Token::BIT_XOR:
BAILOUT("BinaryOperation BIT_XOR");
case Token::BIT_AND:
BAILOUT("BinaryOperation BIT_AND");
case Token::SHL:
BAILOUT("BinaryOperation SHL");
case Token::SAR:
BAILOUT("BinaryOperation SAR");
case Token::SHR:
BAILOUT("BinaryOperation SHR");
case Token::ADD:
BAILOUT("BinaryOperation ADD");
case Token::SUB:
BAILOUT("BinaryOperation SUB");
case Token::MUL:
BAILOUT("BinaryOperation MUL");
case Token::DIV:
BAILOUT("BinaryOperation DIV");
case Token::MOD:
BAILOUT("BinaryOperation MOD");
default:
UNREACHABLE();
}
}
void FastCodeGenSyntaxChecker::VisitCompareOperation(CompareOperation* expr) {
BAILOUT("CompareOperation");
}
void FastCodeGenSyntaxChecker::VisitThisFunction(ThisFunction* expr) {
BAILOUT("ThisFunction");
}
#undef BAILOUT
#undef CHECK_BAILOUT
#define __ ACCESS_MASM(masm()) #define __ ACCESS_MASM(masm())
Handle<Code> FastCodeGenerator::MakeCode(CompilationInfo* info) {
// Label the AST before calling MakeCodePrologue, so AST node numbers are
// printed with the AST.
AstLabeler labeler;
labeler.Label(info);
LivenessAnalyzer analyzer;
analyzer.Analyze(info->function());
CodeGenerator::MakeCodePrologue(info);
const int kInitialBufferSize = 4 * KB;
MacroAssembler masm(NULL, kInitialBufferSize);
// Generate the fast-path code.
FastCodeGenerator fast_cgen(&masm);
fast_cgen.Generate(info);
if (fast_cgen.HasStackOverflow()) {
ASSERT(!Top::has_pending_exception());
return Handle<Code>::null();
}
// Generate the full code for the function in bailout mode, using the same
// macro assembler.
CodeGenerator cgen(&masm);
CodeGeneratorScope scope(&cgen);
info->set_mode(CompilationInfo::SECONDARY);
cgen.Generate(info);
if (cgen.HasStackOverflow()) {
ASSERT(!Top::has_pending_exception());
return Handle<Code>::null();
}
Code::Flags flags = Code::ComputeFlags(Code::FUNCTION, NOT_IN_LOOP);
return CodeGenerator::MakeCodeEpilogue(&masm, flags, info);
}
Register FastCodeGenerator::accumulator0() { return eax; } Register FastCodeGenerator::accumulator0() { return eax; }
Register FastCodeGenerator::accumulator1() { return edx; } Register FastCodeGenerator::accumulator1() { return edx; }
Register FastCodeGenerator::scratch0() { return ecx; } Register FastCodeGenerator::scratch0() { return ecx; }
@ -155,20 +588,27 @@ void FastCodeGenerator::EmitBitOr() {
// commutative. // commutative.
__ or_(destination(), Operand(other_accumulator(destination()))); __ or_(destination(), Operand(other_accumulator(destination())));
} }
} else if (destination().is(no_reg)) {
// Result is not needed but do not clobber the operands in case of
// bailout.
__ mov(scratch0(), accumulator1());
__ or_(scratch0(), Operand(accumulator0()));
__ test(scratch0(), Immediate(kSmiTagMask));
__ j(not_zero, bailout(), not_taken);
} else { } else {
// Preserve the destination operand in a scratch register in case of // Left is in accumulator1, right in accumulator0.
// bailout. Label* bailout = NULL;
__ mov(scratch0(), destination()); if (destination().is(accumulator0())) {
__ or_(destination(), Operand(other_accumulator(destination()))); __ mov(scratch0(), accumulator0());
__ test(destination(), Immediate(kSmiTagMask)); __ or_(destination(), Operand(accumulator1())); // Or is commutative.
__ j(not_zero, bailout(), not_taken); __ test(destination(), Immediate(kSmiTagMask));
bailout = info()->AddBailout(accumulator1(), scratch0()); // Left, right.
} else if (destination().is(accumulator1())) {
__ mov(scratch0(), accumulator1());
__ or_(destination(), Operand(accumulator0()));
__ test(destination(), Immediate(kSmiTagMask));
bailout = info()->AddBailout(scratch0(), accumulator0());
} else {
ASSERT(destination().is(no_reg));
__ mov(scratch0(), accumulator1());
__ or_(scratch0(), Operand(accumulator0()));
__ test(scratch0(), Immediate(kSmiTagMask));
bailout = info()->AddBailout(accumulator1(), accumulator0());
}
__ j(not_zero, bailout, not_taken);
} }
// If we didn't bailout, the result (in fact, both inputs too) is known to // If we didn't bailout, the result (in fact, both inputs too) is known to
@ -191,6 +631,7 @@ void FastCodeGenerator::Generate(CompilationInfo* compilation_info) {
// Note that we keep a live register reference to esi (context) at this // Note that we keep a live register reference to esi (context) at this
// point. // point.
Label* bailout_to_beginning = info()->AddBailout();
// Receiver (this) is allocated to a fixed register. // Receiver (this) is allocated to a fixed register.
if (info()->has_this_properties()) { if (info()->has_this_properties()) {
Comment cmnt(masm(), ";; MapCheck(this)"); Comment cmnt(masm(), ";; MapCheck(this)");
@ -201,7 +642,7 @@ void FastCodeGenerator::Generate(CompilationInfo* compilation_info) {
Handle<HeapObject> object = Handle<HeapObject>::cast(info()->receiver()); Handle<HeapObject> object = Handle<HeapObject>::cast(info()->receiver());
Handle<Map> map(object->map()); Handle<Map> map(object->map());
EmitLoadReceiver(); EmitLoadReceiver();
__ CheckMap(receiver_reg(), map, bailout(), false); __ CheckMap(receiver_reg(), map, bailout_to_beginning, false);
} }
// If there is a global variable access check if the global object is the // If there is a global variable access check if the global object is the
@ -214,7 +655,7 @@ void FastCodeGenerator::Generate(CompilationInfo* compilation_info) {
ASSERT(info()->has_global_object()); ASSERT(info()->has_global_object());
Handle<Map> map(info()->global_object()->map()); Handle<Map> map(info()->global_object()->map());
__ mov(scratch0(), CodeGenerator::GlobalObject()); __ mov(scratch0(), CodeGenerator::GlobalObject());
__ CheckMap(scratch0(), map, bailout(), true); __ CheckMap(scratch0(), map, bailout_to_beginning, true);
} }
VisitStatements(function()->body()); VisitStatements(function()->body());
@ -227,11 +668,286 @@ void FastCodeGenerator::Generate(CompilationInfo* compilation_info) {
__ mov(esp, ebp); __ mov(esp, ebp);
__ pop(ebp); __ pop(ebp);
__ ret((scope()->num_parameters() + 1) * kPointerSize); __ ret((scope()->num_parameters() + 1) * kPointerSize);
}
void FastCodeGenerator::VisitDeclaration(Declaration* decl) {
UNREACHABLE();
}
void FastCodeGenerator::VisitBlock(Block* stmt) {
VisitStatements(stmt->statements());
}
void FastCodeGenerator::VisitExpressionStatement(ExpressionStatement* stmt) {
Visit(stmt->expression());
}
void FastCodeGenerator::VisitEmptyStatement(EmptyStatement* stmt) {
// Nothing to do.
}
void FastCodeGenerator::VisitIfStatement(IfStatement* stmt) {
UNREACHABLE();
}
void FastCodeGenerator::VisitContinueStatement(ContinueStatement* stmt) {
UNREACHABLE();
}
void FastCodeGenerator::VisitBreakStatement(BreakStatement* stmt) {
UNREACHABLE();
}
void FastCodeGenerator::VisitReturnStatement(ReturnStatement* stmt) {
UNREACHABLE();
}
void FastCodeGenerator::VisitWithEnterStatement(WithEnterStatement* stmt) {
UNREACHABLE();
}
void FastCodeGenerator::VisitWithExitStatement(WithExitStatement* stmt) {
UNREACHABLE();
}
void FastCodeGenerator::VisitSwitchStatement(SwitchStatement* stmt) {
UNREACHABLE();
}
void FastCodeGenerator::VisitDoWhileStatement(DoWhileStatement* stmt) {
UNREACHABLE();
}
void FastCodeGenerator::VisitWhileStatement(WhileStatement* stmt) {
UNREACHABLE();
}
void FastCodeGenerator::VisitForStatement(ForStatement* stmt) {
UNREACHABLE();
}
void FastCodeGenerator::VisitForInStatement(ForInStatement* stmt) {
UNREACHABLE();
}
void FastCodeGenerator::VisitTryCatchStatement(TryCatchStatement* stmt) {
UNREACHABLE();
}
void FastCodeGenerator::VisitTryFinallyStatement(TryFinallyStatement* stmt) {
UNREACHABLE();
}
void FastCodeGenerator::VisitDebuggerStatement(DebuggerStatement* stmt) {
UNREACHABLE();
}
void FastCodeGenerator::VisitFunctionLiteral(FunctionLiteral* expr) {
UNREACHABLE();
}
__ bind(&bailout_); void FastCodeGenerator::VisitFunctionBoilerplateLiteral(
FunctionBoilerplateLiteral* expr) {
UNREACHABLE();
} }
void FastCodeGenerator::VisitConditional(Conditional* expr) {
UNREACHABLE();
}
void FastCodeGenerator::VisitSlot(Slot* expr) {
UNREACHABLE();
}
void FastCodeGenerator::VisitVariableProxy(VariableProxy* expr) {
ASSERT(expr->var()->is_global() && !expr->var()->is_this());
// Check if we can compile a global variable load directly from the cell.
ASSERT(info()->has_global_object());
LookupResult lookup;
info()->global_object()->Lookup(*expr->name(), &lookup);
// We only support normal (non-accessor/interceptor) DontDelete properties
// for now.
ASSERT(lookup.IsProperty());
ASSERT_EQ(NORMAL, lookup.type());
ASSERT(lookup.IsDontDelete());
Handle<Object> cell(info()->global_object()->GetPropertyCell(&lookup));
// Global variable lookups do not have side effects, so we do not need to
// emit code if we are in an effect context.
if (!destination().is(no_reg)) {
Comment cmnt(masm(), ";; Global");
if (FLAG_print_ir) {
SmartPointer<char> name = expr->name()->ToCString();
PrintF("%d: t%d = Global(%s) // last_use = %d\n", expr->num(),
expr->num(), *name, expr->var_def()->last_use()->num());
}
EmitGlobalVariableLoad(cell);
}
}
void FastCodeGenerator::VisitLiteral(Literal* expr) {
UNREACHABLE();
}
void FastCodeGenerator::VisitRegExpLiteral(RegExpLiteral* expr) {
UNREACHABLE();
}
void FastCodeGenerator::VisitObjectLiteral(ObjectLiteral* expr) {
UNREACHABLE();
}
void FastCodeGenerator::VisitArrayLiteral(ArrayLiteral* expr) {
UNREACHABLE();
}
void FastCodeGenerator::VisitCatchExtensionObject(CatchExtensionObject* expr) {
UNREACHABLE();
}
void FastCodeGenerator::VisitAssignment(Assignment* expr) {
// Known to be a simple this property assignment. Effectively a unary
// operation.
{ Register my_destination = destination();
set_destination(accumulator0());
Visit(expr->value());
set_destination(my_destination);
}
Property* prop = expr->target()->AsProperty();
ASSERT_NOT_NULL(prop);
ASSERT_NOT_NULL(prop->obj()->AsVariableProxy());
ASSERT(prop->obj()->AsVariableProxy()->var()->is_this());
ASSERT(prop->key()->IsPropertyName());
Handle<String> name =
Handle<String>::cast(prop->key()->AsLiteral()->handle());
Comment cmnt(masm(), ";; Store to this");
if (FLAG_print_ir) {
SmartPointer<char> name_string = name->ToCString();
PrintF("%d: ", expr->num());
if (!destination().is(no_reg)) PrintF("t%d = ", expr->num());
PrintF("Store(this, \"%s\", t%d) // last_use(this) = %d\n", *name_string,
expr->value()->num(),
expr->var_def()->last_use()->num());
}
EmitThisPropertyStore(name);
}
void FastCodeGenerator::VisitThrow(Throw* expr) {
UNREACHABLE();
}
void FastCodeGenerator::VisitProperty(Property* expr) {
ASSERT_NOT_NULL(expr->obj()->AsVariableProxy());
ASSERT(expr->obj()->AsVariableProxy()->var()->is_this());
ASSERT(expr->key()->IsPropertyName());
if (!destination().is(no_reg)) {
Handle<String> name =
Handle<String>::cast(expr->key()->AsLiteral()->handle());
Comment cmnt(masm(), ";; Load from this");
if (FLAG_print_ir) {
SmartPointer<char> name_string = name->ToCString();
PrintF("%d: t%d = Load(this, \"%s\") // last_use(this) = %d\n",
expr->num(), expr->num(), *name_string,
expr->var_def()->last_use()->num());
}
EmitThisPropertyLoad(name);
}
}
void FastCodeGenerator::VisitCall(Call* expr) {
UNREACHABLE();
}
void FastCodeGenerator::VisitCallNew(CallNew* expr) {
UNREACHABLE();
}
void FastCodeGenerator::VisitCallRuntime(CallRuntime* expr) {
UNREACHABLE();
}
void FastCodeGenerator::VisitUnaryOperation(UnaryOperation* expr) {
UNREACHABLE();
}
void FastCodeGenerator::VisitCountOperation(CountOperation* expr) {
UNREACHABLE();
}
void FastCodeGenerator::VisitBinaryOperation(BinaryOperation* expr) {
// We support limited binary operations: bitwise OR only allowed to be
// nested on the left.
ASSERT(expr->op() == Token::BIT_OR);
ASSERT(expr->right()->IsLeaf());
{ Register my_destination = destination();
set_destination(accumulator1());
Visit(expr->left());
set_destination(accumulator0());
Visit(expr->right());
set_destination(my_destination);
}
Comment cmnt(masm(), ";; BIT_OR");
if (FLAG_print_ir) {
PrintF("%d: ", expr->num());
if (!destination().is(no_reg)) PrintF("t%d = ", expr->num());
PrintF("BIT_OR(t%d, t%d)\n", expr->left()->num(), expr->right()->num());
}
EmitBitOr();
}
void FastCodeGenerator::VisitCompareOperation(CompareOperation* expr) {
UNREACHABLE();
}
void FastCodeGenerator::VisitThisFunction(ThisFunction* expr) {
UNREACHABLE();
}
#undef __ #undef __

155
deps/v8/src/ia32/fast-codegen-ia32.h

@ -0,0 +1,155 @@
// Copyright 2010 the V8 project authors. All rights reserved.
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following
// disclaimer in the documentation and/or other materials provided
// with the distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived
// from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#ifndef V8_FAST_CODEGEN_IA32_H_
#define V8_FAST_CODEGEN_IA32_H_
#include "v8.h"
#include "ast.h"
#include "compiler.h"
#include "list.h"
namespace v8 {
namespace internal {
class FastCodeGenSyntaxChecker: public AstVisitor {
public:
explicit FastCodeGenSyntaxChecker()
: info_(NULL), has_supported_syntax_(true) {
}
void Check(CompilationInfo* info);
CompilationInfo* info() { return info_; }
bool has_supported_syntax() { return has_supported_syntax_; }
private:
void VisitDeclarations(ZoneList<Declaration*>* decls);
void VisitStatements(ZoneList<Statement*>* stmts);
// AST node visit functions.
#define DECLARE_VISIT(type) virtual void Visit##type(type* node);
AST_NODE_LIST(DECLARE_VISIT)
#undef DECLARE_VISIT
CompilationInfo* info_;
bool has_supported_syntax_;
DISALLOW_COPY_AND_ASSIGN(FastCodeGenSyntaxChecker);
};
class FastCodeGenerator: public AstVisitor {
public:
explicit FastCodeGenerator(MacroAssembler* masm)
: masm_(masm), info_(NULL), destination_(no_reg), smi_bits_(0) {
}
static Handle<Code> MakeCode(CompilationInfo* info);
void Generate(CompilationInfo* compilation_info);
private:
MacroAssembler* masm() { return masm_; }
CompilationInfo* info() { return info_; }
Register destination() { return destination_; }
void set_destination(Register reg) { destination_ = reg; }
FunctionLiteral* function() { return info_->function(); }
Scope* scope() { return info_->scope(); }
// Platform-specific fixed registers, all guaranteed distinct.
Register accumulator0();
Register accumulator1();
Register scratch0();
Register scratch1();
Register receiver_reg();
Register context_reg();
Register other_accumulator(Register reg) {
ASSERT(reg.is(accumulator0()) || reg.is(accumulator1()));
return (reg.is(accumulator0())) ? accumulator1() : accumulator0();
}
// Flags are true if the respective register is statically known to hold a
// smi. We do not track every register, only the accumulator registers.
bool is_smi(Register reg) {
ASSERT(!reg.is(no_reg));
return (smi_bits_ & reg.bit()) != 0;
}
void set_as_smi(Register reg) {
ASSERT(!reg.is(no_reg));
smi_bits_ = smi_bits_ | reg.bit();
}
void clear_as_smi(Register reg) {
ASSERT(!reg.is(no_reg));
smi_bits_ = smi_bits_ & ~reg.bit();
}
// AST node visit functions.
#define DECLARE_VISIT(type) virtual void Visit##type(type* node);
AST_NODE_LIST(DECLARE_VISIT)
#undef DECLARE_VISIT
// Emit code to load the receiver from the stack into receiver_reg.
void EmitLoadReceiver();
// Emit code to load a global variable directly from a global property
// cell into the destination register.
void EmitGlobalVariableLoad(Handle<Object> cell);
// Emit a store to an own property of this. The stored value is expected
// in accumulator0 and the receiver in receiver_reg. The receiver
// register is preserved and the result (the stored value) is left in the
// destination register.
void EmitThisPropertyStore(Handle<String> name);
// Emit a load from an own property of this. The receiver is expected in
// receiver_reg. The receiver register is preserved and the result is
// left in the destination register.
void EmitThisPropertyLoad(Handle<String> name);
// Emit a bitwise or operation. The left operand is in accumulator1 and
// the right is in accumulator0. The result should be left in the
// destination register.
void EmitBitOr();
MacroAssembler* masm_;
CompilationInfo* info_;
Register destination_;
uint32_t smi_bits_;
DISALLOW_COPY_AND_ASSIGN(FastCodeGenerator);
};
} } // namespace v8::internal
#endif // V8_FAST_CODEGEN_IA32_H_

76
deps/v8/src/ia32/virtual-frame-ia32.cc

@ -948,47 +948,38 @@ Result VirtualFrame::CallKeyedLoadIC(RelocInfo::Mode mode) {
} }
Result VirtualFrame::CallStoreIC() { Result VirtualFrame::CallStoreIC(Handle<String> name, bool is_contextual) {
// Name, value, and receiver are on top of the frame. The IC // Value and (if not contextual) receiver are on top of the frame.
// expects name in ecx, value in eax, and receiver in edx. // The IC expects name in ecx, value in eax, and receiver in edx.
Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Initialize)); Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Initialize));
Result name = Pop();
Result value = Pop(); Result value = Pop();
Result receiver = Pop(); if (is_contextual) {
PrepareForCall(0, 0); PrepareForCall(0, 0);
value.ToRegister(eax);
__ mov(edx, Operand(esi, Context::SlotOffset(Context::GLOBAL_INDEX)));
__ mov(ecx, name);
} else {
Result receiver = Pop();
PrepareForCall(0, 0);
// Optimized for case in which name is a constant value. if (value.is_register() && value.reg().is(edx)) {
if (name.is_register() && (name.reg().is(edx) || name.reg().is(eax))) { if (receiver.is_register() && receiver.reg().is(eax)) {
if (!is_used(ecx)) { // Wrong registers.
name.ToRegister(ecx); __ xchg(eax, edx);
} else if (!is_used(ebx)) { } else {
name.ToRegister(ebx); // Register eax is free for value, which frees edx for receiver.
} else { value.ToRegister(eax);
ASSERT(!is_used(edi)); // Only three results are live, so edi is free. receiver.ToRegister(edx);
name.ToRegister(edi); }
}
}
// Now name is not in edx or eax, so we can fix them, then move name to ecx.
if (value.is_register() && value.reg().is(edx)) {
if (receiver.is_register() && receiver.reg().is(eax)) {
// Wrong registers.
__ xchg(eax, edx);
} else { } else {
// Register eax is free for value, which frees edx for receiver. // Register edx is free for receiver, which guarantees eax is free for
value.ToRegister(eax); // value.
receiver.ToRegister(edx); receiver.ToRegister(edx);
value.ToRegister(eax);
} }
} else {
// Register edx is free for receiver, which guarantees eax is free for
// value.
receiver.ToRegister(edx);
value.ToRegister(eax);
} }
// Receiver and value are in the right place, so ecx is free for name. __ mov(ecx, name);
name.ToRegister(ecx);
name.Unuse();
value.Unuse(); value.Unuse();
receiver.Unuse();
return RawCallCodeObject(ic, RelocInfo::CODE_TARGET); return RawCallCodeObject(ic, RelocInfo::CODE_TARGET);
} }
@ -1175,6 +1166,25 @@ void VirtualFrame::EmitPush(Immediate immediate, NumberInfo::Type info) {
} }
void VirtualFrame::Push(Expression* expr) {
ASSERT(expr->IsTrivial());
Literal* lit = expr->AsLiteral();
if (lit != NULL) {
Push(lit->handle());
return;
}
VariableProxy* proxy = expr->AsVariableProxy();
if (proxy != NULL && proxy->is_this()) {
PushParameterAt(-1);
return;
}
UNREACHABLE();
}
#undef __ #undef __
} } // namespace v8::internal } } // namespace v8::internal

12
deps/v8/src/ia32/virtual-frame-ia32.h

@ -339,12 +339,12 @@ class VirtualFrame: public ZoneObject {
Result CallLoadIC(RelocInfo::Mode mode); Result CallLoadIC(RelocInfo::Mode mode);
// Call keyed load IC. Key and receiver are found on top of the // Call keyed load IC. Key and receiver are found on top of the
// frame. They are not dropped. // frame. Both are dropped.
Result CallKeyedLoadIC(RelocInfo::Mode mode); Result CallKeyedLoadIC(RelocInfo::Mode mode);
// Call store IC. Name, value, and receiver are found on top of the // Call store IC. If the load is contextual, value is found on top of the
// frame. Receiver is not dropped. // frame. If not, value and receiver are on the frame. Both are dropped.
Result CallStoreIC(); Result CallStoreIC(Handle<String> name, bool is_contextual);
// Call keyed store IC. Value, key, and receiver are found on top // Call keyed store IC. Value, key, and receiver are found on top
// of the frame. Key and receiver are not dropped. // of the frame. Key and receiver are not dropped.
@ -415,6 +415,10 @@ class VirtualFrame: public ZoneObject {
result->Unuse(); result->Unuse();
} }
// Pushing an expression expects that the expression is trivial (according
// to Expression::IsTrivial).
void Push(Expression* expr);
// Nip removes zero or more elements from immediately below the top // Nip removes zero or more elements from immediately below the top
// of the frame, leaving the previous top-of-frame value on top of // of the frame, leaving the previous top-of-frame value on top of
// the frame. Nip(k) is equivalent to x = Pop(), Drop(k), Push(x). // the frame. Nip(k) is equivalent to x = Pop(), Drop(k), Push(x).

2
deps/v8/src/jump-target-inl.h

@ -42,7 +42,7 @@ void JumpTarget::InitializeEntryElement(int index, FrameElement* target) {
} else if (target->is_copy()) { } else if (target->is_copy()) {
entry_frame_->elements_[target->index()].set_copied(); entry_frame_->elements_[target->index()].set_copied();
} }
if (direction_ == BIDIRECTIONAL) { if (direction_ == BIDIRECTIONAL && !target->is_copy()) {
entry_frame_->elements_[index].set_number_info(NumberInfo::kUnknown); entry_frame_->elements_[index].set_number_info(NumberInfo::kUnknown);
} }
} }

2
deps/v8/src/jump-target.cc

@ -105,7 +105,6 @@ void JumpTarget::ComputeEntryFrame() {
FrameElement* other = &reaching_frames_[j]->elements_[i]; FrameElement* other = &reaching_frames_[j]->elements_[i];
if (element != NULL && !element->is_copy()) { if (element != NULL && !element->is_copy()) {
ASSERT(other != NULL); ASSERT(other != NULL);
ASSERT(!other->is_copy());
// We overwrite the number information of one of the incoming frames. // We overwrite the number information of one of the incoming frames.
// This is safe because we only use the frame for emitting merge code. // This is safe because we only use the frame for emitting merge code.
// The number information of incoming frames is not used anymore. // The number information of incoming frames is not used anymore.
@ -128,7 +127,6 @@ void JumpTarget::ComputeEntryFrame() {
// elements as copied exactly when they have a copy. Undetermined // elements as copied exactly when they have a copy. Undetermined
// elements are initially recorded as if in memory. // elements are initially recorded as if in memory.
if (target != NULL) { if (target != NULL) {
ASSERT(!target->is_copy()); // These initial elements are never copies.
entry_frame_->elements_[index] = *target; entry_frame_->elements_[index] = *target;
InitializeEntryElement(index, target); InitializeEntryElement(index, target);
} }

14
deps/v8/src/macros.py

@ -74,6 +74,10 @@ const kYearShift = 9;
const kMonthShift = 5; const kMonthShift = 5;
# Type query macros. # Type query macros.
#
# Note: We have special support for typeof(foo) === 'bar' in the compiler.
# It will *not* generate a runtime typeof call for the most important
# values of 'bar'.
macro IS_NULL(arg) = (arg === null); macro IS_NULL(arg) = (arg === null);
macro IS_NULL_OR_UNDEFINED(arg) = (arg == null); macro IS_NULL_OR_UNDEFINED(arg) = (arg == null);
macro IS_UNDEFINED(arg) = (typeof(arg) === 'undefined'); macro IS_UNDEFINED(arg) = (typeof(arg) === 'undefined');
@ -83,7 +87,7 @@ macro IS_BOOLEAN(arg) = (typeof(arg) === 'boolean');
macro IS_OBJECT(arg) = (%_IsObject(arg)); macro IS_OBJECT(arg) = (%_IsObject(arg));
macro IS_ARRAY(arg) = (%_IsArray(arg)); macro IS_ARRAY(arg) = (%_IsArray(arg));
macro IS_FUNCTION(arg) = (%_IsFunction(arg)); macro IS_FUNCTION(arg) = (%_IsFunction(arg));
macro IS_REGEXP(arg) = (%_ClassOf(arg) === 'RegExp'); macro IS_REGEXP(arg) = (%_IsRegExp(arg));
macro IS_DATE(arg) = (%_ClassOf(arg) === 'Date'); macro IS_DATE(arg) = (%_ClassOf(arg) === 'Date');
macro IS_NUMBER_WRAPPER(arg) = (%_ClassOf(arg) === 'Number'); macro IS_NUMBER_WRAPPER(arg) = (%_ClassOf(arg) === 'Number');
macro IS_STRING_WRAPPER(arg) = (%_ClassOf(arg) === 'String'); macro IS_STRING_WRAPPER(arg) = (%_ClassOf(arg) === 'String');
@ -97,9 +101,11 @@ macro FLOOR(arg) = $floor(arg);
# Inline macros. Use %IS_VAR to make sure arg is evaluated only once. # Inline macros. Use %IS_VAR to make sure arg is evaluated only once.
macro NUMBER_IS_NAN(arg) = (!%_IsSmi(%IS_VAR(arg)) && !(arg == arg)); macro NUMBER_IS_NAN(arg) = (!%_IsSmi(%IS_VAR(arg)) && !(arg == arg));
macro TO_INTEGER(arg) = (%_IsSmi(%IS_VAR(arg)) ? arg : ToInteger(arg)); macro TO_INTEGER(arg) = (%_IsSmi(%IS_VAR(arg)) ? arg : ToInteger(arg));
macro TO_INT32(arg) = (%_IsSmi(%IS_VAR(arg)) ? arg : (arg >> 0)); macro TO_INT32(arg) = (%_IsSmi(%IS_VAR(arg)) ? arg : (arg >> 0));
macro TO_UINT32(arg) = (arg >>> 0); macro TO_UINT32(arg) = (arg >>> 0);
macro TO_STRING_INLINE(arg) = (IS_STRING(%IS_VAR(arg)) ? arg : NonStringToString(arg));
# Macros implemented in Python. # Macros implemented in Python.
python macro CHAR_CODE(str) = ord(str[1]); python macro CHAR_CODE(str) = ord(str[1]);

11
deps/v8/src/mips/codegen-mips.cc

@ -305,6 +305,11 @@ void CodeGenerator::GenerateIsArray(ZoneList<Expression*>* args) {
} }
void CodeGenerator::GenerateIsRegExp(ZoneList<Expression*>* args) {
UNIMPLEMENTED_MIPS();
}
void CodeGenerator::GenerateIsConstructCall(ZoneList<Expression*>* args) { void CodeGenerator::GenerateIsConstructCall(ZoneList<Expression*>* args) {
UNIMPLEMENTED_MIPS(); UNIMPLEMENTED_MIPS();
} }
@ -365,6 +370,11 @@ void CodeGenerator::GenerateRegExpExec(ZoneList<Expression*>* args) {
} }
void CodeGenerator::GenerateNumberToString(ZoneList<Expression*>* args) {
UNIMPLEMENTED_MIPS();
}
void CodeGenerator::VisitCallRuntime(CallRuntime* node) { void CodeGenerator::VisitCallRuntime(CallRuntime* node) {
UNIMPLEMENTED_MIPS(); UNIMPLEMENTED_MIPS();
} }
@ -498,4 +508,3 @@ int CompareStub::MinorKey() {
#undef __ #undef __
} } // namespace v8::internal } } // namespace v8::internal

4
deps/v8/src/mips/codegen-mips.h

@ -210,6 +210,7 @@ class CodeGenerator: public AstVisitor {
void GenerateIsSmi(ZoneList<Expression*>* args); void GenerateIsSmi(ZoneList<Expression*>* args);
void GenerateIsNonNegativeSmi(ZoneList<Expression*>* args); void GenerateIsNonNegativeSmi(ZoneList<Expression*>* args);
void GenerateIsArray(ZoneList<Expression*>* args); void GenerateIsArray(ZoneList<Expression*>* args);
void GenerateIsRegExp(ZoneList<Expression*>* args);
// Support for construct call checks. // Support for construct call checks.
void GenerateIsConstructCall(ZoneList<Expression*>* args); void GenerateIsConstructCall(ZoneList<Expression*>* args);
@ -241,6 +242,8 @@ class CodeGenerator: public AstVisitor {
void GenerateSubString(ZoneList<Expression*>* args); void GenerateSubString(ZoneList<Expression*>* args);
void GenerateStringCompare(ZoneList<Expression*>* args); void GenerateStringCompare(ZoneList<Expression*>* args);
void GenerateRegExpExec(ZoneList<Expression*>* args); void GenerateRegExpExec(ZoneList<Expression*>* args);
void GenerateNumberToString(ZoneList<Expression*>* args);
// Fast support for Math.sin and Math.cos. // Fast support for Math.sin and Math.cos.
inline void GenerateMathSin(ZoneList<Expression*>* args); inline void GenerateMathSin(ZoneList<Expression*>* args);
@ -308,4 +311,3 @@ class CodeGenerator: public AstVisitor {
} } // namespace v8::internal } } // namespace v8::internal
#endif // V8_MIPS_CODEGEN_MIPS_H_ #endif // V8_MIPS_CODEGEN_MIPS_H_

33
deps/v8/src/mirror-delay.js

@ -553,14 +553,16 @@ StringMirror.prototype.length = function() {
return this.value_.length; return this.value_.length;
}; };
StringMirror.prototype.getTruncatedValue = function(maxLength) {
StringMirror.prototype.toText = function() { if (maxLength != -1 && this.length() > maxLength) {
if (this.length() > kMaxProtocolStringLength) { return this.value_.substring(0, maxLength) +
return this.value_.substring(0, kMaxProtocolStringLength) +
'... (length: ' + this.length() + ')'; '... (length: ' + this.length() + ')';
} else {
return this.value_;
} }
return this.value_;
}
StringMirror.prototype.toText = function() {
return this.getTruncatedValue(kMaxProtocolStringLength);
} }
@ -1955,6 +1957,15 @@ JSONProtocolSerializer.prototype.inlineRefs_ = function() {
} }
JSONProtocolSerializer.prototype.maxStringLength_ = function() {
if (IS_UNDEFINED(this.options_) ||
IS_UNDEFINED(this.options_.maxStringLength)) {
return kMaxProtocolStringLength;
}
return this.options_.maxStringLength;
}
JSONProtocolSerializer.prototype.add_ = function(mirror) { JSONProtocolSerializer.prototype.add_ = function(mirror) {
// If this mirror is already in the list just return. // If this mirror is already in the list just return.
for (var i = 0; i < this.mirrors_.length; i++) { for (var i = 0; i < this.mirrors_.length; i++) {
@ -1987,8 +1998,7 @@ JSONProtocolSerializer.prototype.serializeReferenceWithDisplayData_ =
o.value = mirror.value(); o.value = mirror.value();
break; break;
case STRING_TYPE: case STRING_TYPE:
// Limit string length. o.value = mirror.getTruncatedValue(this.maxStringLength_());
o.value = mirror.toText();
break; break;
case FUNCTION_TYPE: case FUNCTION_TYPE:
o.name = mirror.name(); o.name = mirror.name();
@ -2052,11 +2062,12 @@ JSONProtocolSerializer.prototype.serialize_ = function(mirror, reference,
case STRING_TYPE: case STRING_TYPE:
// String values might have their value cropped to keep down size. // String values might have their value cropped to keep down size.
if (mirror.length() > kMaxProtocolStringLength) { if (this.maxStringLength_() != -1 &&
var str = mirror.value().substring(0, kMaxProtocolStringLength); mirror.length() > this.maxStringLength_()) {
var str = mirror.getTruncatedValue(this.maxStringLength_());
content.value = str; content.value = str;
content.fromIndex = 0; content.fromIndex = 0;
content.toIndex = kMaxProtocolStringLength; content.toIndex = this.maxStringLength_();
} else { } else {
content.value = mirror.value(); content.value = mirror.value();
} }

2
deps/v8/src/objects.h

@ -179,7 +179,7 @@ class PropertyDetails BASE_EMBEDDED {
class TypeField: public BitField<PropertyType, 0, 3> {}; class TypeField: public BitField<PropertyType, 0, 3> {};
class AttributesField: public BitField<PropertyAttributes, 3, 3> {}; class AttributesField: public BitField<PropertyAttributes, 3, 3> {};
class DeletedField: public BitField<uint32_t, 6, 1> {}; class DeletedField: public BitField<uint32_t, 6, 1> {};
class IndexField: public BitField<uint32_t, 7, 31-7> {}; class IndexField: public BitField<uint32_t, 7, 32-7> {};
static const int kInitialIndex = 1; static const int kInitialIndex = 1;
private: private:

2
deps/v8/src/register-allocator.h

@ -141,7 +141,7 @@ class Result BASE_EMBEDDED {
class TypeField: public BitField<Type, 0, 2> {}; class TypeField: public BitField<Type, 0, 2> {};
class NumberInfoField : public BitField<NumberInfo::Type, 2, 3> {}; class NumberInfoField : public BitField<NumberInfo::Type, 2, 3> {};
class DataField: public BitField<uint32_t, 5, 32 - 6> {}; class DataField: public BitField<uint32_t, 5, 32 - 5> {};
inline void CopyTo(Result* destination) const; inline void CopyTo(Result* destination) const;

128
deps/v8/src/runtime.cc

@ -2276,6 +2276,20 @@ static int SingleCharIndexOf(Vector<const schar> string,
return -1; return -1;
} }
template <typename schar>
static int SingleCharLastIndexOf(Vector<const schar> string,
schar pattern_char,
int start_index) {
for (int i = start_index; i >= 0; i--) {
if (pattern_char == string[i]) {
return i;
}
}
return -1;
}
// Trivial string search for shorter strings. // Trivial string search for shorter strings.
// On return, if "complete" is set to true, the return value is the // On return, if "complete" is set to true, the return value is the
// final result of searching for the patter in the subject. // final result of searching for the patter in the subject.
@ -2352,7 +2366,7 @@ static int StringMatchStrategy(Vector<const schar> sub,
// We have an ASCII haystack and a non-ASCII needle. Check if there // We have an ASCII haystack and a non-ASCII needle. Check if there
// really is a non-ASCII character in the needle and bail out if there // really is a non-ASCII character in the needle and bail out if there
// is. // is.
if (sizeof(pchar) > 1 && sizeof(schar) == 1) { if (sizeof(schar) == 1 && sizeof(pchar) > 1) {
for (int i = 0; i < pat.length(); i++) { for (int i = 0; i < pat.length(); i++) {
uc16 c = pat[i]; uc16 c = pat[i];
if (c > String::kMaxAsciiCharCode) { if (c > String::kMaxAsciiCharCode) {
@ -2455,39 +2469,115 @@ static Object* Runtime_StringIndexOf(Arguments args) {
} }
template <typename schar, typename pchar>
static int StringMatchBackwards(Vector<const schar> sub,
Vector<const pchar> pat,
int idx) {
ASSERT(pat.length() >= 1);
ASSERT(idx + pat.length() <= sub.length());
if (sizeof(schar) == 1 && sizeof(pchar) > 1) {
for (int i = 0; i < pat.length(); i++) {
uc16 c = pat[i];
if (c > String::kMaxAsciiCharCode) {
return -1;
}
}
}
pchar pattern_first_char = pat[0];
for (int i = idx; i >= 0; i--) {
if (sub[i] != pattern_first_char) continue;
int j = 1;
while (j < pat.length()) {
if (pat[j] != sub[i+j]) {
break;
}
j++;
}
if (j == pat.length()) {
return i;
}
}
return -1;
}
static Object* Runtime_StringLastIndexOf(Arguments args) { static Object* Runtime_StringLastIndexOf(Arguments args) {
NoHandleAllocation ha; HandleScope scope; // create a new handle scope
ASSERT(args.length() == 3); ASSERT(args.length() == 3);
CONVERT_CHECKED(String, sub, args[0]); CONVERT_ARG_CHECKED(String, sub, 0);
CONVERT_CHECKED(String, pat, args[1]); CONVERT_ARG_CHECKED(String, pat, 1);
Object* index = args[2];
sub->TryFlattenIfNotFlat();
pat->TryFlattenIfNotFlat();
Object* index = args[2];
uint32_t start_index; uint32_t start_index;
if (!Array::IndexFromObject(index, &start_index)) return Smi::FromInt(-1); if (!Array::IndexFromObject(index, &start_index)) return Smi::FromInt(-1);
uint32_t pattern_length = pat->length(); uint32_t pat_length = pat->length();
uint32_t sub_length = sub->length(); uint32_t sub_length = sub->length();
if (start_index + pattern_length > sub_length) { if (start_index + pat_length > sub_length) {
start_index = sub_length - pattern_length; start_index = sub_length - pat_length;
} }
for (int i = start_index; i >= 0; i--) { if (pat_length == 0) {
bool found = true; return Smi::FromInt(start_index);
for (uint32_t j = 0; j < pattern_length; j++) { }
if (sub->Get(i + j) != pat->Get(j)) {
found = false; if (!sub->IsFlat()) {
break; FlattenString(sub);
}
if (pat_length == 1) {
AssertNoAllocation no_heap_allocation; // ensure vectors stay valid
if (sub->IsAsciiRepresentation()) {
uc16 pchar = pat->Get(0);
if (pchar > String::kMaxAsciiCharCode) {
return Smi::FromInt(-1);
} }
return Smi::FromInt(SingleCharLastIndexOf(sub->ToAsciiVector(),
static_cast<char>(pat->Get(0)),
start_index));
} else {
return Smi::FromInt(SingleCharLastIndexOf(sub->ToUC16Vector(),
pat->Get(0),
start_index));
} }
if (found) return Smi::FromInt(i);
} }
return Smi::FromInt(-1); if (!pat->IsFlat()) {
FlattenString(pat);
}
AssertNoAllocation no_heap_allocation; // ensure vectors stay valid
int position = -1;
if (pat->IsAsciiRepresentation()) {
Vector<const char> pat_vector = pat->ToAsciiVector();
if (sub->IsAsciiRepresentation()) {
position = StringMatchBackwards(sub->ToAsciiVector(),
pat_vector,
start_index);
} else {
position = StringMatchBackwards(sub->ToUC16Vector(),
pat_vector,
start_index);
}
} else {
Vector<const uc16> pat_vector = pat->ToUC16Vector();
if (sub->IsAsciiRepresentation()) {
position = StringMatchBackwards(sub->ToAsciiVector(),
pat_vector,
start_index);
} else {
position = StringMatchBackwards(sub->ToUC16Vector(),
pat_vector,
start_index);
}
}
return Smi::FromInt(position);
} }

7
deps/v8/src/runtime.js

@ -529,6 +529,13 @@ function ToString(x) {
return (IS_NULL(x)) ? 'null' : %ToString(%DefaultString(x)); return (IS_NULL(x)) ? 'null' : %ToString(%DefaultString(x));
} }
function NonStringToString(x) {
if (IS_NUMBER(x)) return %NumberToString(x);
if (IS_BOOLEAN(x)) return x ? 'true' : 'false';
if (IS_UNDEFINED(x)) return 'undefined';
return (IS_NULL(x)) ? 'null' : %ToString(%DefaultString(x));
}
// ECMA-262, section 9.9, page 36. // ECMA-262, section 9.9, page 36.
function ToObject(x) { function ToObject(x) {

2
deps/v8/src/scopeinfo.cc

@ -536,7 +536,7 @@ int ContextSlotCache::Hash(Code* code, String* name) {
// Uses only lower 32 bits if pointers are larger. // Uses only lower 32 bits if pointers are larger.
uintptr_t addr_hash = uintptr_t addr_hash =
static_cast<uint32_t>(reinterpret_cast<uintptr_t>(code)) >> 2; static_cast<uint32_t>(reinterpret_cast<uintptr_t>(code)) >> 2;
return (addr_hash ^ name->Hash()) % kLength; return static_cast<int>((addr_hash ^ name->Hash()) % kLength);
} }

4
deps/v8/src/serialize.cc

@ -852,10 +852,10 @@ void SnapshotByteSink::PutInt(uintptr_t integer, const char* description) {
const int max_shift = ((kPointerSize * kBitsPerByte) / 7) * 7; const int max_shift = ((kPointerSize * kBitsPerByte) / 7) * 7;
for (int shift = max_shift; shift > 0; shift -= 7) { for (int shift = max_shift; shift > 0; shift -= 7) {
if (integer >= static_cast<uintptr_t>(1u) << shift) { if (integer >= static_cast<uintptr_t>(1u) << shift) {
Put(((integer >> shift) & 0x7f) | 0x80, "IntPart"); Put((static_cast<int>((integer >> shift)) & 0x7f) | 0x80, "IntPart");
} }
} }
PutSection(integer & 0x7f, "IntLastPart"); PutSection(static_cast<int>(integer & 0x7f), "IntLastPart");
} }
#ifdef DEBUG #ifdef DEBUG

2
deps/v8/src/spaces-inl.h

@ -183,7 +183,7 @@ Page* MemoryAllocator::GetNextPage(Page* p) {
int MemoryAllocator::GetChunkId(Page* p) { int MemoryAllocator::GetChunkId(Page* p) {
ASSERT(p->is_valid()); ASSERT(p->is_valid());
return p->opaque_header & Page::kPageAlignmentMask; return static_cast<int>(p->opaque_header & Page::kPageAlignmentMask);
} }

120
deps/v8/src/string.js

@ -34,7 +34,7 @@
// Set the String function and constructor. // Set the String function and constructor.
%SetCode($String, function(x) { %SetCode($String, function(x) {
var value = %_ArgumentsLength() == 0 ? '' : ToString(x); var value = %_ArgumentsLength() == 0 ? '' : TO_STRING_INLINE(x);
if (%_IsConstructCall()) { if (%_IsConstructCall()) {
%_SetValueOf(this, value); %_SetValueOf(this, value);
} else { } else {
@ -64,7 +64,7 @@ function StringValueOf() {
function StringCharAt(pos) { function StringCharAt(pos) {
var char_code = %_FastCharCodeAt(this, pos); var char_code = %_FastCharCodeAt(this, pos);
if (!%_IsSmi(char_code)) { if (!%_IsSmi(char_code)) {
var subject = ToString(this); var subject = TO_STRING_INLINE(this);
var index = TO_INTEGER(pos); var index = TO_INTEGER(pos);
if (index >= subject.length || index < 0) return ""; if (index >= subject.length || index < 0) return "";
char_code = %StringCharCodeAt(subject, index); char_code = %StringCharCodeAt(subject, index);
@ -79,7 +79,7 @@ function StringCharCodeAt(pos) {
if (%_IsSmi(fast_answer)) { if (%_IsSmi(fast_answer)) {
return fast_answer; return fast_answer;
} }
var subject = ToString(this); var subject = TO_STRING_INLINE(this);
var index = TO_INTEGER(pos); var index = TO_INTEGER(pos);
return %StringCharCodeAt(subject, index); return %StringCharCodeAt(subject, index);
} }
@ -88,7 +88,7 @@ function StringCharCodeAt(pos) {
// ECMA-262, section 15.5.4.6 // ECMA-262, section 15.5.4.6
function StringConcat() { function StringConcat() {
var len = %_ArgumentsLength(); var len = %_ArgumentsLength();
var this_as_string = IS_STRING(this) ? this : ToString(this); var this_as_string = TO_STRING_INLINE(this);
if (len === 1) { if (len === 1) {
return this_as_string + %_Arguments(0); return this_as_string + %_Arguments(0);
} }
@ -96,7 +96,7 @@ function StringConcat() {
parts[0] = this_as_string; parts[0] = this_as_string;
for (var i = 0; i < len; i++) { for (var i = 0; i < len; i++) {
var part = %_Arguments(i); var part = %_Arguments(i);
parts[i + 1] = IS_STRING(part) ? part : ToString(part); parts[i + 1] = TO_STRING_INLINE(part);
} }
return %StringBuilderConcat(parts, len + 1, ""); return %StringBuilderConcat(parts, len + 1, "");
} }
@ -107,8 +107,8 @@ function StringConcat() {
// ECMA-262 section 15.5.4.7 // ECMA-262 section 15.5.4.7
function StringIndexOf(searchString /* position */) { // length == 1 function StringIndexOf(searchString /* position */) { // length == 1
var subject_str = ToString(this); var subject_str = TO_STRING_INLINE(this);
var pattern_str = ToString(searchString); var pattern_str = TO_STRING_INLINE(searchString);
var subject_str_len = subject_str.length; var subject_str_len = subject_str.length;
var pattern_str_len = pattern_str.length; var pattern_str_len = pattern_str.length;
var index = 0; var index = 0;
@ -125,9 +125,9 @@ function StringIndexOf(searchString /* position */) { // length == 1
// ECMA-262 section 15.5.4.8 // ECMA-262 section 15.5.4.8
function StringLastIndexOf(searchString /* position */) { // length == 1 function StringLastIndexOf(searchString /* position */) { // length == 1
var sub = ToString(this); var sub = TO_STRING_INLINE(this);
var subLength = sub.length; var subLength = sub.length;
var pat = ToString(searchString); var pat = TO_STRING_INLINE(searchString);
var patLength = pat.length; var patLength = pat.length;
var index = subLength - patLength; var index = subLength - patLength;
if (%_ArgumentsLength() > 1) { if (%_ArgumentsLength() > 1) {
@ -156,8 +156,8 @@ function StringLastIndexOf(searchString /* position */) { // length == 1
function StringLocaleCompare(other) { function StringLocaleCompare(other) {
if (%_ArgumentsLength() === 0) return 0; if (%_ArgumentsLength() === 0) return 0;
var this_str = ToString(this); var this_str = TO_STRING_INLINE(this);
var other_str = ToString(other); var other_str = TO_STRING_INLINE(other);
return %StringLocaleCompare(this_str, other_str); return %StringLocaleCompare(this_str, other_str);
} }
@ -165,7 +165,7 @@ function StringLocaleCompare(other) {
// ECMA-262 section 15.5.4.10 // ECMA-262 section 15.5.4.10
function StringMatch(regexp) { function StringMatch(regexp) {
if (!IS_REGEXP(regexp)) regexp = new ORIGINAL_REGEXP(regexp); if (!IS_REGEXP(regexp)) regexp = new ORIGINAL_REGEXP(regexp);
var subject = ToString(this); var subject = TO_STRING_INLINE(this);
if (!regexp.global) return regexp.exec(subject); if (!regexp.global) return regexp.exec(subject);
%_Log('regexp', 'regexp-match,%0S,%1r', [subject, regexp]); %_Log('regexp', 'regexp-match,%0S,%1r', [subject, regexp]);
@ -200,7 +200,7 @@ var reusableMatchInfo = [2, "", "", -1, -1];
// ECMA-262, section 15.5.4.11 // ECMA-262, section 15.5.4.11
function StringReplace(search, replace) { function StringReplace(search, replace) {
var subject = IS_STRING(this) ? this : ToString(this); var subject = TO_STRING_INLINE(this);
// Delegate to one of the regular expression variants if necessary. // Delegate to one of the regular expression variants if necessary.
if (IS_REGEXP(search)) { if (IS_REGEXP(search)) {
@ -213,7 +213,7 @@ function StringReplace(search, replace) {
} }
// Convert the search argument to a string and search for it. // Convert the search argument to a string and search for it.
search = IS_STRING(search) ? search : ToString(search); search = TO_STRING_INLINE(search);
var start = %StringIndexOf(subject, search, 0); var start = %StringIndexOf(subject, search, 0);
if (start < 0) return subject; if (start < 0) return subject;
var end = start + search.length; var end = start + search.length;
@ -228,7 +228,7 @@ function StringReplace(search, replace) {
} else { } else {
reusableMatchInfo[CAPTURE0] = start; reusableMatchInfo[CAPTURE0] = start;
reusableMatchInfo[CAPTURE1] = end; reusableMatchInfo[CAPTURE1] = end;
if (!IS_STRING(replace)) replace = ToString(replace); replace = TO_STRING_INLINE(replace);
ExpandReplacement(replace, subject, reusableMatchInfo, builder); ExpandReplacement(replace, subject, reusableMatchInfo, builder);
} }
@ -241,7 +241,7 @@ function StringReplace(search, replace) {
// Helper function for regular expressions in String.prototype.replace. // Helper function for regular expressions in String.prototype.replace.
function StringReplaceRegExp(subject, regexp, replace) { function StringReplaceRegExp(subject, regexp, replace) {
replace = ToString(replace); replace = TO_STRING_INLINE(replace);
return %StringReplaceRegExpWithString(subject, return %StringReplaceRegExpWithString(subject,
regexp, regexp,
replace, replace,
@ -462,7 +462,7 @@ function ApplyReplacementFunction(replace, matchInfo, subject) {
// ECMA-262 section 15.5.4.12 // ECMA-262 section 15.5.4.12
function StringSearch(re) { function StringSearch(re) {
var regexp = new ORIGINAL_REGEXP(re); var regexp = new ORIGINAL_REGEXP(re);
var s = ToString(this); var s = TO_STRING_INLINE(this);
var last_idx = regexp.lastIndex; // keep old lastIndex var last_idx = regexp.lastIndex; // keep old lastIndex
regexp.lastIndex = 0; // ignore re.global property regexp.lastIndex = 0; // ignore re.global property
var result = regexp.exec(s); var result = regexp.exec(s);
@ -476,7 +476,7 @@ function StringSearch(re) {
// ECMA-262 section 15.5.4.13 // ECMA-262 section 15.5.4.13
function StringSlice(start, end) { function StringSlice(start, end) {
var s = ToString(this); var s = TO_STRING_INLINE(this);
var s_len = s.length; var s_len = s.length;
var start_i = TO_INTEGER(start); var start_i = TO_INTEGER(start);
var end_i = s_len; var end_i = s_len;
@ -511,7 +511,7 @@ function StringSlice(start, end) {
// ECMA-262 section 15.5.4.14 // ECMA-262 section 15.5.4.14
function StringSplit(separator, limit) { function StringSplit(separator, limit) {
var subject = ToString(this); var subject = TO_STRING_INLINE(this);
limit = (IS_UNDEFINED(limit)) ? 0xffffffff : TO_UINT32(limit); limit = (IS_UNDEFINED(limit)) ? 0xffffffff : TO_UINT32(limit);
if (limit === 0) return []; if (limit === 0) return [];
@ -525,18 +525,35 @@ function StringSplit(separator, limit) {
} }
var length = subject.length; var length = subject.length;
if (IS_REGEXP(separator)) { if (!IS_REGEXP(separator)) {
%_Log('regexp', 'regexp-split,%0S,%1r', [subject, separator]); separator = TO_STRING_INLINE(separator);
} else { var separator_length = separator.length;
separator = ToString(separator);
// If the separator string is empty then return the elements in the subject. // If the separator string is empty then return the elements in the subject.
if (separator.length == 0) { if (separator_length === 0) {
var result = $Array(length); var result = $Array(length);
for (var i = 0; i < length; i++) result[i] = subject[i]; for (var i = 0; i < length; i++) result[i] = subject[i];
return result; return result;
} }
var result = [];
var start_index = 0;
var index;
while (true) {
if (start_index + separator_length > length ||
(index = %StringIndexOf(subject, separator, start_index)) === -1) {
result.push(SubString(subject, start_index, length));
break;
}
if (result.push(SubString(subject, start_index, index)) === limit) break;
start_index = index + separator_length;
}
return result;
} }
%_Log('regexp', 'regexp-split,%0S,%1r', [subject, separator]);
if (length === 0) { if (length === 0) {
if (splitMatch(separator, subject, 0, 0) != null) return []; if (splitMatch(separator, subject, 0, 0) != null) return [];
return [subject]; return [subject];
@ -571,7 +588,8 @@ function StringSplit(separator, limit) {
result[result.length] = SubString(subject, currentIndex, matchInfo[CAPTURE0]); result[result.length] = SubString(subject, currentIndex, matchInfo[CAPTURE0]);
if (result.length === limit) return result; if (result.length === limit) return result;
for (var i = 2; i < NUMBER_OF_CAPTURES(matchInfo); i += 2) { var num_captures = NUMBER_OF_CAPTURES(matchInfo);
for (var i = 2; i < num_captures; i += 2) {
var start = matchInfo[CAPTURE(i)]; var start = matchInfo[CAPTURE(i)];
var end = matchInfo[CAPTURE(i + 1)]; var end = matchInfo[CAPTURE(i + 1)];
if (start != -1 && end != -1) { if (start != -1 && end != -1) {
@ -591,28 +609,18 @@ function StringSplit(separator, limit) {
// Helper function used by split. This version returns the matchInfo // Helper function used by split. This version returns the matchInfo
// instead of allocating a new array with basically the same information. // instead of allocating a new array with basically the same information.
function splitMatch(separator, subject, current_index, start_index) { function splitMatch(separator, subject, current_index, start_index) {
if (IS_REGEXP(separator)) { var matchInfo = DoRegExpExec(separator, subject, start_index);
var matchInfo = DoRegExpExec(separator, subject, start_index); if (matchInfo == null) return null;
if (matchInfo == null) return null; // Section 15.5.4.14 paragraph two says that we do not allow zero length
// Section 15.5.4.14 paragraph two says that we do not allow zero length // matches at the end of the string.
// matches at the end of the string. if (matchInfo[CAPTURE0] === subject.length) return null;
if (matchInfo[CAPTURE0] === subject.length) return null; return matchInfo;
return matchInfo; }
}
var separatorIndex = subject.indexOf(separator, start_index);
if (separatorIndex === -1) return null;
reusableMatchInfo[CAPTURE0] = separatorIndex;
reusableMatchInfo[CAPTURE1] = separatorIndex + separator.length;
return reusableMatchInfo;
};
// ECMA-262 section 15.5.4.15 // ECMA-262 section 15.5.4.15
function StringSubstring(start, end) { function StringSubstring(start, end) {
var s = this; var s = TO_STRING_INLINE(this);
if (!IS_STRING(s)) s = ToString(s);
var s_len = s.length; var s_len = s.length;
var start_i = TO_INTEGER(start); var start_i = TO_INTEGER(start);
@ -643,7 +651,7 @@ function StringSubstring(start, end) {
// This is not a part of ECMA-262. // This is not a part of ECMA-262.
function StringSubstr(start, n) { function StringSubstr(start, n) {
var s = ToString(this); var s = TO_STRING_INLINE(this);
var len; var len;
// Correct n: If not given, set to string length; if explicitly // Correct n: If not given, set to string length; if explicitly
@ -681,38 +689,38 @@ function StringSubstr(start, n) {
// ECMA-262, 15.5.4.16 // ECMA-262, 15.5.4.16
function StringToLowerCase() { function StringToLowerCase() {
return %StringToLowerCase(ToString(this)); return %StringToLowerCase(TO_STRING_INLINE(this));
} }
// ECMA-262, 15.5.4.17 // ECMA-262, 15.5.4.17
function StringToLocaleLowerCase() { function StringToLocaleLowerCase() {
return %StringToLowerCase(ToString(this)); return %StringToLowerCase(TO_STRING_INLINE(this));
} }
// ECMA-262, 15.5.4.18 // ECMA-262, 15.5.4.18
function StringToUpperCase() { function StringToUpperCase() {
return %StringToUpperCase(ToString(this)); return %StringToUpperCase(TO_STRING_INLINE(this));
} }
// ECMA-262, 15.5.4.19 // ECMA-262, 15.5.4.19
function StringToLocaleUpperCase() { function StringToLocaleUpperCase() {
return %StringToUpperCase(ToString(this)); return %StringToUpperCase(TO_STRING_INLINE(this));
} }
// ES5, 15.5.4.20 // ES5, 15.5.4.20
function StringTrim() { function StringTrim() {
return %StringTrim(ToString(this), true, true); return %StringTrim(TO_STRING_INLINE(this), true, true);
} }
function StringTrimLeft() { function StringTrimLeft() {
return %StringTrim(ToString(this), true, false); return %StringTrim(TO_STRING_INLINE(this), true, false);
} }
function StringTrimRight() { function StringTrimRight() {
return %StringTrim(ToString(this), false, true); return %StringTrim(TO_STRING_INLINE(this), false, true);
} }
// ECMA-262, section 15.5.3.2 // ECMA-262, section 15.5.3.2
@ -731,10 +739,10 @@ function StringFromCharCode(code) {
// Helper function for very basic XSS protection. // Helper function for very basic XSS protection.
function HtmlEscape(str) { function HtmlEscape(str) {
return ToString(str).replace(/</g, "&lt;") return TO_STRING_INLINE(str).replace(/</g, "&lt;")
.replace(/>/g, "&gt;") .replace(/>/g, "&gt;")
.replace(/"/g, "&quot;") .replace(/"/g, "&quot;")
.replace(/'/g, "&#039;"); .replace(/'/g, "&#039;");
}; };
@ -813,7 +821,7 @@ function ReplaceResultBuilder(str) {
ReplaceResultBuilder.prototype.add = function(str) { ReplaceResultBuilder.prototype.add = function(str) {
if (!IS_STRING(str)) str = ToString(str); str = TO_STRING_INLINE(str);
if (str.length > 0) { if (str.length > 0) {
var elements = this.elements; var elements = this.elements;
elements[elements.length] = str; elements[elements.length] = str;

14
deps/v8/src/stub-cache.cc

@ -105,7 +105,7 @@ Object* StubCache::ComputeLoadField(String* name,
if (code->IsFailure()) return code; if (code->IsFailure()) return code;
LOG(CodeCreateEvent(Logger::LOAD_IC_TAG, Code::cast(code), name)); LOG(CodeCreateEvent(Logger::LOAD_IC_TAG, Code::cast(code), name));
Object* result = receiver->map()->UpdateCodeCache(name, Code::cast(code)); Object* result = receiver->map()->UpdateCodeCache(name, Code::cast(code));
if (result->IsFailure()) return code; if (result->IsFailure()) return result;
} }
return Set(name, receiver->map(), Code::cast(code)); return Set(name, receiver->map(), Code::cast(code));
} }
@ -124,7 +124,7 @@ Object* StubCache::ComputeLoadCallback(String* name,
if (code->IsFailure()) return code; if (code->IsFailure()) return code;
LOG(CodeCreateEvent(Logger::LOAD_IC_TAG, Code::cast(code), name)); LOG(CodeCreateEvent(Logger::LOAD_IC_TAG, Code::cast(code), name));
Object* result = receiver->map()->UpdateCodeCache(name, Code::cast(code)); Object* result = receiver->map()->UpdateCodeCache(name, Code::cast(code));
if (result->IsFailure()) return code; if (result->IsFailure()) return result;
} }
return Set(name, receiver->map(), Code::cast(code)); return Set(name, receiver->map(), Code::cast(code));
} }
@ -143,7 +143,7 @@ Object* StubCache::ComputeLoadConstant(String* name,
if (code->IsFailure()) return code; if (code->IsFailure()) return code;
LOG(CodeCreateEvent(Logger::LOAD_IC_TAG, Code::cast(code), name)); LOG(CodeCreateEvent(Logger::LOAD_IC_TAG, Code::cast(code), name));
Object* result = receiver->map()->UpdateCodeCache(name, Code::cast(code)); Object* result = receiver->map()->UpdateCodeCache(name, Code::cast(code));
if (result->IsFailure()) return code; if (result->IsFailure()) return result;
} }
return Set(name, receiver->map(), Code::cast(code)); return Set(name, receiver->map(), Code::cast(code));
} }
@ -160,7 +160,7 @@ Object* StubCache::ComputeLoadInterceptor(String* name,
if (code->IsFailure()) return code; if (code->IsFailure()) return code;
LOG(CodeCreateEvent(Logger::LOAD_IC_TAG, Code::cast(code), name)); LOG(CodeCreateEvent(Logger::LOAD_IC_TAG, Code::cast(code), name));
Object* result = receiver->map()->UpdateCodeCache(name, Code::cast(code)); Object* result = receiver->map()->UpdateCodeCache(name, Code::cast(code));
if (result->IsFailure()) return code; if (result->IsFailure()) return result;
} }
return Set(name, receiver->map(), Code::cast(code)); return Set(name, receiver->map(), Code::cast(code));
} }
@ -189,7 +189,7 @@ Object* StubCache::ComputeLoadGlobal(String* name,
if (code->IsFailure()) return code; if (code->IsFailure()) return code;
LOG(CodeCreateEvent(Logger::LOAD_IC_TAG, Code::cast(code), name)); LOG(CodeCreateEvent(Logger::LOAD_IC_TAG, Code::cast(code), name));
Object* result = receiver->map()->UpdateCodeCache(name, Code::cast(code)); Object* result = receiver->map()->UpdateCodeCache(name, Code::cast(code));
if (result->IsFailure()) return code; if (result->IsFailure()) return result;
} }
return Set(name, receiver->map(), Code::cast(code)); return Set(name, receiver->map(), Code::cast(code));
} }
@ -351,7 +351,7 @@ Object* StubCache::ComputeStoreGlobal(String* name,
if (code->IsFailure()) return code; if (code->IsFailure()) return code;
LOG(CodeCreateEvent(Logger::LOAD_IC_TAG, Code::cast(code), name)); LOG(CodeCreateEvent(Logger::LOAD_IC_TAG, Code::cast(code), name));
Object* result = receiver->map()->UpdateCodeCache(name, Code::cast(code)); Object* result = receiver->map()->UpdateCodeCache(name, Code::cast(code));
if (result->IsFailure()) return code; if (result->IsFailure()) return result;
} }
return Set(name, receiver->map(), Code::cast(code)); return Set(name, receiver->map(), Code::cast(code));
} }
@ -566,7 +566,7 @@ Object* StubCache::ComputeCallGlobal(int argc,
ASSERT_EQ(flags, Code::cast(code)->flags()); ASSERT_EQ(flags, Code::cast(code)->flags());
LOG(CodeCreateEvent(Logger::CALL_IC_TAG, Code::cast(code), name)); LOG(CodeCreateEvent(Logger::CALL_IC_TAG, Code::cast(code), name));
Object* result = receiver->map()->UpdateCodeCache(name, Code::cast(code)); Object* result = receiver->map()->UpdateCodeCache(name, Code::cast(code));
if (result->IsFailure()) return code; if (result->IsFailure()) return result;
} }
return Set(name, receiver->map(), Code::cast(code)); return Set(name, receiver->map(), Code::cast(code));
} }

6
deps/v8/src/utils.h

@ -157,7 +157,9 @@ class BitField {
// Returns a uint32_t mask of bit field. // Returns a uint32_t mask of bit field.
static uint32_t mask() { static uint32_t mask() {
return (1U << (size + shift)) - (1U << shift); // To use all bits of a uint32 in a bitfield without compiler warnings we
// have to compute 2^32 without using a shift count of 32.
return ((1U << shift) << size) - (1U << shift);
} }
// Returns a uint32_t with the bit field value encoded. // Returns a uint32_t with the bit field value encoded.
@ -168,7 +170,7 @@ class BitField {
// Extracts the bit field from the value. // Extracts the bit field from the value.
static T decode(uint32_t value) { static T decode(uint32_t value) {
return static_cast<T>((value >> shift) & ((1U << (size)) - 1)); return static_cast<T>((value & mask()) >> shift);
} }
}; };

4
deps/v8/src/version.cc

@ -34,8 +34,8 @@
// cannot be changed without changing the SCons build script. // cannot be changed without changing the SCons build script.
#define MAJOR_VERSION 2 #define MAJOR_VERSION 2
#define MINOR_VERSION 1 #define MINOR_VERSION 1
#define BUILD_NUMBER 1 #define BUILD_NUMBER 2
#define PATCH_LEVEL 1 #define PATCH_LEVEL 0
#define CANDIDATE_VERSION false #define CANDIDATE_VERSION false
// Define SONAME to have the SCons build the put a specific SONAME into the // Define SONAME to have the SCons build the put a specific SONAME into the

40
deps/v8/src/x64/assembler-x64.cc

@ -33,46 +33,6 @@
namespace v8 { namespace v8 {
namespace internal { namespace internal {
// -----------------------------------------------------------------------------
// Implementation of Register
Register rax = { 0 };
Register rcx = { 1 };
Register rdx = { 2 };
Register rbx = { 3 };
Register rsp = { 4 };
Register rbp = { 5 };
Register rsi = { 6 };
Register rdi = { 7 };
Register r8 = { 8 };
Register r9 = { 9 };
Register r10 = { 10 };
Register r11 = { 11 };
Register r12 = { 12 };
Register r13 = { 13 };
Register r14 = { 14 };
Register r15 = { 15 };
Register no_reg = { -1 };
XMMRegister xmm0 = { 0 };
XMMRegister xmm1 = { 1 };
XMMRegister xmm2 = { 2 };
XMMRegister xmm3 = { 3 };
XMMRegister xmm4 = { 4 };
XMMRegister xmm5 = { 5 };
XMMRegister xmm6 = { 6 };
XMMRegister xmm7 = { 7 };
XMMRegister xmm8 = { 8 };
XMMRegister xmm9 = { 9 };
XMMRegister xmm10 = { 10 };
XMMRegister xmm11 = { 11 };
XMMRegister xmm12 = { 12 };
XMMRegister xmm13 = { 13 };
XMMRegister xmm14 = { 14 };
XMMRegister xmm15 = { 15 };
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
// Implementation of CpuFeatures // Implementation of CpuFeatures

94
deps/v8/src/x64/assembler-x64.h

@ -118,51 +118,23 @@ struct Register {
int code_; int code_;
}; };
extern Register rax; const Register rax = { 0 };
extern Register rcx; const Register rcx = { 1 };
extern Register rdx; const Register rdx = { 2 };
extern Register rbx; const Register rbx = { 3 };
extern Register rsp; const Register rsp = { 4 };
extern Register rbp; const Register rbp = { 5 };
extern Register rsi; const Register rsi = { 6 };
extern Register rdi; const Register rdi = { 7 };
extern Register r8; const Register r8 = { 8 };
extern Register r9; const Register r9 = { 9 };
extern Register r10; const Register r10 = { 10 };
extern Register r11; const Register r11 = { 11 };
extern Register r12; const Register r12 = { 12 };
extern Register r13; const Register r13 = { 13 };
extern Register r14; const Register r14 = { 14 };
extern Register r15; const Register r15 = { 15 };
extern Register no_reg; const Register no_reg = { -1 };
struct MMXRegister {
bool is_valid() const { return 0 <= code_ && code_ < 2; }
int code() const {
ASSERT(is_valid());
return code_;
}
int code_;
};
extern MMXRegister mm0;
extern MMXRegister mm1;
extern MMXRegister mm2;
extern MMXRegister mm3;
extern MMXRegister mm4;
extern MMXRegister mm5;
extern MMXRegister mm6;
extern MMXRegister mm7;
extern MMXRegister mm8;
extern MMXRegister mm9;
extern MMXRegister mm10;
extern MMXRegister mm11;
extern MMXRegister mm12;
extern MMXRegister mm13;
extern MMXRegister mm14;
extern MMXRegister mm15;
struct XMMRegister { struct XMMRegister {
@ -186,22 +158,22 @@ struct XMMRegister {
int code_; int code_;
}; };
extern XMMRegister xmm0; const XMMRegister xmm0 = { 0 };
extern XMMRegister xmm1; const XMMRegister xmm1 = { 1 };
extern XMMRegister xmm2; const XMMRegister xmm2 = { 2 };
extern XMMRegister xmm3; const XMMRegister xmm3 = { 3 };
extern XMMRegister xmm4; const XMMRegister xmm4 = { 4 };
extern XMMRegister xmm5; const XMMRegister xmm5 = { 5 };
extern XMMRegister xmm6; const XMMRegister xmm6 = { 6 };
extern XMMRegister xmm7; const XMMRegister xmm7 = { 7 };
extern XMMRegister xmm8; const XMMRegister xmm8 = { 8 };
extern XMMRegister xmm9; const XMMRegister xmm9 = { 9 };
extern XMMRegister xmm10; const XMMRegister xmm10 = { 10 };
extern XMMRegister xmm11; const XMMRegister xmm11 = { 11 };
extern XMMRegister xmm12; const XMMRegister xmm12 = { 12 };
extern XMMRegister xmm13; const XMMRegister xmm13 = { 13 };
extern XMMRegister xmm14; const XMMRegister xmm14 = { 14 };
extern XMMRegister xmm15; const XMMRegister xmm15 = { 15 };
enum Condition { enum Condition {
// any value < 0 is considered no_condition // any value < 0 is considered no_condition

26
deps/v8/src/x64/codegen-x64.cc

@ -277,7 +277,7 @@ void CodeGenerator::DeclareGlobals(Handle<FixedArray> pairs) {
} }
void CodeGenerator::Generate(CompilationInfo* info, Mode mode) { void CodeGenerator::Generate(CompilationInfo* info) {
// Record the position for debugging purposes. // Record the position for debugging purposes.
CodeForFunctionPosition(info->function()); CodeForFunctionPosition(info->function());
@ -316,7 +316,7 @@ void CodeGenerator::Generate(CompilationInfo* info, Mode mode) {
// rsi: callee's context // rsi: callee's context
allocator_->Initialize(); allocator_->Initialize();
if (mode == PRIMARY) { if (info->mode() == CompilationInfo::PRIMARY) {
frame_->Enter(); frame_->Enter();
// Allocate space for locals and initialize them. // Allocate space for locals and initialize them.
@ -407,6 +407,12 @@ void CodeGenerator::Generate(CompilationInfo* info, Mode mode) {
// frame to match this state. // frame to match this state.
frame_->Adjust(3); frame_->Adjust(3);
allocator_->Unuse(rdi); allocator_->Unuse(rdi);
// Bind all the bailout labels to the beginning of the function.
List<CompilationInfo::Bailout*>* bailouts = info->bailouts();
for (int i = 0; i < bailouts->length(); i++) {
__ bind(bailouts->at(i)->label());
}
} }
// Initialize the function return target after the locals are set // Initialize the function return target after the locals are set
@ -3627,6 +3633,22 @@ void CodeGenerator::GenerateIsArray(ZoneList<Expression*>* args) {
} }
void CodeGenerator::GenerateIsRegExp(ZoneList<Expression*>* args) {
ASSERT(args->length() == 1);
Load(args->at(0));
Result value = frame_->Pop();
value.ToRegister();
ASSERT(value.is_valid());
Condition is_smi = masm_->CheckSmi(value.reg());
destination()->false_target()->Branch(is_smi);
// It is a heap object - get map.
// Check if the object is a regexp.
__ CmpObjectType(value.reg(), JS_REGEXP_TYPE, kScratchRegister);
value.Unuse();
destination()->Split(equal);
}
void CodeGenerator::GenerateIsObject(ZoneList<Expression*>* args) { void CodeGenerator::GenerateIsObject(ZoneList<Expression*>* args) {
// This generates a fast version of: // This generates a fast version of:
// (typeof(arg) === 'object' || %_ClassOf(arg) == 'RegExp') // (typeof(arg) === 'object' || %_ClassOf(arg) == 'RegExp')

12
deps/v8/src/x64/codegen-x64.h

@ -294,15 +294,6 @@ enum ArgumentsAllocationMode {
class CodeGenerator: public AstVisitor { class CodeGenerator: public AstVisitor {
public: public:
// Compilation mode. Either the compiler is used as the primary
// compiler and needs to setup everything or the compiler is used as
// the secondary compiler for split compilation and has to handle
// bailouts.
enum Mode {
PRIMARY,
SECONDARY
};
// Takes a function literal, generates code for it. This function should only // Takes a function literal, generates code for it. This function should only
// be called by compiler.cc. // be called by compiler.cc.
static Handle<Code> MakeCode(CompilationInfo* info); static Handle<Code> MakeCode(CompilationInfo* info);
@ -385,7 +376,7 @@ class CodeGenerator: public AstVisitor {
void VisitStatementsAndSpill(ZoneList<Statement*>* statements); void VisitStatementsAndSpill(ZoneList<Statement*>* statements);
// Main code generation function // Main code generation function
void Generate(CompilationInfo* info, Mode mode); void Generate(CompilationInfo* info);
// Generate the return sequence code. Should be called no more than // Generate the return sequence code. Should be called no more than
// once per compiled function, immediately after binding the return // once per compiled function, immediately after binding the return
@ -536,6 +527,7 @@ class CodeGenerator: public AstVisitor {
void GenerateIsSmi(ZoneList<Expression*>* args); void GenerateIsSmi(ZoneList<Expression*>* args);
void GenerateIsNonNegativeSmi(ZoneList<Expression*>* args); void GenerateIsNonNegativeSmi(ZoneList<Expression*>* args);
void GenerateIsArray(ZoneList<Expression*>* args); void GenerateIsArray(ZoneList<Expression*>* args);
void GenerateIsRegExp(ZoneList<Expression*>* args);
void GenerateIsObject(ZoneList<Expression*>* args); void GenerateIsObject(ZoneList<Expression*>* args);
void GenerateIsFunction(ZoneList<Expression*>* args); void GenerateIsFunction(ZoneList<Expression*>* args);
void GenerateIsUndetectableObject(ZoneList<Expression*>* args); void GenerateIsUndetectableObject(ZoneList<Expression*>* args);

38
deps/v8/src/x64/fast-codegen-x64.cc

@ -156,21 +156,28 @@ void FastCodeGenerator::EmitBitOr() {
// commutative. // commutative.
__ or_(destination(), other_accumulator(destination())); __ or_(destination(), other_accumulator(destination()));
} }
} else if (destination().is(no_reg)) {
// Result is not needed but do not clobber the operands in case of
// bailout.
__ movq(scratch0(), accumulator1());
__ or_(scratch0(), accumulator0());
__ JumpIfNotSmi(scratch0(), bailout());
} else { } else {
// Preserve the destination operand in a scratch register in case of // Left is in accumulator1, right in accumulator0.
// bailout. if (destination().is(accumulator0())) {
__ movq(scratch0(), destination()); __ movq(scratch0(), accumulator0());
__ or_(destination(), other_accumulator(destination())); __ or_(destination(), accumulator1()); // Or is commutative.
__ JumpIfNotSmi(destination(), bailout()); Label* bailout =
info()->AddBailout(accumulator1(), scratch0()); // Left, right.
__ JumpIfNotSmi(destination(), bailout);
} else if (destination().is(accumulator1())) {
__ movq(scratch0(), accumulator1());
__ or_(destination(), accumulator0());
Label* bailout = info()->AddBailout(scratch0(), accumulator0());
__ JumpIfNotSmi(destination(), bailout);
} else {
ASSERT(destination().is(no_reg));
__ movq(scratch0(), accumulator1());
__ or_(scratch0(), accumulator0());
Label* bailout = info()->AddBailout(accumulator1(), accumulator0());
__ JumpIfNotSmi(scratch0(), bailout);
}
} }
// If we didn't bailout, the result (in fact, both inputs too) is known to // If we didn't bailout, the result (in fact, both inputs too) is known to
// be a smi. // be a smi.
set_as_smi(accumulator0()); set_as_smi(accumulator0());
@ -191,6 +198,7 @@ void FastCodeGenerator::Generate(CompilationInfo* compilation_info) {
// Note that we keep a live register reference to esi (context) at this // Note that we keep a live register reference to esi (context) at this
// point. // point.
Label* bailout_to_beginning = info()->AddBailout();
// Receiver (this) is allocated to a fixed register. // Receiver (this) is allocated to a fixed register.
if (info()->has_this_properties()) { if (info()->has_this_properties()) {
Comment cmnt(masm(), ";; MapCheck(this)"); Comment cmnt(masm(), ";; MapCheck(this)");
@ -201,7 +209,7 @@ void FastCodeGenerator::Generate(CompilationInfo* compilation_info) {
Handle<HeapObject> object = Handle<HeapObject>::cast(info()->receiver()); Handle<HeapObject> object = Handle<HeapObject>::cast(info()->receiver());
Handle<Map> map(object->map()); Handle<Map> map(object->map());
EmitLoadReceiver(); EmitLoadReceiver();
__ CheckMap(receiver_reg(), map, bailout(), false); __ CheckMap(receiver_reg(), map, bailout_to_beginning, false);
} }
// If there is a global variable access check if the global object is the // If there is a global variable access check if the global object is the
@ -214,7 +222,7 @@ void FastCodeGenerator::Generate(CompilationInfo* compilation_info) {
ASSERT(info()->has_global_object()); ASSERT(info()->has_global_object());
Handle<Map> map(info()->global_object()->map()); Handle<Map> map(info()->global_object()->map());
__ movq(scratch0(), CodeGenerator::GlobalObject()); __ movq(scratch0(), CodeGenerator::GlobalObject());
__ CheckMap(scratch0(), map, bailout(), true); __ CheckMap(scratch0(), map, bailout_to_beginning, true);
} }
VisitStatements(info()->function()->body()); VisitStatements(info()->function()->body());
@ -227,8 +235,6 @@ void FastCodeGenerator::Generate(CompilationInfo* compilation_info) {
__ movq(rsp, rbp); __ movq(rsp, rbp);
__ pop(rbp); __ pop(rbp);
__ ret((scope()->num_parameters() + 1) * kPointerSize); __ ret((scope()->num_parameters() + 1) * kPointerSize);
__ bind(&bailout_);
} }

2
deps/v8/src/x64/macro-assembler-x64.h

@ -36,7 +36,7 @@ namespace internal {
// Default scratch register used by MacroAssembler (and other code that needs // Default scratch register used by MacroAssembler (and other code that needs
// a spare register). The register isn't callee save, and not used by the // a spare register). The register isn't callee save, and not used by the
// function calling convention. // function calling convention.
static const Register kScratchRegister = r10; static const Register kScratchRegister = { 10 }; // r10.
// Convenience for platform-independent signatures. // Convenience for platform-independent signatures.
typedef Operand MemOperand; typedef Operand MemOperand;

62
deps/v8/test/mjsunit/bugs/bug-619.js

@ -0,0 +1,62 @@
// Copyright 2010 the V8 project authors. All rights reserved.
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following
// disclaimer in the documentation and/or other materials provided
// with the distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived
// from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
// When this bug is corrected move to object-define-property and add
// additional tests for configurable in the same manner as existing tests
// there.
var obj = {};
obj[1] = 42;
assertEquals(42, obj[1]);
Object.defineProperty(obj, '1', {value:10, writable:false});
assertEquals(10, obj[1]);
// We should not be able to override obj[1].
obj[1] = 5;
assertEquals(10, obj[1]);
// Try on a range of numbers.
for(var i = 0; i < 1024; i++) {
obj[i] = 42;
}
for(var i = 0; i < 1024; i++) {
Object.defineProperty(obj, i, {value: i, writable:false});
}
for(var i = 0; i < 1024; i++) {
assertEquals(i, obj[i]);
}
for(var i = 0; i < 1024; i++) {
obj[1] = 5;
}
for(var i = 0; i < 1024; i++) {
assertEquals(i, obj[i]);
}

37
deps/v8/test/mjsunit/debug-evaluate.js

@ -87,6 +87,37 @@ function listener(event, exec_state, event_data, data) {
testRequest(dcp, '{"expression":"a","global":true}', true, 1); testRequest(dcp, '{"expression":"a","global":true}', true, 1);
testRequest(dcp, '{"expression":"this.a","global":true}', true, 1); testRequest(dcp, '{"expression":"this.a","global":true}', true, 1);
// Test that the whole string text is returned if maxStringLength
// parameter is passed.
testRequest(
dcp,
'{"expression":"this.longString","global":true,maxStringLength:-1}',
true,
longString);
testRequest(
dcp,
'{"expression":"this.longString","global":true,maxStringLength:' +
longString.length + '}',
true,
longString);
var truncatedStringSuffix = '... (length: ' + longString.length + ')';
testRequest(
dcp,
'{"expression":"this.longString","global":true,maxStringLength:0}',
true,
truncatedStringSuffix);
testRequest(
dcp,
'{"expression":"this.longString","global":true,maxStringLength:1}',
true,
longString.charAt(0) + truncatedStringSuffix);
// Test that by default string is truncated to first 80 chars.
testRequest(
dcp,
'{"expression":"this.longString","global":true}',
true,
longString.substring(0, 80) + truncatedStringSuffix);
// Indicate that all was processed. // Indicate that all was processed.
listenerComplete = true; listenerComplete = true;
} }
@ -109,6 +140,12 @@ function g() {
a = 1; a = 1;
// String which is longer than 80 chars.
var longString = "1234567890_";
for (var i = 0; i < 4; i++) {
longString += longString;
}
// Set a break point at return in f and invoke g to hit the breakpoint. // Set a break point at return in f and invoke g to hit the breakpoint.
Debug.setBreakPoint(f, 2, 0); Debug.setBreakPoint(f, 2, 0);
g(); g();

4
deps/v8/tools/gyp/v8.gyp

@ -269,7 +269,6 @@
'../../src/execution.h', '../../src/execution.h',
'../../src/factory.cc', '../../src/factory.cc',
'../../src/factory.h', '../../src/factory.h',
'../../src/fast-codegen.cc',
'../../src/fast-codegen.h', '../../src/fast-codegen.h',
'../../src/flag-definitions.h', '../../src/flag-definitions.h',
'../../src/flags.cc', '../../src/flags.cc',
@ -404,6 +403,7 @@
'../../src/arm', '../../src/arm',
], ],
'sources': [ 'sources': [
'../../src/fast-codegen.cc',
'../../src/arm/assembler-arm-inl.h', '../../src/arm/assembler-arm-inl.h',
'../../src/arm/assembler-arm.cc', '../../src/arm/assembler-arm.cc',
'../../src/arm/assembler-arm.h', '../../src/arm/assembler-arm.h',
@ -455,6 +455,7 @@
'../../src/ia32/debug-ia32.cc', '../../src/ia32/debug-ia32.cc',
'../../src/ia32/disasm-ia32.cc', '../../src/ia32/disasm-ia32.cc',
'../../src/ia32/fast-codegen-ia32.cc', '../../src/ia32/fast-codegen-ia32.cc',
'../../src/ia32/fast-codegen-ia32.h',
'../../src/ia32/frames-ia32.cc', '../../src/ia32/frames-ia32.cc',
'../../src/ia32/frames-ia32.h', '../../src/ia32/frames-ia32.h',
'../../src/ia32/full-codegen-ia32.cc', '../../src/ia32/full-codegen-ia32.cc',
@ -475,6 +476,7 @@
'../../src/x64', '../../src/x64',
], ],
'sources': [ 'sources': [
'../../src/fast-codegen.cc',
'../../src/x64/assembler-x64-inl.h', '../../src/x64/assembler-x64-inl.h',
'../../src/x64/assembler-x64.cc', '../../src/x64/assembler-x64.cc',
'../../src/x64/assembler-x64.h', '../../src/x64/assembler-x64.h',

2
deps/v8/tools/visual_studio/v8_base.vcproj

@ -401,7 +401,7 @@
> >
</File> </File>
<File <File
RelativePath="..\..\src\fast-codegen.cc" RelativePath="..\..\src\ia32\fast-codegen-ia32.h"
> >
</File> </File>
<File <File

98
doc/api.txt

@ -19,7 +19,7 @@ World":
var sys = require("sys"), var sys = require("sys"),
http = require("http"); http = require("http");
http.createServer(function (request, response) { http.createServer(function (request, response) {
response.writeHeader(200, {"Content-Type": "text/plain"}); response.writeHead(200, {"Content-Type": "text/plain"});
response.write("Hello World\n"); response.write("Hello World\n");
response.close(); response.close();
}).listen(8000); }).listen(8000);
@ -113,11 +113,10 @@ What platform you're running on. +"linux2"+, +"darwin"+, etc.
Returns the memory usage of the Node process. It looks like this Returns the memory usage of the Node process. It looks like this
+ +
---------------------- ----------------------
{ { rss: 4935680
"rss": 4935680, , vsize: 41893888
"vsize": 41893888, , heapTotal: 1826816
"heapTotal": 1826816, , heapUsed: 650472
"heapUsed": 650472
} }
---------------------- ----------------------
+ +
@ -138,6 +137,9 @@ Returns the current working directory of the process.
+process.getuid(), process.setuid(id)+:: +process.getuid(), process.setuid(id)+::
Gets/sets the user identity of the process. (See setuid(2).) Gets/sets the user identity of the process. (See setuid(2).)
+process.getgid(), process.setgid(id)+::
Gets/sets the group identity of the process. (See setgid(2).)
+process.chdir(directory)+:: +process.chdir(directory)+::
Changes the current working directory of the process. Changes the current working directory of the process.
@ -198,17 +200,30 @@ These function are in the module +"sys"+. Use +require("sys")+ to access
them. them.
+puts(string)+:: +puts(string)+::
Outputs the +string+ and a trailing new-line to +stdout+. Outputs +string+ and a trailing new-line to +stdout+.
+print(string)+:: +print(string)+::
Like +puts()+ but without the trailing new-line. Like +puts()+ but without the trailing new-line.
+debug(string)+:: +debug(string)+::
A synchronous output function. Will block the process and A synchronous output function. Will block the process and
output the string immediately to stdout. output +string+ immediately to +stdout+.
+inspect(object, showHidden, depth)+ ::
Return a string representation of +object+. (For debugging.)
+
If +showHidden+ is +true+, then the object's non-enumerable properties will be
shown too.
+
If +depth+ is provided, it tells +inspect+ how many times to recurse while
formatting the object. This is useful for inspecting large complicated objects.
The default is to only recurse twice. To make it recurse indefinitely, pass
in +null+ for +depth+.
+inspect(object, showHidden)+ ::
Return a string representation of the +object+. (For debugging.) If showHidden is true, then the object's non-enumerable properties will be shown too.
+exec(command, callback)+:: +exec(command, callback)+::
Executes the command as a child process, buffers the output and returns it Executes the command as a child process, buffers the output and returns it
@ -227,7 +242,6 @@ will be +null+. On error +err+ will be an instance of +Error+ and +err.code+
will be the exit code of the child process. will be the exit code of the child process.
== Events == Events
Many objects in Node emit events: a TCP server emits an event each time Many objects in Node emit events: a TCP server emits an event each time
@ -608,6 +622,30 @@ See the +fs.Stats+ section below for more information.
Synchronous stat(2) or lstat(2). Returns an instance of +fs.Stats+. Synchronous stat(2) or lstat(2). Returns an instance of +fs.Stats+.
+fs.link(srcpath, dstpath, callback)+ ::
Asynchronous link(2).
No arguments other than a possible exception are given to the completion callback.
+fs.linkSync(dstpath, srcpath)+ ::
Synchronous link(2).
+fs.symlink(linkdata, path, callback)+ ::
Asynchronous symlink(2).
No arguments other than a possible exception are given to the completion callback.
+fs.symlinkSync(linkdata, path)+ ::
Synchronous symlink(2).
+fs.readlink(path, callback)+ ::
Asynchronous readlink(2).
The callback gets two arguments +(err, resolvedPath)+.
+fs.readlinkSync(path)+ ::
Synchronous readlink(2). Returns the resolved path.
+fs.unlink(path, callback)+ :: +fs.unlink(path, callback)+ ::
Asynchronous unlink(2). Asynchronous unlink(2).
No arguments other than a possible exception are given to the completion callback. No arguments other than a possible exception are given to the completion callback.
@ -867,11 +905,10 @@ If you would like to parse the URL into its parts, you can use
+ +
---------------------------------------- ----------------------------------------
node> require("url").parse("/status?name=ryan") node> require("url").parse("/status?name=ryan")
{ { href: '/status?name=ryan'
"href": "/status?name=ryan", , search: '?name=ryan'
"search": "?name=ryan", , query: 'name=ryan'
"query": "name=ryan", , pathname: '/status'
"pathname": "/status"
} }
---------------------------------------- ----------------------------------------
+ +
@ -881,13 +918,10 @@ you can use the +require("querystring").parse+ function, or pass
+ +
---------------------------------------- ----------------------------------------
node> require("url").parse("/status?name=ryan", true) node> require("url").parse("/status?name=ryan", true)
{ { href: '/status?name=ryan'
"href": "/status?name=ryan", , search: '?name=ryan'
"search": "?name=ryan", , query: { name: 'ryan' }
"query": { , pathname: '/status'
"name": "ryan"
},
"pathname": "/status"
} }
---------------------------------------- ----------------------------------------
+ +
@ -924,7 +958,7 @@ The +http.Connection+ object.
This object is created internally by a HTTP server--not by the user. It is This object is created internally by a HTTP server--not by the user. It is
passed as the second parameter to the +"request"+ event. passed as the second parameter to the +"request"+ event.
+response.writeHeader(statusCode[, reasonPhrase] , headers)+ :: +response.writeHead(statusCode[, reasonPhrase] , headers)+ ::
Sends a response header to the request. The status code is a 3-digit HTTP Sends a response header to the request. The status code is a 3-digit HTTP
status code, like +404+. The last argument, +headers+, are the response headers. status code, like +404+. The last argument, +headers+, are the response headers.
@ -935,7 +969,7 @@ Example:
+ +
---------------------------------------- ----------------------------------------
var body = "hello world"; var body = "hello world";
response.writeHeader(200, { response.writeHead(200, {
"Content-Length": body.length, "Content-Length": body.length,
"Content-Type": "text/plain" "Content-Type": "text/plain"
}); });
@ -946,7 +980,7 @@ be called before +response.close()+ is called.
+response.write(chunk, encoding="ascii")+ :: +response.write(chunk, encoding="ascii")+ ::
This method must be called after +writeHeader+ was This method must be called after +writeHead+ was
called. It sends a chunk of the response body. This method may called. It sends a chunk of the response body. This method may
be called multiple times to provide successive parts of the body. be called multiple times to provide successive parts of the body.
+ +
@ -1270,7 +1304,7 @@ http.createServer(function (req, res) {
fields = {}, fields = {},
name, filename; name, filename;
mp.addListener("error", function (er) { mp.addListener("error", function (er) {
res.writeHeader(400, {"content-type":"text/plain"}); res.writeHead(400, {"content-type":"text/plain"});
res.write("You sent a bad message!\n"+er.message); res.write("You sent a bad message!\n"+er.message);
res.close(); res.close();
}); });
@ -1290,7 +1324,7 @@ http.createServer(function (req, res) {
}); });
mp.addListener("complete", function () { mp.addListener("complete", function () {
var response = "You posted: \n" + sys.inspect(fields); var response = "You posted: \n" + sys.inspect(fields);
res.writeHeader(200, { res.writeHead(200, {
"content-type" : "text/plain", "content-type" : "text/plain",
"content-length" : response.length "content-length" : response.length
}); });
@ -1656,13 +1690,7 @@ Normalize an array of path parts, taking care of +".."+ and +"."+ parts. Exampl
path.normalizeArray(["", path.normalizeArray(["",
"foo", "bar", "baz", "asdf", "quux", ".."]) "foo", "bar", "baz", "asdf", "quux", ".."])
// returns // returns
[ [ '', 'foo', 'bar', 'baz', 'asdf' ]
"",
"foo",
"bar",
"baz",
"asdf"
]
------------------------------------ ------------------------------------
+ +

2
doc/index.html

@ -48,7 +48,7 @@ var sys = require('sys'),
http = require('http'); http = require('http');
http.createServer(function (req, res) { http.createServer(function (req, res) {
setTimeout(function () { setTimeout(function () {
res.writeHeader(200, {'Content-Type': 'text/plain'}); res.writeHead(200, {'Content-Type': 'text/plain'});
res.write('Hello World'); res.write('Hello World');
res.close(); res.close();
}, 2000); }, 2000);

7
lib/http.js

@ -257,7 +257,7 @@ sys.inherits(ServerResponse, OutgoingMessage);
exports.ServerResponse = ServerResponse; exports.ServerResponse = ServerResponse;
ServerResponse.prototype.writeHeader = function (statusCode) { ServerResponse.prototype.writeHead = function (statusCode) {
var reasonPhrase, headers, headerIndex; var reasonPhrase, headers, headerIndex;
if (typeof arguments[1] == 'string') { if (typeof arguments[1] == 'string') {
@ -279,8 +279,9 @@ ServerResponse.prototype.writeHeader = function (statusCode) {
this.sendHeaderLines(status_line, headers); this.sendHeaderLines(status_line, headers);
}; };
// TODO eventually remove sendHeader() // TODO eventually remove sendHeader(), writeHeader()
ServerResponse.prototype.sendHeader = ServerResponse.prototype.writeHeader; ServerResponse.prototype.sendHeader = ServerResponse.prototype.writeHead;
ServerResponse.prototype.writeHeader = ServerResponse.prototype.writeHead;
function ClientRequest (method, url, headers) { function ClientRequest (method, url, headers) {
OutgoingMessage.call(this); OutgoingMessage.call(this);

63
lib/sys.js

@ -29,13 +29,13 @@ exports.error = function (x) {
* @param {Object} value The object to print out * @param {Object} value The object to print out
* @param {Boolean} showHidden Flag that shows hidden (not enumerable) properties of objects. * @param {Boolean} showHidden Flag that shows hidden (not enumerable) properties of objects.
*/ */
exports.inspect = function (obj, showHidden) { exports.inspect = function (obj, showHidden, depth) {
var seen = []; var seen = [];
function format(value) { function format(value, recurseTimes) {
// Primitive types cannot have properties // Primitive types cannot have properties
switch (typeof value) { switch (typeof value) {
case 'undefined': return 'undefined'; case 'undefined': return 'undefined';
case 'string': return JSON.stringify(value); case 'string': return JSON.stringify(value).replace(/'/g, "\\'").replace(/\\"/g, '"').replace(/(^"|"$)/g, "'");
case 'number': return '' + value; case 'number': return '' + value;
case 'boolean': return '' + value; case 'boolean': return '' + value;
} }
@ -45,9 +45,12 @@ exports.inspect = function (obj, showHidden) {
} }
// Look up the keys of the object. // Look up the keys of the object.
var keys = showHidden ? Object.getOwnPropertyNames(value).map(function (key) { if (showHidden) {
return '' + key; var keys = Object.getOwnPropertyNames(value).map(function (key) { return '' + key; });
}) : Object.keys(value); } else {
var keys = Object.keys(value);
}
var visible_keys = Object.keys(value); var visible_keys = Object.keys(value);
// Functions without properties can be shortcutted. // Functions without properties can be shortcutted.
@ -92,7 +95,15 @@ exports.inspect = function (obj, showHidden) {
return braces[0] + base + braces[1]; return braces[0] + base + braces[1];
} }
return braces[0] + base + "\n" + (keys.map(function (key) { if( recurseTimes < 0 ) {
if (value instanceof RegExp) {
return '' + value;
} else {
return "[object Object]";
}
}
output = keys.map(function (key) {
var name, str; var name, str;
if (value.__lookupGetter__) { if (value.__lookupGetter__) {
if (value.__lookupGetter__(key)) { if (value.__lookupGetter__(key)) {
@ -112,7 +123,17 @@ exports.inspect = function (obj, showHidden) {
} }
if (!str) { if (!str) {
if (seen.indexOf(value[key]) < 0) { if (seen.indexOf(value[key]) < 0) {
str = format(value[key]); if ( recurseTimes === null) {
str = format(value[key]);
}
else {
str = format(value[key], recurseTimes - 1);
}
if( str.indexOf('\n') > -1 ) {
str = '\n' + str.split('\n').map(function(line) {
return ' ' + line;
}).join('\n');
}
} else { } else {
str = '[Circular]'; str = '[Circular]';
} }
@ -122,14 +143,32 @@ exports.inspect = function (obj, showHidden) {
return str; return str;
} }
name = JSON.stringify('' + key); name = JSON.stringify('' + key);
if( name.match(/^"([a-zA-Z_0-9]+)"$/) ) {
name = name.substr(1, name.length-2);
}
else {
name = name.replace(/'/g, "\\'").replace(/\\"/g, '"').replace(/(^"|"$)/g, "'");
}
} }
return name + ": " + str; return name + ": " + str;
}).join(",\n")).split("\n").map(function (line) { });
return ' ' + line;
}).join('\n') + "\n" + braces[1];
var length = output.reduce(function(prev, cur) {
return prev + cur.length + 1;
},0);
if( length > 50 ) {
output = braces[0] + (base === '' ? '' : base + '\n,') + ' ' + output.join('\n, ') + '\n' +braces[1];
}
else {
output = braces[0] + base + ' ' + output.join(', ') + ' ' + braces[1];
}
return output;
} }
return format(obj); return format(obj, (typeof depth === 'undefined' ? 2 : depth));
}; };
exports.p = function () { exports.p = function () {

34
src/node.cc

@ -492,6 +492,29 @@ static Handle<Value> GetUid(const Arguments& args) {
return scope.Close(Integer::New(uid)); return scope.Close(Integer::New(uid));
} }
static Handle<Value> GetGid(const Arguments& args) {
HandleScope scope;
int gid = getgid();
return scope.Close(Integer::New(gid));
}
static Handle<Value> SetGid(const Arguments& args) {
HandleScope scope;
if (args.Length() < 1) {
return ThrowException(Exception::Error(
String::New("setgid requires 1 argument")));
}
Local<Integer> given_gid = args[0]->ToInteger();
int gid = given_gid->Int32Value();
int result;
if ((result == setgid(gid)) != 0) {
return ThrowException(Exception::Error(String::New(strerror(errno))));
}
return Undefined();
}
static Handle<Value> SetUid(const Arguments& args) { static Handle<Value> SetUid(const Arguments& args) {
HandleScope scope; HandleScope scope;
@ -1038,6 +1061,10 @@ static void Load(int argc, char *argv[]) {
NODE_SET_METHOD(process, "cwd", Cwd); NODE_SET_METHOD(process, "cwd", Cwd);
NODE_SET_METHOD(process, "getuid", GetUid); NODE_SET_METHOD(process, "getuid", GetUid);
NODE_SET_METHOD(process, "setuid", SetUid); NODE_SET_METHOD(process, "setuid", SetUid);
NODE_SET_METHOD(process, "setgid", SetGid);
NODE_SET_METHOD(process, "getgid", GetGid);
NODE_SET_METHOD(process, "umask", Umask); NODE_SET_METHOD(process, "umask", Umask);
NODE_SET_METHOD(process, "dlopen", DLOpen); NODE_SET_METHOD(process, "dlopen", DLOpen);
NODE_SET_METHOD(process, "kill", Kill); NODE_SET_METHOD(process, "kill", Kill);
@ -1165,7 +1192,8 @@ static void PrintHelp() {
printf("Usage: node [options] script.js [arguments] \n" printf("Usage: node [options] script.js [arguments] \n"
" -v, --version print node's version\n" " -v, --version print node's version\n"
" --debug[=port] enable remote debugging via given TCP port\n" " --debug[=port] enable remote debugging via given TCP port\n"
" --debug-brk[=port] as above, but break in node.js and\n" " without stopping the execution\n"
" --debug-brk[=port] as above, but break in script.js and\n"
" wait for remote debugger to connect\n" " wait for remote debugger to connect\n"
" --cflags print pre-processor and compiler flags\n" " --cflags print pre-processor and compiler flags\n"
" --v8-options print v8 command line options\n\n" " --v8-options print v8 command line options\n\n"
@ -1180,7 +1208,7 @@ static void ParseArgs(int *argc, char **argv) {
const char *arg = argv[i]; const char *arg = argv[i];
if (strstr(arg, "--debug") == arg) { if (strstr(arg, "--debug") == arg) {
ParseDebugOpt(arg); ParseDebugOpt(arg);
argv[i] = reinterpret_cast<const char*>(""); argv[i] = const_cast<char*>("");
option_end_index = i; option_end_index = i;
} else if (strcmp(arg, "--version") == 0 || strcmp(arg, "-v") == 0) { } else if (strcmp(arg, "--version") == 0 || strcmp(arg, "-v") == 0) {
printf("%s\n", NODE_VERSION); printf("%s\n", NODE_VERSION);
@ -1192,7 +1220,7 @@ static void ParseArgs(int *argc, char **argv) {
PrintHelp(); PrintHelp();
exit(0); exit(0);
} else if (strcmp(arg, "--v8-options") == 0) { } else if (strcmp(arg, "--v8-options") == 0) {
argv[i] = reinterpret_cast<const char*>("--help"); argv[i] = const_cast<char*>("--help");
option_end_index = i+1; option_end_index = i+1;
} else if (argv[i][0] != '-') { } else if (argv[i][0] != '-') {
option_end_index = i-1; option_end_index = i-1;

28
src/node.js

@ -498,6 +498,30 @@ var fsModule = createInternalModule("fs", function (exports) {
return process.fs.stat(path); return process.fs.stat(path);
}; };
exports.readlink = function (path, callback) {
process.fs.readlink(path, callback || noop);
};
exports.readlinkSync = function (path) {
return process.fs.readlink(path);
};
exports.symlink = function (destination, path, callback) {
process.fs.symlink(destination, path, callback || noop);
};
exports.symlinkSync = function (destination, path) {
return process.fs.symlink(destination, path);
};
exports.link = function (srcpath, dstpath, callback) {
process.fs.link(srcpath, dstpath, callback || noop);
};
exports.linkSync = function (srcpath, dstpath) {
return process.fs.link(srcpath, dstpath);
};
exports.unlink = function (path, callback) { exports.unlink = function (path, callback) {
process.fs.unlink(path, callback || noop); process.fs.unlink(path, callback || noop);
}; };
@ -530,7 +554,7 @@ var fsModule = createInternalModule("fs", function (exports) {
}); });
} }
exports.writeFile = function (path, data, encoding_) { exports.writeFile = function (path, data, encoding_, callback) {
var encoding = (typeof(encoding_) == 'string' ? encoding_ : 'utf8'); var encoding = (typeof(encoding_) == 'string' ? encoding_ : 'utf8');
var callback_ = arguments[arguments.length - 1]; var callback_ = arguments[arguments.length - 1];
var callback = (typeof(callback_) == 'function' ? callback_ : null); var callback = (typeof(callback_) == 'function' ? callback_ : null);
@ -574,7 +598,7 @@ var fsModule = createInternalModule("fs", function (exports) {
}); });
} }
exports.readFile = function (path, encoding_) { exports.readFile = function (path, encoding_, callback) {
var encoding = typeof(encoding_) == 'string' ? encoding : 'utf8'; var encoding = typeof(encoding_) == 'string' ? encoding : 'utf8';
var callback_ = arguments[arguments.length - 1]; var callback_ = arguments[arguments.length - 1];
var callback = (typeof(callback_) == 'function' ? callback_ : null); var callback = (typeof(callback_) == 'function' ? callback_ : null);

75
src/node_file.cc

@ -10,6 +10,12 @@
#include <assert.h> #include <assert.h>
#include <string.h> #include <string.h>
#include <errno.h> #include <errno.h>
#include <limits.h>
/* used for readlink, AIX doesn't provide it */
#ifndef PATH_MAX
#define PATH_MAX 4096
#endif
namespace node { namespace node {
@ -53,6 +59,8 @@ static int After(eio_req *req) {
case EIO_RMDIR: case EIO_RMDIR:
case EIO_MKDIR: case EIO_MKDIR:
case EIO_FTRUNCATE: case EIO_FTRUNCATE:
case EIO_LINK:
case EIO_SYMLINK:
case EIO_CHMOD: case EIO_CHMOD:
argc = 0; argc = 0;
break; break;
@ -76,6 +84,13 @@ static int After(eio_req *req) {
argv[1] = BuildStatsObject(s); argv[1] = BuildStatsObject(s);
break; break;
} }
case EIO_READLINK:
{
argc = 2;
argv[1] = String::New(static_cast<char*>(req->ptr2), req->result);
break;
}
case EIO_READ: case EIO_READ:
{ {
@ -198,6 +213,63 @@ static Handle<Value> LStat(const Arguments& args) {
} }
} }
static Handle<Value> Symlink(const Arguments& args) {
HandleScope scope;
if (args.Length() < 2 || !args[0]->IsString() || !args[1]->IsString()) {
return THROW_BAD_ARGS;
}
String::Utf8Value dest(args[0]->ToString());
String::Utf8Value path(args[1]->ToString());
if (args[2]->IsFunction()) {
ASYNC_CALL(symlink, args[2], *dest, *path)
} else {
int ret = symlink(*dest, *path);
if (ret != 0) return ThrowException(errno_exception(errno));
return Undefined();
}
}
static Handle<Value> Link(const Arguments& args) {
HandleScope scope;
if (args.Length() < 2 || !args[0]->IsString() || !args[1]->IsString()) {
return THROW_BAD_ARGS;
}
String::Utf8Value orig_path(args[0]->ToString());
String::Utf8Value new_path(args[1]->ToString());
if (args[2]->IsFunction()) {
ASYNC_CALL(link, args[2], *orig_path, *new_path)
} else {
int ret = link(*orig_path, *new_path);
if (ret != 0) return ThrowException(errno_exception(errno));
return Undefined();
}
}
static Handle<Value> ReadLink(const Arguments& args) {
HandleScope scope;
if (args.Length() < 1 || !args[0]->IsString()) {
return THROW_BAD_ARGS;
}
String::Utf8Value path(args[0]->ToString());
if (args[1]->IsFunction()) {
ASYNC_CALL(readlink, args[1], *path)
} else {
char buf[PATH_MAX];
ssize_t bz = readlink(*path, buf, PATH_MAX);
if (bz == -1) return ThrowException(errno_exception(errno));
return scope.Close(String::New(buf));
}
}
static Handle<Value> Rename(const Arguments& args) { static Handle<Value> Rename(const Arguments& args) {
HandleScope scope; HandleScope scope;
@ -496,6 +568,9 @@ void File::Initialize(Handle<Object> target) {
NODE_SET_METHOD(target, "readdir", ReadDir); NODE_SET_METHOD(target, "readdir", ReadDir);
NODE_SET_METHOD(target, "stat", Stat); NODE_SET_METHOD(target, "stat", Stat);
NODE_SET_METHOD(target, "lstat", LStat); NODE_SET_METHOD(target, "lstat", LStat);
NODE_SET_METHOD(target, "link", Link);
NODE_SET_METHOD(target, "symlink", Symlink);
NODE_SET_METHOD(target, "readlink", ReadLink);
NODE_SET_METHOD(target, "unlink", Unlink); NODE_SET_METHOD(target, "unlink", Unlink);
NODE_SET_METHOD(target, "write", Write); NODE_SET_METHOD(target, "write", Write);

3
src/node_signal_handler.cc

@ -56,6 +56,9 @@ Handle<Value> SignalHandler::New(const Arguments& args) {
ev_signal_init(&handler->watcher_, SignalHandler::OnSignal, sig); ev_signal_init(&handler->watcher_, SignalHandler::OnSignal, sig);
handler->watcher_.data = handler; handler->watcher_.data = handler;
// Give signal handlers very high priority. The only thing that has higher
// priority is the garbage collector check.
ev_set_priority(&handler->watcher_, EV_MAXPRI-1);
ev_signal_start(EV_DEFAULT_UC_ &handler->watcher_); ev_signal_start(EV_DEFAULT_UC_ &handler->watcher_);
ev_unref(EV_DEFAULT_UC); ev_unref(EV_DEFAULT_UC);

2
test/mjsunit/common.js → test/common.js

@ -2,7 +2,7 @@ var path = require("path");
exports.testDir = path.dirname(__filename); exports.testDir = path.dirname(__filename);
exports.fixturesDir = path.join(exports.testDir, "fixtures"); exports.fixturesDir = path.join(exports.testDir, "fixtures");
exports.libDir = path.join(exports.testDir, "../../lib"); exports.libDir = path.join(exports.testDir, "../lib");
require.paths.unshift(exports.libDir); require.paths.unshift(exports.libDir);

0
test/mjsunit/disabled/test-cat.js → test/disabled/test-cat.js

0
test/mjsunit/disabled/test-dns.js → test/disabled/test-dns.js

0
test/mjsunit/disabled/test-eio-race3.js → test/disabled/test-eio-race3.js

0
test/mjsunit/disabled/test-fs-sendfile.js → test/disabled/test-fs-sendfile.js

0
test/mjsunit/disabled/test-http-stress.js → test/disabled/test-http-stress.js

0
test/mjsunit/fixtures/a.js → test/fixtures/a.js

0
test/mjsunit/fixtures/b/c.js → test/fixtures/b/c.js

0
test/mjsunit/fixtures/b/d.js → test/fixtures/b/d.js

0
test/mjsunit/fixtures/b/package/index.js → test/fixtures/b/package/index.js

0
test/mjsunit/fixtures/cycles/folder/foo.js → test/fixtures/cycles/folder/foo.js

0
test/mjsunit/fixtures/cycles/root.js → test/fixtures/cycles/root.js

0
test/mjsunit/fixtures/echo.js → test/fixtures/echo.js

0
test/mjsunit/fixtures/multipart.js → test/fixtures/multipart.js

0
test/mjsunit/fixtures/nested-index/one/hello.js → test/fixtures/nested-index/one/hello.js

0
test/mjsunit/fixtures/nested-index/one/index.js → test/fixtures/nested-index/one/index.js

0
test/mjsunit/fixtures/nested-index/two/hello.js → test/fixtures/nested-index/two/hello.js

0
test/mjsunit/fixtures/nested-index/two/index.js → test/fixtures/nested-index/two/index.js

0
test/mjsunit/fixtures/print-chars.js → test/fixtures/print-chars.js

0
test/fixtures/readdir/are

0
test/fixtures/readdir/dir/empty

0
test/fixtures/readdir/empty

0
test/fixtures/readdir/files

0
test/fixtures/readdir/for

0
test/fixtures/readdir/just

0
test/fixtures/readdir/testing.js

0
test/fixtures/readdir/these

0
test/mjsunit/fixtures/test_ca.pem → test/fixtures/test_ca.pem

0
test/mjsunit/fixtures/test_cert.pem → test/fixtures/test_cert.pem

0
test/mjsunit/fixtures/test_key.pem → test/fixtures/test_key.pem

0
test/mjsunit/fixtures/throws_error.js → test/fixtures/throws_error.js

0
test/mjsunit/fixtures/x.txt → test/fixtures/x.txt

1
test/internet/internet.status

@ -0,0 +1 @@
prefix internet

21
test/mjsunit/testcfg.py → test/internet/testcfg.py

@ -35,10 +35,10 @@ FLAGS_PATTERN = re.compile(r"//\s+Flags:(.*)")
FILES_PATTERN = re.compile(r"//\s+Files:(.*)") FILES_PATTERN = re.compile(r"//\s+Files:(.*)")
class MjsunitTestCase(test.TestCase): class SimpleTestCase(test.TestCase):
def __init__(self, path, file, mode, context, config): def __init__(self, path, file, mode, context, config):
super(MjsunitTestCase, self).__init__(context, path) super(SimpleTestCase, self).__init__(context, path)
self.file = file self.file = file
self.config = config self.config = config
self.mode = mode self.mode = mode
@ -68,10 +68,10 @@ class MjsunitTestCase(test.TestCase):
return open(self.file).read() return open(self.file).read()
class MjsunitTestConfiguration(test.TestConfiguration): class SimpleTestConfiguration(test.TestConfiguration):
def __init__(self, context, root): def __init__(self, context, root):
super(MjsunitTestConfiguration, self).__init__(context, root) super(SimpleTestConfiguration, self).__init__(context, root)
def Ls(self, path): def Ls(self, path):
def SelectTest(name): def SelectTest(name):
@ -79,27 +79,30 @@ class MjsunitTestConfiguration(test.TestConfiguration):
return [f[:-3] for f in os.listdir(path) if SelectTest(f)] return [f[:-3] for f in os.listdir(path) if SelectTest(f)]
def ListTests(self, current_path, path, mode): def ListTests(self, current_path, path, mode):
mjsunit = [current_path + [t] for t in self.Ls(self.root)] simple = [current_path + [t] for t in self.Ls(self.root)]
#simple = [current_path + ['simple', t] for t in self.Ls(join(self.root, 'simple'))]
#pummel = [current_path + ['pummel', t] for t in self.Ls(join(self.root, 'pummel'))]
#internet = [current_path + ['internet', t] for t in self.Ls(join(self.root, 'internet'))]
#regress = [current_path + ['regress', t] for t in self.Ls(join(self.root, 'regress'))] #regress = [current_path + ['regress', t] for t in self.Ls(join(self.root, 'regress'))]
#bugs = [current_path + ['bugs', t] for t in self.Ls(join(self.root, 'bugs'))] #bugs = [current_path + ['bugs', t] for t in self.Ls(join(self.root, 'bugs'))]
#tools = [current_path + ['tools', t] for t in self.Ls(join(self.root, 'tools'))] #tools = [current_path + ['tools', t] for t in self.Ls(join(self.root, 'tools'))]
all_tests = mjsunit # + regress + bugs + tools all_tests = simple # + regress + bugs + tools
result = [] result = []
for test in all_tests: for test in all_tests:
if self.Contains(path, test): if self.Contains(path, test):
file_path = join(self.root, reduce(join, test[1:], "") + ".js") file_path = join(self.root, reduce(join, test[1:], "") + ".js")
result.append(MjsunitTestCase(test, file_path, mode, self.context, self)) result.append(SimpleTestCase(test, file_path, mode, self.context, self))
return result return result
def GetBuildRequirements(self): def GetBuildRequirements(self):
return ['sample', 'sample=shell'] return ['sample', 'sample=shell']
def GetTestStatus(self, sections, defs): def GetTestStatus(self, sections, defs):
status_file = join(self.root, 'mjsunit.status') status_file = join(self.root, 'simple.status')
if exists(status_file): if exists(status_file):
test.ReadConfigurationInto(status_file, sections, defs) test.ReadConfigurationInto(status_file, sections, defs)
def GetConfiguration(context, root): def GetConfiguration(context, root):
return MjsunitTestConfiguration(context, root) return SimpleTestConfiguration(context, root)

40
test/mjsunit/test-readdir.js

@ -1,40 +0,0 @@
process.mixin(require("./common"));
var got_error = false;
var files = ['a.js'
, 'b'
, 'cycles'
, 'echo.js'
, 'multipart.js'
, 'nested-index'
, 'print-chars.js'
, 'test_ca.pem'
, 'test_cert.pem'
, 'test_key.pem'
, 'throws_error.js'
, 'x.txt'
];
puts('readdirSync ' + fixturesDir);
var f = fs.readdirSync(fixturesDir);
p(f);
assert.deepEqual(files, f.sort());
puts("readdir " + fixturesDir);
fs.readdir(fixturesDir, function (err, f) {
if (err) {
puts("error");
got_error = true;
} else {
p(f);
assert.deepEqual(files, f.sort());
}
});
process.addListener("exit", function () {
assert.equal(false, got_error);
puts("exit");
});

5
test/mjsunit/test-sync-fileread.js

@ -1,5 +0,0 @@
process.mixin(require('./common'));
var fixture = path.join(__dirname, "fixtures/x.txt");
assert.equal("xyz\n", fs.readFileSync(fixture));

1
test/pummel/pummel.status

@ -0,0 +1 @@
prefix pummel

2
test/mjsunit/test-http-client-reconnect-bug.js → test/pummel/test-http-client-reconnect-bug.js

@ -1,4 +1,4 @@
process.mixin(require("./common")); process.mixin(require("../common"));
var tcp = require("tcp"), var tcp = require("tcp"),
sys = require("sys"), sys = require("sys"),

4
test/mjsunit/test-keep-alive.js → test/pummel/test-keep-alive.js

@ -1,12 +1,12 @@
// This test requires the program "ab" // This test requires the program "ab"
process.mixin(require("./common")); process.mixin(require("../common"));
http = require("http"); http = require("http");
sys = require("sys"); sys = require("sys");
PORT = 8891; PORT = 8891;
body = "hello world\n"; body = "hello world\n";
server = http.createServer(function (req, res) { server = http.createServer(function (req, res) {
res.writeHeader(200, { res.writeHead(200, {
"Content-Length": body.length, "Content-Length": body.length,
"Content-Type": "text/plain", "Content-Type": "text/plain",
}); });

8
test/mjsunit/test-multipart.js → test/pummel/test-multipart.js

@ -1,10 +1,10 @@
process.mixin(require("./common")); process.mixin(require("../common"));
var http = require("http"), var http = require("http"),
multipart = require("multipart"), multipart = require("multipart"),
sys = require("sys"), sys = require("sys"),
PORT = 8222, PORT = 8222,
fixture = require("./fixtures/multipart"), fixture = require("../fixtures/multipart"),
events = require("events"), events = require("events"),
testPart = function (expect, part) { testPart = function (expect, part) {
if (!expect) { if (!expect) {
@ -77,12 +77,12 @@ var server = http.createServer(function (req, res) {
} }
mp.addListener("error", function (er) { mp.addListener("error", function (er) {
sys.puts("!! error occurred"); sys.puts("!! error occurred");
res.writeHeader(400, {}); res.writeHead(400, {});
res.write("bad"); res.write("bad");
res.close(); res.close();
}); });
mp.addListener("complete", function () { mp.addListener("complete", function () {
res.writeHeader(200, {}); res.writeHead(200, {});
res.write("ok"); res.write("ok");
res.close(); res.close();
}); });

Some files were not shown because too many files changed in this diff

Loading…
Cancel
Save