diff options
author | Ryan Dahl <ry@tinyclouds.org> | 2010-02-23 17:52:50 -0800 |
---|---|---|
committer | Ryan Dahl <ry@tinyclouds.org> | 2010-02-23 17:52:50 -0800 |
commit | b80bdda14e2213e928d3dc3895b3c680d2ea674a (patch) | |
tree | 54f55fe0d2f2cf75cf1026e7dd01ca13d67f4254 /deps/v8/src | |
parent | df1c1e593f8aac17e6edd8aa1fe278893b2e5a39 (diff) | |
download | node-b80bdda14e2213e928d3dc3895b3c680d2ea674a.tar.gz |
Upgrade V8 to 2.1.2
Diffstat (limited to 'deps/v8/src')
43 files changed, 1506 insertions, 385 deletions
diff --git a/deps/v8/src/SConscript b/deps/v8/src/SConscript index 1a81cc73c..73de193ad 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 046d7b95b..95c50f262 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<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 @@ -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) { // 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 10e28f411..1a2e5525a 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<Code> MakeCode(CompilationInfo* info); @@ -244,7 +235,7 @@ class CodeGenerator: public AstVisitor { inline void VisitStatementsAndSpill(ZoneList<Statement*>* 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<Expression*>* args); void GenerateIsNonNegativeSmi(ZoneList<Expression*>* args); void GenerateIsArray(ZoneList<Expression*>* args); + void GenerateIsRegExp(ZoneList<Expression*>* args); void GenerateIsObject(ZoneList<Expression*>* args); void GenerateIsFunction(ZoneList<Expression*>* args); void GenerateIsUndetectableObject(ZoneList<Expression*>* args); diff --git a/deps/v8/src/arm/fast-codegen-arm.cc b/deps/v8/src/arm/fast-codegen-arm.cc index a07b0d2dc..aa7128fca 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<HeapObject> object = Handle<HeapObject>::cast(info()->receiver()); Handle<Map> 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> 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 8e717a6c8..927a9f503 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<String> n) { return !is_this() && name().is_identical_to(n); } diff --git a/deps/v8/src/codegen.cc b/deps/v8/src/codegen.cc index 01ee6d072..dbd1100d9 100644 --- a/deps/v8/src/codegen.cc +++ b/deps/v8/src/codegen.cc @@ -248,7 +248,7 @@ Handle<Code> 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<Code>::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 5c10cb62c..8dcde84bb 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 <Type, shift, size>. class InLoopBits: public BitField<InLoopFlag, 0, 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; } 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 6ee2246b2..f01889d0a 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<JSFunction> 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<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. + 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<Script> script_; FunctionLiteral* function_; + Mode mode_; bool is_eval_; int loop_nesting_; @@ -157,6 +204,10 @@ class CompilationInfo BASE_EMBEDDED { bool has_this_properties_; bool has_globals_; + // An ordered list of bailout points encountered during fast-path + // compilation. + List<Bailout*> bailouts_; + DISALLOW_COPY_AND_ASSIGN(CompilationInfo); }; diff --git a/deps/v8/src/debug-delay.js b/deps/v8/src/debug-delay.js index 754ac5d04..55c25a926 100644 --- a/deps/v8/src/debug-delay.js +++ b/deps/v8/src/debug-delay.js @@ -1202,11 +1202,16 @@ DebugCommandProcessor.prototype.processDebugJSONRequest = function(json_request) throw new Error('Command not specified'); } - // TODO(yurys): remove request.arguments.compactFormat check once - // ChromeDevTools are switched to 'inlineRefs' - if (request.arguments && (request.arguments.inlineRefs || - request.arguments.compactFormat)) { - response.setOption('inlineRefs', true); + if (request.arguments) { + var args = request.arguments; + // TODO(yurys): remove request.arguments.compactFormat check once + // ChromeDevTools are switched to 'inlineRefs' + if (args.inlineRefs || args.compactFormat) { + response.setOption('inlineRefs', true); + } + if (!IS_UNDEFINED(args.maxStringLength)) { + response.setOption('maxStringLength', args.maxStringLength); + } } if (request.command == 'continue') { diff --git a/deps/v8/src/fast-codegen.cc b/deps/v8/src/fast-codegen.cc index ecd26527c..602d6b88c 100644 --- a/deps/v8/src/fast-codegen.cc +++ b/deps/v8/src/fast-codegen.cc @@ -456,7 +456,8 @@ Handle<Code> FastCodeGenerator::MakeCode(CompilationInfo* info) { // macro assembler. CodeGenerator cgen(&masm); CodeGeneratorScope scope(&cgen); - cgen.Generate(info, CodeGenerator::SECONDARY); + info->set_mode(CompilationInfo::SECONDARY); + cgen.Generate(info); if (cgen.HasStackOverflow()) { ASSERT(!Top::has_pending_exception()); return Handle<Code>::null(); diff --git a/deps/v8/src/fast-codegen.h b/deps/v8/src/fast-codegen.h index 96ee5dddb..e96daf65b 100644 --- a/deps/v8/src/fast-codegen.h +++ b/deps/v8/src/fast-codegen.h @@ -28,10 +28,15 @@ #ifndef 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 "ast.h" #include "compiler.h" +#include "list.h" namespace v8 { namespace internal { @@ -76,7 +81,6 @@ class FastCodeGenerator: public AstVisitor { private: MacroAssembler* masm() { return masm_; } CompilationInfo* info() { return info_; } - Label* bailout() { return &bailout_; } Register destination() { return destination_; } void set_destination(Register reg) { destination_ = reg; } @@ -142,7 +146,6 @@ class FastCodeGenerator: public AstVisitor { MacroAssembler* masm_; CompilationInfo* info_; - Label bailout_; Register destination_; uint32_t smi_bits_; @@ -152,4 +155,6 @@ class FastCodeGenerator: public AstVisitor { } } // namespace v8::internal +#endif // V8_TARGET_ARCH_IA32 + #endif // V8_FAST_CODEGEN_H_ diff --git a/deps/v8/src/frame-element.h b/deps/v8/src/frame-element.h index 3ae6d303f..5762814ff 100644 --- a/deps/v8/src/frame-element.h +++ b/deps/v8/src/frame-element.h @@ -65,6 +65,9 @@ class FrameElement BASE_EMBEDDED { } 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::encode(info); } @@ -250,7 +253,7 @@ class FrameElement BASE_EMBEDDED { class CopiedField: public BitField<bool, 3, 1> {}; class SyncedField: public BitField<bool, 4, 1> {}; 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; }; diff --git a/deps/v8/src/heap.cc b/deps/v8/src/heap.cc index fc4e666b9..cfb786ac7 100644 --- a/deps/v8/src/heap.cc +++ b/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. uintptr_t addr_hash = 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); } diff --git a/deps/v8/src/heap.h b/deps/v8/src/heap.h index 22ab875bb..3f34df72b 100644 --- a/deps/v8/src/heap.h +++ b/deps/v8/src/heap.h @@ -1383,9 +1383,9 @@ class DescriptorLookupCache { private: static int Hash(DescriptorArray* array, String* name) { // 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; - uintptr_t name_hash = + uint32_t name_hash = static_cast<uint32_t>(reinterpret_cast<uintptr_t>(name)) >> 2; return (array_hash ^ name_hash) % kLength; } diff --git a/deps/v8/src/ia32/codegen-ia32.cc b/deps/v8/src/ia32/codegen-ia32.cc index 7ec3ff4c5..85d8ed9bc 100644 --- a/deps/v8/src/ia32/codegen-ia32.cc +++ b/deps/v8/src/ia32/codegen-ia32.cc @@ -125,7 +125,7 @@ Scope* CodeGenerator::scope() { return info_->function()->scope(); } // edi: called JS function // esi: callee's context -void CodeGenerator::Generate(CompilationInfo* info, Mode mode) { +void CodeGenerator::Generate(CompilationInfo* info) { // Record the position for debugging purposes. CodeForFunctionPosition(info->function()); @@ -164,7 +164,7 @@ void CodeGenerator::Generate(CompilationInfo* info, Mode mode) { // esi: callee's context allocator_->Initialize(); - if (mode == PRIMARY) { + if (info->mode() == CompilationInfo::PRIMARY) { frame_->Enter(); // Allocate space for locals and initialize them. @@ -255,6 +255,12 @@ void CodeGenerator::Generate(CompilationInfo* info, Mode mode) { // frame to match this state. frame_->Adjust(3); 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 @@ -689,6 +695,11 @@ void CodeGenerator::LoadReference(Reference* ref) { // The expression is a variable proxy that does not rewrite to a // property. Global variables are treated as named property references. 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(); ref->set_type(Reference::NAMED); } else { @@ -4307,6 +4318,10 @@ Result CodeGenerator::LoadFromGlobalSlotCheckExtensions( // All extension objects were empty and it is safe to use a global // 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(); frame_->Push(slot->var()->name()); RelocInfo::Mode mode = (typeof_state == INSIDE_TYPEOF) @@ -4592,8 +4607,8 @@ void CodeGenerator::VisitObjectLiteral(ObjectLiteral* node) { // Duplicate the object as the IC receiver. frame_->Dup(); Load(property->value()); - frame_->Push(key); - Result ignored = frame_->CallStoreIC(); + Result dummy = frame_->CallStoreIC(Handle<String>::cast(key), false); + dummy.Unuse(); break; } // Fall through @@ -4762,26 +4777,33 @@ void CodeGenerator::EmitNamedPropertyAssignment(Assignment* node) { Property* prop = node->target()->AsProperty(); 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; + bool is_trivial_receiver = false; if (var != NULL) { name = var->name(); - LoadGlobal(); } else { Literal* lit = prop->key()->AsLiteral(); - ASSERT(lit != NULL); + ASSERT_NOT_NULL(lit); 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()) { + ASSERT_EQ(NULL, var); // Change to slow case in the beginning of an initialization block to // 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); } - 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 // converted back to fast case after the assignment. frame()->Dup(); @@ -4789,7 +4811,16 @@ void CodeGenerator::EmitNamedPropertyAssignment(Assignment* node) { // Evaluate the right-hand side. 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); frame()->Push(&value); Load(node->value()); @@ -4806,23 +4837,34 @@ void CodeGenerator::EmitNamedPropertyAssignment(Assignment* node) { // Perform the assignment. It is safe to ignore constants here. 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()); - Result answer = EmitNamedStore(name); + bool is_contextual = (var != NULL); + Result answer = EmitNamedStore(name, is_contextual); frame()->Push(&answer); if (node->ends_initialization_block()) { - // The argument to the runtime call is the extra copy of the receiver, - // which is below the value of the assignment. Swap the receiver and - // the value of the assignment expression. - Result result = frame()->Pop(); - Result receiver = frame()->Pop(); - frame()->Push(&result); - frame()->Push(&receiver); + ASSERT_EQ(NULL, var); + // The argument to the runtime call is the receiver. + if (is_trivial_receiver) { + frame()->Push(prop->obj()); + } else { + // A copy of the receiver is below the value of the assignment. Swap + // 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); } - ASSERT(frame()->height() == original_height + 1); + ASSERT_EQ(frame()->height(), original_height + 1); } @@ -4832,7 +4874,7 @@ void CodeGenerator::EmitKeyedPropertyAssignment(Assignment* node) { #endif Comment cmnt(masm_, "[ Named Property Assignment"); Property* prop = node->target()->AsProperty(); - ASSERT(prop != NULL); + ASSERT_NOT_NULL(prop); // Evaluate the receiver subexpression. 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) { // This generates a fast version of: // (typeof(arg) === 'object' || %_ClassOf(arg) == 'RegExp') @@ -6347,13 +6408,10 @@ void CodeGenerator::VisitCompareOperation(CompareOperation* node) { __ movzx_b(temp.reg(), FieldOperand(temp.reg(), Map::kBitFieldOffset)); __ test(temp.reg(), Immediate(1 << Map::kIsUndetectable)); destination()->false_target()->Branch(not_zero); - __ mov(temp.reg(), FieldOperand(answer.reg(), HeapObject::kMapOffset)); - __ movzx_b(temp.reg(), - FieldOperand(temp.reg(), Map::kInstanceTypeOffset)); - __ cmp(temp.reg(), FIRST_NONSTRING_TYPE); + __ CmpObjectType(answer.reg(), FIRST_NONSTRING_TYPE, temp.reg()); temp.Unuse(); answer.Unuse(); - destination()->Split(less); + destination()->Split(below); } else if (check->Equals(Heap::boolean_symbol())) { __ 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 - int original_height = frame()->height(); + int expected_height = frame()->height() - (is_contextual ? 1 : 2); #endif - frame()->Push(name); - Result result = frame()->CallStoreIC(); + Result result = frame()->CallStoreIC(name, is_contextual); - ASSERT(frame()->height() == original_height - 2); + ASSERT_EQ(expected_height, frame()->height()); return result; } @@ -7058,7 +7115,7 @@ void Reference::SetValue(InitState init_state) { case NAMED: { Comment cmnt(masm, "[ Store to named Property"); - Result answer = cgen_->EmitNamedStore(GetName()); + Result answer = cgen_->EmitNamedStore(GetName(), false); cgen_->frame()->Push(&answer); set_unloaded(); break; diff --git a/deps/v8/src/ia32/codegen-ia32.h b/deps/v8/src/ia32/codegen-ia32.h index a6cb3164b..99dc340b6 100644 --- a/deps/v8/src/ia32/codegen-ia32.h +++ b/deps/v8/src/ia32/codegen-ia32.h @@ -294,15 +294,6 @@ enum ArgumentsAllocationMode { 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<Code> MakeCode(CompilationInfo* info); @@ -384,7 +375,7 @@ class CodeGenerator: public AstVisitor { void VisitStatementsAndSpill(ZoneList<Statement*>* statements); // 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 // 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. Result EmitNamedLoad(Handle<String> name, bool is_contextual); - // Reciever and value are passed on the frame and consumed. - Result EmitNamedStore(Handle<String> name); + // If the store is contextual, value is passed on the frame and consumed. + // 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. Result EmitKeyedLoad(); @@ -551,6 +543,7 @@ class CodeGenerator: public AstVisitor { void GenerateIsSmi(ZoneList<Expression*>* args); void GenerateIsNonNegativeSmi(ZoneList<Expression*>* args); void GenerateIsArray(ZoneList<Expression*>* args); + void GenerateIsRegExp(ZoneList<Expression*>* args); void GenerateIsObject(ZoneList<Expression*>* args); void GenerateIsFunction(ZoneList<Expression*>* args); void GenerateIsUndetectableObject(ZoneList<Expression*>* args); diff --git a/deps/v8/src/ia32/fast-codegen-ia32.cc b/deps/v8/src/ia32/fast-codegen-ia32.cc index 9bab75aa6..f1c250771 100644 --- a/deps/v8/src/ia32/fast-codegen-ia32.cc +++ b/deps/v8/src/ia32/fast-codegen-ia32.cc @@ -29,12 +29,445 @@ #include "codegen-inl.h" #include "fast-codegen.h" +#include "data-flow.h" +#include "scopes.h" namespace v8 { 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()) +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::accumulator1() { return edx; } Register FastCodeGenerator::scratch0() { return ecx; } @@ -155,20 +588,27 @@ void FastCodeGenerator::EmitBitOr() { // commutative. __ 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 { - // Preserve the destination operand in a scratch register in case of - // bailout. - __ mov(scratch0(), destination()); - __ or_(destination(), Operand(other_accumulator(destination()))); - __ test(destination(), Immediate(kSmiTagMask)); - __ j(not_zero, bailout(), not_taken); + // Left is in accumulator1, right in accumulator0. + Label* bailout = NULL; + if (destination().is(accumulator0())) { + __ mov(scratch0(), accumulator0()); + __ or_(destination(), Operand(accumulator1())); // Or is commutative. + __ 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 @@ -191,6 +631,7 @@ void FastCodeGenerator::Generate(CompilationInfo* compilation_info) { // Note that we keep a live register reference to esi (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)"); @@ -201,7 +642,7 @@ void FastCodeGenerator::Generate(CompilationInfo* compilation_info) { Handle<HeapObject> object = Handle<HeapObject>::cast(info()->receiver()); Handle<Map> map(object->map()); 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 @@ -214,7 +655,7 @@ void FastCodeGenerator::Generate(CompilationInfo* compilation_info) { ASSERT(info()->has_global_object()); Handle<Map> map(info()->global_object()->map()); __ mov(scratch0(), CodeGenerator::GlobalObject()); - __ CheckMap(scratch0(), map, bailout(), true); + __ CheckMap(scratch0(), map, bailout_to_beginning, true); } VisitStatements(function()->body()); @@ -227,11 +668,286 @@ void FastCodeGenerator::Generate(CompilationInfo* compilation_info) { __ mov(esp, ebp); __ pop(ebp); __ 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 __ diff --git a/deps/v8/src/ia32/fast-codegen-ia32.h b/deps/v8/src/ia32/fast-codegen-ia32.h new file mode 100644 index 000000000..e0851afe0 --- /dev/null +++ b/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_ diff --git a/deps/v8/src/ia32/virtual-frame-ia32.cc b/deps/v8/src/ia32/virtual-frame-ia32.cc index d2485392f..7df028e94 100644 --- a/deps/v8/src/ia32/virtual-frame-ia32.cc +++ b/deps/v8/src/ia32/virtual-frame-ia32.cc @@ -948,47 +948,38 @@ Result VirtualFrame::CallKeyedLoadIC(RelocInfo::Mode mode) { } -Result VirtualFrame::CallStoreIC() { - // Name, value, and receiver are on top of the frame. The IC - // expects name in ecx, value in eax, and receiver in edx. +Result VirtualFrame::CallStoreIC(Handle<String> name, bool is_contextual) { + // Value and (if not contextual) receiver are on top of the frame. + // The IC expects name in ecx, value in eax, and receiver in edx. Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Initialize)); - Result name = Pop(); Result value = Pop(); - Result receiver = Pop(); - PrepareForCall(0, 0); + if (is_contextual) { + 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 (name.is_register() && (name.reg().is(edx) || name.reg().is(eax))) { - if (!is_used(ecx)) { - name.ToRegister(ecx); - } else if (!is_used(ebx)) { - name.ToRegister(ebx); - } else { - ASSERT(!is_used(edi)); // Only three results are live, so edi is free. - 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); + if (value.is_register() && value.reg().is(edx)) { + if (receiver.is_register() && receiver.reg().is(eax)) { + // Wrong registers. + __ xchg(eax, edx); + } else { + // Register eax is free for value, which frees edx for receiver. + value.ToRegister(eax); + receiver.ToRegister(edx); + } } else { - // Register eax is free for value, which frees edx for receiver. - value.ToRegister(eax); + // Register edx is free for receiver, which guarantees eax is free for + // value. 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. - name.ToRegister(ecx); - name.Unuse(); + __ mov(ecx, name); value.Unuse(); - receiver.Unuse(); 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 __ } } // namespace v8::internal diff --git a/deps/v8/src/ia32/virtual-frame-ia32.h b/deps/v8/src/ia32/virtual-frame-ia32.h index b078ba089..7be593cc5 100644 --- a/deps/v8/src/ia32/virtual-frame-ia32.h +++ b/deps/v8/src/ia32/virtual-frame-ia32.h @@ -339,12 +339,12 @@ class VirtualFrame: public ZoneObject { Result CallLoadIC(RelocInfo::Mode mode); // 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); - // Call store IC. Name, value, and receiver are found on top of the - // frame. Receiver is not dropped. - Result CallStoreIC(); + // Call store IC. If the load is contextual, value is found on top of the + // frame. If not, value and receiver are on the frame. Both are dropped. + Result CallStoreIC(Handle<String> name, bool is_contextual); // Call keyed store IC. Value, key, and receiver are found on top // of the frame. Key and receiver are not dropped. @@ -415,6 +415,10 @@ class VirtualFrame: public ZoneObject { 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 // 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). diff --git a/deps/v8/src/jump-target-inl.h b/deps/v8/src/jump-target-inl.h index dcd615eef..3cd9a8bde 100644 --- a/deps/v8/src/jump-target-inl.h +++ b/deps/v8/src/jump-target-inl.h @@ -42,7 +42,7 @@ void JumpTarget::InitializeEntryElement(int index, FrameElement* target) { } else if (target->is_copy()) { 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); } } diff --git a/deps/v8/src/jump-target.cc b/deps/v8/src/jump-target.cc index 66764e6a7..bce379a92 100644 --- a/deps/v8/src/jump-target.cc +++ b/deps/v8/src/jump-target.cc @@ -105,7 +105,6 @@ void JumpTarget::ComputeEntryFrame() { FrameElement* other = &reaching_frames_[j]->elements_[i]; if (element != NULL && !element->is_copy()) { ASSERT(other != NULL); - ASSERT(!other->is_copy()); // We overwrite the number information of one of the incoming frames. // This is safe because we only use the frame for emitting merge code. // 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 are initially recorded as if in memory. if (target != NULL) { - ASSERT(!target->is_copy()); // These initial elements are never copies. entry_frame_->elements_[index] = *target; InitializeEntryElement(index, target); } diff --git a/deps/v8/src/macros.py b/deps/v8/src/macros.py index c160b4916..ccc2037f2 100644 --- a/deps/v8/src/macros.py +++ b/deps/v8/src/macros.py @@ -74,6 +74,10 @@ const kYearShift = 9; const kMonthShift = 5; # 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_OR_UNDEFINED(arg) = (arg == null); 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_ARRAY(arg) = (%_IsArray(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_NUMBER_WRAPPER(arg) = (%_ClassOf(arg) === 'Number'); 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. macro NUMBER_IS_NAN(arg) = (!%_IsSmi(%IS_VAR(arg)) && !(arg == 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_UINT32(arg) = (arg >>> 0); +macro TO_INTEGER(arg) = (%_IsSmi(%IS_VAR(arg)) ? arg : ToInteger(arg)); +macro TO_INT32(arg) = (%_IsSmi(%IS_VAR(arg)) ? 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. python macro CHAR_CODE(str) = ord(str[1]); diff --git a/deps/v8/src/mips/codegen-mips.cc b/deps/v8/src/mips/codegen-mips.cc index 5a27c2864..2de45f67f 100644 --- a/deps/v8/src/mips/codegen-mips.cc +++ b/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) { 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) { UNIMPLEMENTED_MIPS(); } @@ -498,4 +508,3 @@ int CompareStub::MinorKey() { #undef __ } } // namespace v8::internal - diff --git a/deps/v8/src/mips/codegen-mips.h b/deps/v8/src/mips/codegen-mips.h index 05138bc64..147b8724e 100644 --- a/deps/v8/src/mips/codegen-mips.h +++ b/deps/v8/src/mips/codegen-mips.h @@ -210,6 +210,7 @@ class CodeGenerator: public AstVisitor { void GenerateIsSmi(ZoneList<Expression*>* args); void GenerateIsNonNegativeSmi(ZoneList<Expression*>* args); void GenerateIsArray(ZoneList<Expression*>* args); + void GenerateIsRegExp(ZoneList<Expression*>* args); // Support for construct call checks. void GenerateIsConstructCall(ZoneList<Expression*>* args); @@ -241,6 +242,8 @@ class CodeGenerator: public AstVisitor { void GenerateSubString(ZoneList<Expression*>* args); void GenerateStringCompare(ZoneList<Expression*>* args); void GenerateRegExpExec(ZoneList<Expression*>* args); + void GenerateNumberToString(ZoneList<Expression*>* args); + // Fast support for Math.sin and Math.cos. inline void GenerateMathSin(ZoneList<Expression*>* args); @@ -308,4 +311,3 @@ class CodeGenerator: public AstVisitor { } } // namespace v8::internal #endif // V8_MIPS_CODEGEN_MIPS_H_ - diff --git a/deps/v8/src/mirror-delay.js b/deps/v8/src/mirror-delay.js index e1bedfdff..7c743ec2c 100644 --- a/deps/v8/src/mirror-delay.js +++ b/deps/v8/src/mirror-delay.js @@ -553,14 +553,16 @@ StringMirror.prototype.length = function() { return this.value_.length; }; - -StringMirror.prototype.toText = function() { - if (this.length() > kMaxProtocolStringLength) { - return this.value_.substring(0, kMaxProtocolStringLength) + +StringMirror.prototype.getTruncatedValue = function(maxLength) { + if (maxLength != -1 && this.length() > maxLength) { + return this.value_.substring(0, maxLength) + '... (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) { // If this mirror is already in the list just return. for (var i = 0; i < this.mirrors_.length; i++) { @@ -1987,8 +1998,7 @@ JSONProtocolSerializer.prototype.serializeReferenceWithDisplayData_ = o.value = mirror.value(); break; case STRING_TYPE: - // Limit string length. - o.value = mirror.toText(); + o.value = mirror.getTruncatedValue(this.maxStringLength_()); break; case FUNCTION_TYPE: o.name = mirror.name(); @@ -2052,11 +2062,12 @@ JSONProtocolSerializer.prototype.serialize_ = function(mirror, reference, case STRING_TYPE: // String values might have their value cropped to keep down size. - if (mirror.length() > kMaxProtocolStringLength) { - var str = mirror.value().substring(0, kMaxProtocolStringLength); + if (this.maxStringLength_() != -1 && + mirror.length() > this.maxStringLength_()) { + var str = mirror.getTruncatedValue(this.maxStringLength_()); content.value = str; content.fromIndex = 0; - content.toIndex = kMaxProtocolStringLength; + content.toIndex = this.maxStringLength_(); } else { content.value = mirror.value(); } diff --git a/deps/v8/src/objects.h b/deps/v8/src/objects.h index 3ed0a705e..75338920c 100644 --- a/deps/v8/src/objects.h +++ b/deps/v8/src/objects.h @@ -179,7 +179,7 @@ class PropertyDetails BASE_EMBEDDED { class TypeField: public BitField<PropertyType, 0, 3> {}; class AttributesField: public BitField<PropertyAttributes, 3, 3> {}; 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; private: diff --git a/deps/v8/src/register-allocator.h b/deps/v8/src/register-allocator.h index 4ec0bb4db..747200a05 100644 --- a/deps/v8/src/register-allocator.h +++ b/deps/v8/src/register-allocator.h @@ -141,7 +141,7 @@ class Result BASE_EMBEDDED { class TypeField: public BitField<Type, 0, 2> {}; 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; diff --git a/deps/v8/src/runtime.cc b/deps/v8/src/runtime.cc index 38e332b24..6459aa78d 100644 --- a/deps/v8/src/runtime.cc +++ b/deps/v8/src/runtime.cc @@ -2276,6 +2276,20 @@ static int SingleCharIndexOf(Vector<const schar> string, 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. // On return, if "complete" is set to true, the return value is the // 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 // really is a non-ASCII character in the needle and bail out if there // is. - if (sizeof(pchar) > 1 && sizeof(schar) == 1) { + if (sizeof(schar) == 1 && sizeof(pchar) > 1) { for (int i = 0; i < pat.length(); i++) { uc16 c = pat[i]; 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) { - NoHandleAllocation ha; + HandleScope scope; // create a new handle scope ASSERT(args.length() == 3); - CONVERT_CHECKED(String, sub, args[0]); - CONVERT_CHECKED(String, pat, args[1]); - Object* index = args[2]; - - sub->TryFlattenIfNotFlat(); - pat->TryFlattenIfNotFlat(); + CONVERT_ARG_CHECKED(String, sub, 0); + CONVERT_ARG_CHECKED(String, pat, 1); + Object* index = args[2]; uint32_t start_index; 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(); - if (start_index + pattern_length > sub_length) { - start_index = sub_length - pattern_length; + if (start_index + pat_length > sub_length) { + start_index = sub_length - pat_length; } - for (int i = start_index; i >= 0; i--) { - bool found = true; - for (uint32_t j = 0; j < pattern_length; j++) { - if (sub->Get(i + j) != pat->Get(j)) { - found = false; - break; + if (pat_length == 0) { + return Smi::FromInt(start_index); + } + + if (!sub->IsFlat()) { + 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); } diff --git a/deps/v8/src/runtime.js b/deps/v8/src/runtime.js index 231763cbc..e9d984877 100644 --- a/deps/v8/src/runtime.js +++ b/deps/v8/src/runtime.js @@ -529,6 +529,13 @@ function ToString(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. function ToObject(x) { diff --git a/deps/v8/src/scopeinfo.cc b/deps/v8/src/scopeinfo.cc index 8b989d7a3..de1841b02 100644 --- a/deps/v8/src/scopeinfo.cc +++ b/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. uintptr_t addr_hash = 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); } diff --git a/deps/v8/src/serialize.cc b/deps/v8/src/serialize.cc index bc934fb5a..0819ec224 100644 --- a/deps/v8/src/serialize.cc +++ b/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; for (int shift = max_shift; shift > 0; shift -= 7) { 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 diff --git a/deps/v8/src/spaces-inl.h b/deps/v8/src/spaces-inl.h index 4fd8a6c8d..72f83050b 100644 --- a/deps/v8/src/spaces-inl.h +++ b/deps/v8/src/spaces-inl.h @@ -183,7 +183,7 @@ Page* MemoryAllocator::GetNextPage(Page* p) { int MemoryAllocator::GetChunkId(Page* p) { ASSERT(p->is_valid()); - return p->opaque_header & Page::kPageAlignmentMask; + return static_cast<int>(p->opaque_header & Page::kPageAlignmentMask); } diff --git a/deps/v8/src/string.js b/deps/v8/src/string.js index ba01ed67e..49f403de7 100644 --- a/deps/v8/src/string.js +++ b/deps/v8/src/string.js @@ -34,7 +34,7 @@ // Set the String function and constructor. %SetCode($String, function(x) { - var value = %_ArgumentsLength() == 0 ? '' : ToString(x); + var value = %_ArgumentsLength() == 0 ? '' : TO_STRING_INLINE(x); if (%_IsConstructCall()) { %_SetValueOf(this, value); } else { @@ -64,7 +64,7 @@ function StringValueOf() { function StringCharAt(pos) { var char_code = %_FastCharCodeAt(this, pos); if (!%_IsSmi(char_code)) { - var subject = ToString(this); + var subject = TO_STRING_INLINE(this); var index = TO_INTEGER(pos); if (index >= subject.length || index < 0) return ""; char_code = %StringCharCodeAt(subject, index); @@ -79,7 +79,7 @@ function StringCharCodeAt(pos) { if (%_IsSmi(fast_answer)) { return fast_answer; } - var subject = ToString(this); + var subject = TO_STRING_INLINE(this); var index = TO_INTEGER(pos); return %StringCharCodeAt(subject, index); } @@ -88,7 +88,7 @@ function StringCharCodeAt(pos) { // ECMA-262, section 15.5.4.6 function StringConcat() { var len = %_ArgumentsLength(); - var this_as_string = IS_STRING(this) ? this : ToString(this); + var this_as_string = TO_STRING_INLINE(this); if (len === 1) { return this_as_string + %_Arguments(0); } @@ -96,7 +96,7 @@ function StringConcat() { parts[0] = this_as_string; for (var i = 0; i < len; 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, ""); } @@ -107,8 +107,8 @@ function StringConcat() { // ECMA-262 section 15.5.4.7 function StringIndexOf(searchString /* position */) { // length == 1 - var subject_str = ToString(this); - var pattern_str = ToString(searchString); + var subject_str = TO_STRING_INLINE(this); + var pattern_str = TO_STRING_INLINE(searchString); var subject_str_len = subject_str.length; var pattern_str_len = pattern_str.length; var index = 0; @@ -125,9 +125,9 @@ function StringIndexOf(searchString /* position */) { // length == 1 // ECMA-262 section 15.5.4.8 function StringLastIndexOf(searchString /* position */) { // length == 1 - var sub = ToString(this); + var sub = TO_STRING_INLINE(this); var subLength = sub.length; - var pat = ToString(searchString); + var pat = TO_STRING_INLINE(searchString); var patLength = pat.length; var index = subLength - patLength; if (%_ArgumentsLength() > 1) { @@ -156,8 +156,8 @@ function StringLastIndexOf(searchString /* position */) { // length == 1 function StringLocaleCompare(other) { if (%_ArgumentsLength() === 0) return 0; - var this_str = ToString(this); - var other_str = ToString(other); + var this_str = TO_STRING_INLINE(this); + var other_str = TO_STRING_INLINE(other); return %StringLocaleCompare(this_str, other_str); } @@ -165,7 +165,7 @@ function StringLocaleCompare(other) { // ECMA-262 section 15.5.4.10 function StringMatch(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); %_Log('regexp', 'regexp-match,%0S,%1r', [subject, regexp]); @@ -200,7 +200,7 @@ var reusableMatchInfo = [2, "", "", -1, -1]; // ECMA-262, section 15.5.4.11 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. if (IS_REGEXP(search)) { @@ -213,7 +213,7 @@ function StringReplace(search, replace) { } // 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); if (start < 0) return subject; var end = start + search.length; @@ -228,7 +228,7 @@ function StringReplace(search, replace) { } else { reusableMatchInfo[CAPTURE0] = start; reusableMatchInfo[CAPTURE1] = end; - if (!IS_STRING(replace)) replace = ToString(replace); + replace = TO_STRING_INLINE(replace); ExpandReplacement(replace, subject, reusableMatchInfo, builder); } @@ -241,7 +241,7 @@ function StringReplace(search, replace) { // Helper function for regular expressions in String.prototype.replace. function StringReplaceRegExp(subject, regexp, replace) { - replace = ToString(replace); + replace = TO_STRING_INLINE(replace); return %StringReplaceRegExpWithString(subject, regexp, replace, @@ -462,7 +462,7 @@ function ApplyReplacementFunction(replace, matchInfo, subject) { // ECMA-262 section 15.5.4.12 function StringSearch(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 regexp.lastIndex = 0; // ignore re.global property var result = regexp.exec(s); @@ -476,7 +476,7 @@ function StringSearch(re) { // ECMA-262 section 15.5.4.13 function StringSlice(start, end) { - var s = ToString(this); + var s = TO_STRING_INLINE(this); var s_len = s.length; var start_i = TO_INTEGER(start); var end_i = s_len; @@ -511,7 +511,7 @@ function StringSlice(start, end) { // ECMA-262 section 15.5.4.14 function StringSplit(separator, limit) { - var subject = ToString(this); + var subject = TO_STRING_INLINE(this); limit = (IS_UNDEFINED(limit)) ? 0xffffffff : TO_UINT32(limit); if (limit === 0) return []; @@ -525,18 +525,35 @@ function StringSplit(separator, limit) { } var length = subject.length; - if (IS_REGEXP(separator)) { - %_Log('regexp', 'regexp-split,%0S,%1r', [subject, separator]); - } else { - separator = ToString(separator); + if (!IS_REGEXP(separator)) { + separator = TO_STRING_INLINE(separator); + var separator_length = separator.length; + // 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); for (var i = 0; i < length; i++) result[i] = subject[i]; 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 (splitMatch(separator, subject, 0, 0) != null) return []; return [subject]; @@ -571,7 +588,8 @@ function StringSplit(separator, limit) { result[result.length] = SubString(subject, currentIndex, matchInfo[CAPTURE0]); 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 end = matchInfo[CAPTURE(i + 1)]; if (start != -1 && end != -1) { @@ -591,28 +609,18 @@ function StringSplit(separator, limit) { // Helper function used by split. This version returns the matchInfo // instead of allocating a new array with basically the same information. function splitMatch(separator, subject, current_index, start_index) { - if (IS_REGEXP(separator)) { - var matchInfo = DoRegExpExec(separator, subject, start_index); - if (matchInfo == null) return null; - // Section 15.5.4.14 paragraph two says that we do not allow zero length - // matches at the end of the string. - if (matchInfo[CAPTURE0] === subject.length) return null; - return matchInfo; - } - - var separatorIndex = subject.indexOf(separator, start_index); - if (separatorIndex === -1) return null; - - reusableMatchInfo[CAPTURE0] = separatorIndex; - reusableMatchInfo[CAPTURE1] = separatorIndex + separator.length; - return reusableMatchInfo; -}; + var matchInfo = DoRegExpExec(separator, subject, start_index); + if (matchInfo == null) return null; + // Section 15.5.4.14 paragraph two says that we do not allow zero length + // matches at the end of the string. + if (matchInfo[CAPTURE0] === subject.length) return null; + return matchInfo; +} // ECMA-262 section 15.5.4.15 function StringSubstring(start, end) { - var s = this; - if (!IS_STRING(s)) s = ToString(s); + var s = TO_STRING_INLINE(this); var s_len = s.length; var start_i = TO_INTEGER(start); @@ -643,7 +651,7 @@ function StringSubstring(start, end) { // This is not a part of ECMA-262. function StringSubstr(start, n) { - var s = ToString(this); + var s = TO_STRING_INLINE(this); var len; // 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 function StringToLowerCase() { - return %StringToLowerCase(ToString(this)); + return %StringToLowerCase(TO_STRING_INLINE(this)); } // ECMA-262, 15.5.4.17 function StringToLocaleLowerCase() { - return %StringToLowerCase(ToString(this)); + return %StringToLowerCase(TO_STRING_INLINE(this)); } // ECMA-262, 15.5.4.18 function StringToUpperCase() { - return %StringToUpperCase(ToString(this)); + return %StringToUpperCase(TO_STRING_INLINE(this)); } // ECMA-262, 15.5.4.19 function StringToLocaleUpperCase() { - return %StringToUpperCase(ToString(this)); + return %StringToUpperCase(TO_STRING_INLINE(this)); } // ES5, 15.5.4.20 function StringTrim() { - return %StringTrim(ToString(this), true, true); + return %StringTrim(TO_STRING_INLINE(this), true, true); } function StringTrimLeft() { - return %StringTrim(ToString(this), true, false); + return %StringTrim(TO_STRING_INLINE(this), true, false); } function StringTrimRight() { - return %StringTrim(ToString(this), false, true); + return %StringTrim(TO_STRING_INLINE(this), false, true); } // ECMA-262, section 15.5.3.2 @@ -731,10 +739,10 @@ function StringFromCharCode(code) { // Helper function for very basic XSS protection. function HtmlEscape(str) { - return ToString(str).replace(/</g, "<") - .replace(/>/g, ">") - .replace(/"/g, """) - .replace(/'/g, "'"); + return TO_STRING_INLINE(str).replace(/</g, "<") + .replace(/>/g, ">") + .replace(/"/g, """) + .replace(/'/g, "'"); }; @@ -813,7 +821,7 @@ function ReplaceResultBuilder(str) { ReplaceResultBuilder.prototype.add = function(str) { - if (!IS_STRING(str)) str = ToString(str); + str = TO_STRING_INLINE(str); if (str.length > 0) { var elements = this.elements; elements[elements.length] = str; diff --git a/deps/v8/src/stub-cache.cc b/deps/v8/src/stub-cache.cc index 3adaa40c1..577c2d773 100644 --- a/deps/v8/src/stub-cache.cc +++ b/deps/v8/src/stub-cache.cc @@ -105,7 +105,7 @@ Object* StubCache::ComputeLoadField(String* name, if (code->IsFailure()) return code; LOG(CodeCreateEvent(Logger::LOAD_IC_TAG, Code::cast(code), name)); 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)); } @@ -124,7 +124,7 @@ Object* StubCache::ComputeLoadCallback(String* name, if (code->IsFailure()) return code; LOG(CodeCreateEvent(Logger::LOAD_IC_TAG, Code::cast(code), name)); 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)); } @@ -143,7 +143,7 @@ Object* StubCache::ComputeLoadConstant(String* name, if (code->IsFailure()) return code; LOG(CodeCreateEvent(Logger::LOAD_IC_TAG, Code::cast(code), name)); 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)); } @@ -160,7 +160,7 @@ Object* StubCache::ComputeLoadInterceptor(String* name, if (code->IsFailure()) return code; LOG(CodeCreateEvent(Logger::LOAD_IC_TAG, Code::cast(code), name)); 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)); } @@ -189,7 +189,7 @@ Object* StubCache::ComputeLoadGlobal(String* name, if (code->IsFailure()) return code; LOG(CodeCreateEvent(Logger::LOAD_IC_TAG, Code::cast(code), name)); 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)); } @@ -351,7 +351,7 @@ Object* StubCache::ComputeStoreGlobal(String* name, if (code->IsFailure()) return code; LOG(CodeCreateEvent(Logger::LOAD_IC_TAG, Code::cast(code), name)); 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)); } @@ -566,7 +566,7 @@ Object* StubCache::ComputeCallGlobal(int argc, ASSERT_EQ(flags, Code::cast(code)->flags()); LOG(CodeCreateEvent(Logger::CALL_IC_TAG, Code::cast(code), name)); 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)); } diff --git a/deps/v8/src/utils.h b/deps/v8/src/utils.h index c59ca258a..2fcd241fd 100644 --- a/deps/v8/src/utils.h +++ b/deps/v8/src/utils.h @@ -157,7 +157,9 @@ class BitField { // Returns a uint32_t mask of bit field. 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. @@ -168,7 +170,7 @@ class BitField { // Extracts the bit field from the value. static T decode(uint32_t value) { - return static_cast<T>((value >> shift) & ((1U << (size)) - 1)); + return static_cast<T>((value & mask()) >> shift); } }; diff --git a/deps/v8/src/version.cc b/deps/v8/src/version.cc index 717bcc3e7..eaa63d541 100644 --- a/deps/v8/src/version.cc +++ b/deps/v8/src/version.cc @@ -34,8 +34,8 @@ // cannot be changed without changing the SCons build script. #define MAJOR_VERSION 2 #define MINOR_VERSION 1 -#define BUILD_NUMBER 1 -#define PATCH_LEVEL 1 +#define BUILD_NUMBER 2 +#define PATCH_LEVEL 0 #define CANDIDATE_VERSION false // Define SONAME to have the SCons build the put a specific SONAME into the diff --git a/deps/v8/src/x64/assembler-x64.cc b/deps/v8/src/x64/assembler-x64.cc index 1f97235ab..a994f45b1 100644 --- a/deps/v8/src/x64/assembler-x64.cc +++ b/deps/v8/src/x64/assembler-x64.cc @@ -34,46 +34,6 @@ namespace v8 { 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 // The required user mode extensions in X64 are (from AMD64 ABI Table A.1): diff --git a/deps/v8/src/x64/assembler-x64.h b/deps/v8/src/x64/assembler-x64.h index 6c6f6a34b..501952550 100644 --- a/deps/v8/src/x64/assembler-x64.h +++ b/deps/v8/src/x64/assembler-x64.h @@ -118,51 +118,23 @@ struct Register { int code_; }; -extern Register rax; -extern Register rcx; -extern Register rdx; -extern Register rbx; -extern Register rsp; -extern Register rbp; -extern Register rsi; -extern Register rdi; -extern Register r8; -extern Register r9; -extern Register r10; -extern Register r11; -extern Register r12; -extern Register r13; -extern Register r14; -extern Register r15; -extern Register no_reg; - - -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; +const Register rax = { 0 }; +const Register rcx = { 1 }; +const Register rdx = { 2 }; +const Register rbx = { 3 }; +const Register rsp = { 4 }; +const Register rbp = { 5 }; +const Register rsi = { 6 }; +const Register rdi = { 7 }; +const Register r8 = { 8 }; +const Register r9 = { 9 }; +const Register r10 = { 10 }; +const Register r11 = { 11 }; +const Register r12 = { 12 }; +const Register r13 = { 13 }; +const Register r14 = { 14 }; +const Register r15 = { 15 }; +const Register no_reg = { -1 }; struct XMMRegister { @@ -186,22 +158,22 @@ struct XMMRegister { int code_; }; -extern XMMRegister xmm0; -extern XMMRegister xmm1; -extern XMMRegister xmm2; -extern XMMRegister xmm3; -extern XMMRegister xmm4; -extern XMMRegister xmm5; -extern XMMRegister xmm6; -extern XMMRegister xmm7; -extern XMMRegister xmm8; -extern XMMRegister xmm9; -extern XMMRegister xmm10; -extern XMMRegister xmm11; -extern XMMRegister xmm12; -extern XMMRegister xmm13; -extern XMMRegister xmm14; -extern XMMRegister xmm15; +const XMMRegister xmm0 = { 0 }; +const XMMRegister xmm1 = { 1 }; +const XMMRegister xmm2 = { 2 }; +const XMMRegister xmm3 = { 3 }; +const XMMRegister xmm4 = { 4 }; +const XMMRegister xmm5 = { 5 }; +const XMMRegister xmm6 = { 6 }; +const XMMRegister xmm7 = { 7 }; +const XMMRegister xmm8 = { 8 }; +const XMMRegister xmm9 = { 9 }; +const XMMRegister xmm10 = { 10 }; +const XMMRegister xmm11 = { 11 }; +const XMMRegister xmm12 = { 12 }; +const XMMRegister xmm13 = { 13 }; +const XMMRegister xmm14 = { 14 }; +const XMMRegister xmm15 = { 15 }; enum Condition { // any value < 0 is considered no_condition diff --git a/deps/v8/src/x64/codegen-x64.cc b/deps/v8/src/x64/codegen-x64.cc index 6c063f3e7..28a522f34 100644 --- a/deps/v8/src/x64/codegen-x64.cc +++ b/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. CodeForFunctionPosition(info->function()); @@ -316,7 +316,7 @@ void CodeGenerator::Generate(CompilationInfo* info, Mode mode) { // rsi: callee's context allocator_->Initialize(); - if (mode == PRIMARY) { + if (info->mode() == CompilationInfo::PRIMARY) { frame_->Enter(); // Allocate space for locals and initialize them. @@ -407,6 +407,12 @@ void CodeGenerator::Generate(CompilationInfo* info, Mode mode) { // frame to match this state. frame_->Adjust(3); 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 @@ -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) { // This generates a fast version of: // (typeof(arg) === 'object' || %_ClassOf(arg) == 'RegExp') diff --git a/deps/v8/src/x64/codegen-x64.h b/deps/v8/src/x64/codegen-x64.h index 345431241..4593a2839 100644 --- a/deps/v8/src/x64/codegen-x64.h +++ b/deps/v8/src/x64/codegen-x64.h @@ -294,15 +294,6 @@ enum ArgumentsAllocationMode { 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<Code> MakeCode(CompilationInfo* info); @@ -385,7 +376,7 @@ class CodeGenerator: public AstVisitor { void VisitStatementsAndSpill(ZoneList<Statement*>* statements); // 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 // once per compiled function, immediately after binding the return @@ -536,6 +527,7 @@ class CodeGenerator: public AstVisitor { void GenerateIsSmi(ZoneList<Expression*>* args); void GenerateIsNonNegativeSmi(ZoneList<Expression*>* args); void GenerateIsArray(ZoneList<Expression*>* args); + void GenerateIsRegExp(ZoneList<Expression*>* args); void GenerateIsObject(ZoneList<Expression*>* args); void GenerateIsFunction(ZoneList<Expression*>* args); void GenerateIsUndetectableObject(ZoneList<Expression*>* args); diff --git a/deps/v8/src/x64/fast-codegen-x64.cc b/deps/v8/src/x64/fast-codegen-x64.cc index 1af768554..4dbf26a42 100644 --- a/deps/v8/src/x64/fast-codegen-x64.cc +++ b/deps/v8/src/x64/fast-codegen-x64.cc @@ -156,21 +156,28 @@ void FastCodeGenerator::EmitBitOr() { // commutative. __ 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 { - // Preserve the destination operand in a scratch register in case of - // bailout. - __ movq(scratch0(), destination()); - __ or_(destination(), other_accumulator(destination())); - __ JumpIfNotSmi(destination(), bailout()); + // Left is in accumulator1, right in accumulator0. + if (destination().is(accumulator0())) { + __ movq(scratch0(), accumulator0()); + __ or_(destination(), accumulator1()); // Or is commutative. + 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 // be a smi. 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 // 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)"); @@ -201,7 +209,7 @@ void FastCodeGenerator::Generate(CompilationInfo* compilation_info) { Handle<HeapObject> object = Handle<HeapObject>::cast(info()->receiver()); Handle<Map> map(object->map()); 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 @@ -214,7 +222,7 @@ void FastCodeGenerator::Generate(CompilationInfo* compilation_info) { ASSERT(info()->has_global_object()); Handle<Map> map(info()->global_object()->map()); __ movq(scratch0(), CodeGenerator::GlobalObject()); - __ CheckMap(scratch0(), map, bailout(), true); + __ CheckMap(scratch0(), map, bailout_to_beginning, true); } VisitStatements(info()->function()->body()); @@ -227,8 +235,6 @@ void FastCodeGenerator::Generate(CompilationInfo* compilation_info) { __ movq(rsp, rbp); __ pop(rbp); __ ret((scope()->num_parameters() + 1) * kPointerSize); - - __ bind(&bailout_); } diff --git a/deps/v8/src/x64/macro-assembler-x64.h b/deps/v8/src/x64/macro-assembler-x64.h index 6deeddce7..2673086dc 100644 --- a/deps/v8/src/x64/macro-assembler-x64.h +++ b/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 // a spare register). The register isn't callee save, and not used by the // function calling convention. -static const Register kScratchRegister = r10; +static const Register kScratchRegister = { 10 }; // r10. // Convenience for platform-independent signatures. typedef Operand MemOperand; |