diff --git a/Makefile b/Makefile index 2776d42507..67c56e2d28 100644 --- a/Makefile +++ b/Makefile @@ -24,6 +24,15 @@ test-all: all test-debug: all 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 build/default/node benchmark/run.js diff --git a/benchmark/http_simple.js b/benchmark/http_simple.js index 1d758b0328..8bfc097244 100644 --- a/benchmark/http_simple.js +++ b/benchmark/http_simple.js @@ -47,7 +47,7 @@ http.createServer(function (req, res) { var content_length = body.length.toString(); - res.writeHeader( status + res.writeHead( status , { "Content-Type": "text/plain" , "Content-Length": content_length } diff --git a/benchmark/static_http_server.js b/benchmark/static_http_server.js index 5bc48120f6..5b4f220ba8 100644 --- a/benchmark/static_http_server.js +++ b/benchmark/static_http_server.js @@ -16,7 +16,7 @@ for (var i = 0; i < bytes; i++) { } var server = http.createServer(function (req, res) { - res.writeHeader(200, { + res.writeHead(200, { "Content-Type": "text/plain", "Content-Length": body.length }); diff --git a/deps/evcom/evcom.c b/deps/evcom/evcom.c index 0f48ab0812..1ee02a1f0a 100644 --- a/deps/evcom/evcom.c +++ b/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); + // 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); if (stream->on_close) stream->on_close(stream); diff --git a/deps/v8/ChangeLog b/deps/v8/ChangeLog index 8d4cd22339..339fd18f59 100644 --- a/deps/v8/ChangeLog +++ b/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 [ES5] Implemented Object.defineProperty. diff --git a/deps/v8/src/SConscript b/deps/v8/src/SConscript index 1a81cc73ca..73de193ad5 100755 --- a/deps/v8/src/SConscript +++ b/deps/v8/src/SConscript @@ -57,7 +57,6 @@ SOURCES = { disassembler.cc execution.cc factory.cc - fast-codegen.cc flags.cc frame-element.cc frames.cc @@ -109,6 +108,7 @@ SOURCES = { zone.cc """), 'arch:arm': Split(""" + fast-codegen.cc arm/builtins-arm.cc arm/codegen-arm.cc arm/constants-arm.cc @@ -133,6 +133,7 @@ SOURCES = { arm/assembler-thumb2.cc """), 'arch:mips': Split(""" + fast-codegen.cc mips/assembler-mips.cc mips/builtins-mips.cc mips/codegen-mips.cc @@ -169,6 +170,7 @@ SOURCES = { ia32/virtual-frame-ia32.cc """), 'arch:x64': Split(""" + fast-codegen.cc x64/assembler-x64.cc x64/builtins-x64.cc x64/codegen-x64.cc diff --git a/deps/v8/src/arm/codegen-arm.cc b/deps/v8/src/arm/codegen-arm.cc index 046d7b95b1..95c50f262f 100644 --- a/deps/v8/src/arm/codegen-arm.cc +++ b/deps/v8/src/arm/codegen-arm.cc @@ -142,7 +142,7 @@ Scope* CodeGenerator::scope() { return info_->function()->scope(); } // r1: called JS function // cp: callee's context -void CodeGenerator::Generate(CompilationInfo* info, Mode mode) { +void CodeGenerator::Generate(CompilationInfo* info) { // Record the position for debugging purposes. CodeForFunctionPosition(info->function()); @@ -174,7 +174,7 @@ void CodeGenerator::Generate(CompilationInfo* info, Mode mode) { } #endif - if (mode == PRIMARY) { + if (info->mode() == CompilationInfo::PRIMARY) { frame_->Enter(); // tos: code slot @@ -277,6 +277,12 @@ void CodeGenerator::Generate(CompilationInfo* info, Mode mode) { frame_->Adjust(4); allocator_->Unuse(r1); allocator_->Unuse(lr); + + // Bind all the bailout labels to the beginning of the function. + List* 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 @@ -3420,6 +3426,25 @@ void CodeGenerator::GenerateIsArray(ZoneList* args) { } +void CodeGenerator::GenerateIsRegExp(ZoneList* 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* args) { // This generates a fast version of: // (typeof(arg) === 'object' || %_ClassOf(arg) == 'RegExp') diff --git a/deps/v8/src/arm/codegen-arm.h b/deps/v8/src/arm/codegen-arm.h index 10e28f4110..1a2e5525a2 100644 --- a/deps/v8/src/arm/codegen-arm.h +++ b/deps/v8/src/arm/codegen-arm.h @@ -150,15 +150,6 @@ class CodeGenState BASE_EMBEDDED { class CodeGenerator: public AstVisitor { 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 // be called by compiler.cc. static Handle MakeCode(CompilationInfo* info); @@ -244,7 +235,7 @@ class CodeGenerator: public AstVisitor { inline void VisitStatementsAndSpill(ZoneList* statements); // Main code generation function - void Generate(CompilationInfo* info, Mode mode); + void Generate(CompilationInfo* info); // The following are used by class Reference. void LoadReference(Reference* ref); @@ -359,6 +350,7 @@ class CodeGenerator: public AstVisitor { void GenerateIsSmi(ZoneList* args); void GenerateIsNonNegativeSmi(ZoneList* args); void GenerateIsArray(ZoneList* args); + void GenerateIsRegExp(ZoneList* args); void GenerateIsObject(ZoneList* args); void GenerateIsFunction(ZoneList* args); void GenerateIsUndetectableObject(ZoneList* args); diff --git a/deps/v8/src/arm/fast-codegen-arm.cc b/deps/v8/src/arm/fast-codegen-arm.cc index a07b0d2dcb..aa7128fcae 100644 --- a/deps/v8/src/arm/fast-codegen-arm.cc +++ b/deps/v8/src/arm/fast-codegen-arm.cc @@ -148,17 +148,25 @@ void FastCodeGenerator::EmitBitOr() { if (!destination().is(no_reg)) { __ 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 { - // Preserve the destination operand in a scratch register in case of - // bailout. - __ mov(scratch0(), destination()); - __ orr(destination(), accumulator1(), Operand(accumulator0())); - __ BranchOnNotSmi(destination(), bailout()); + // Left is in accumulator1, right in accumulator0. + if (destination().is(accumulator0())) { + __ mov(scratch0(), accumulator0()); + __ orr(destination(), accumulator1(), Operand(accumulator1())); + 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 @@ -179,6 +187,7 @@ void FastCodeGenerator::Generate(CompilationInfo* compilation_info) { // Note that we keep a live register reference to cp (context) at // this point. + Label* bailout_to_beginning = info()->AddBailout(); // Receiver (this) is allocated to a fixed register. if (info()->has_this_properties()) { Comment cmnt(masm(), ";; MapCheck(this)"); @@ -189,7 +198,7 @@ void FastCodeGenerator::Generate(CompilationInfo* compilation_info) { Handle object = Handle::cast(info()->receiver()); Handle map(object->map()); 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 @@ -202,7 +211,7 @@ void FastCodeGenerator::Generate(CompilationInfo* compilation_info) { ASSERT(info()->has_global_object()); Handle map(info()->global_object()->map()); __ ldr(scratch0(), CodeGenerator::GlobalObject()); - __ CheckMap(scratch0(), scratch1(), map, bailout(), true); + __ CheckMap(scratch0(), scratch1(), map, bailout_to_beginning, true); } VisitStatements(function()->body()); @@ -217,8 +226,6 @@ void FastCodeGenerator::Generate(CompilationInfo* compilation_info) { int32_t sp_delta = (scope()->num_parameters() + 1) * kPointerSize; __ add(sp, sp, Operand(sp_delta)); __ Jump(lr); - - __ bind(&bailout_); } diff --git a/deps/v8/src/ast.h b/deps/v8/src/ast.h index 8e717a6c8c..927a9f5035 100644 --- a/deps/v8/src/ast.h +++ b/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 // modification, are permitted provided that the following conditions are // met: @@ -199,6 +199,10 @@ class Expression: public AstNode { // evaluated. 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 // statement. This is used to transform postfix increments to // (faster) prefix increments. @@ -738,6 +742,7 @@ class Literal: public Expression { } virtual bool IsLeaf() { return true; } + virtual bool IsTrivial() { return true; } // Identity testers. 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(); } + // Reading from a mutable variable is a side effect, but 'this' is + // immutable. + virtual bool IsTrivial() { return is_this(); } + bool IsVariable(Handle n) { return !is_this() && name().is_identical_to(n); } diff --git a/deps/v8/src/codegen.cc b/deps/v8/src/codegen.cc index 01ee6d0720..dbd1100d9e 100644 --- a/deps/v8/src/codegen.cc +++ b/deps/v8/src/codegen.cc @@ -248,7 +248,7 @@ Handle CodeGenerator::MakeCode(CompilationInfo* info) { CodeGenerator cgen(&masm); CodeGeneratorScope scope(&cgen); live_edit_tracker.RecordFunctionScope(info->function()->scope()); - cgen.Generate(info, PRIMARY); + cgen.Generate(info); if (cgen.HasStackOverflow()) { ASSERT(!Top::has_pending_exception()); return Handle::null(); @@ -360,6 +360,7 @@ CodeGenerator::InlineRuntimeLUT CodeGenerator::kInlineRuntimeLUT[] = { {&CodeGenerator::GenerateIsSmi, "_IsSmi"}, {&CodeGenerator::GenerateIsNonNegativeSmi, "_IsNonNegativeSmi"}, {&CodeGenerator::GenerateIsArray, "_IsArray"}, + {&CodeGenerator::GenerateIsRegExp, "_IsRegExp"}, {&CodeGenerator::GenerateIsConstructCall, "_IsConstructCall"}, {&CodeGenerator::GenerateArgumentsLength, "_ArgumentsLength"}, {&CodeGenerator::GenerateArgumentsAccess, "_Arguments"}, diff --git a/deps/v8/src/codegen.h b/deps/v8/src/codegen.h index 5c10cb62cf..8dcde84bbd 100644 --- a/deps/v8/src/codegen.h +++ b/deps/v8/src/codegen.h @@ -518,14 +518,14 @@ class CallFunctionStub: public CodeStub { } #endif - // Minor key encoding in 31 bits AAAAAAAAAAAAAAAAAAAAAFI A(rgs)F(lag)I(nloop). + // Minor key encoding in 32 bits with Bitfield . class InLoopBits: public BitField {}; class FlagBits: public BitField {}; - class ArgcBits: public BitField {}; + class ArgcBits: public BitField {}; Major MajorKey() { return CallFunction; } 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_) | FlagBits::encode(flags_) | ArgcBits::encode(argc_); diff --git a/deps/v8/src/compiler.h b/deps/v8/src/compiler.h index 6ee2246b29..f01889d0a1 100644 --- a/deps/v8/src/compiler.h +++ b/deps/v8/src/compiler.h @@ -41,6 +41,37 @@ namespace internal { // is constructed based on the resources available at compile-time. class CompilationInfo BASE_EMBEDDED { 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. CompilationInfo(Handle closure, int loop_nesting, @@ -117,9 +148,13 @@ class CompilationInfo BASE_EMBEDDED { int loop_nesting() { return loop_nesting_; } bool has_receiver() { return !receiver_.is_null(); } Handle receiver() { return receiver_; } + List* 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. + Mode mode() { return mode_; } + void set_mode(Mode mode) { mode_ = mode; } + bool has_this_properties() { return has_this_properties_; } void set_has_this_properties(bool flag) { has_this_properties_ = flag; } @@ -137,8 +172,19 @@ class CompilationInfo BASE_EMBEDDED { // Derived accessors. 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: void Initialize() { + mode_ = PRIMARY; has_this_properties_ = false; has_globals_ = false; } @@ -148,6 +194,7 @@ class CompilationInfo BASE_EMBEDDED { Handle