diff options
Diffstat (limited to 'chromium/v8/src/ia32/full-codegen-ia32.cc')
-rw-r--r-- | chromium/v8/src/ia32/full-codegen-ia32.cc | 1080 |
1 files changed, 478 insertions, 602 deletions
diff --git a/chromium/v8/src/ia32/full-codegen-ia32.cc b/chromium/v8/src/ia32/full-codegen-ia32.cc index 3c5d4aa2788..0ea77f09145 100644 --- a/chromium/v8/src/ia32/full-codegen-ia32.cc +++ b/chromium/v8/src/ia32/full-codegen-ia32.cc @@ -1,43 +1,20 @@ // Copyright 2012 the V8 project authors. All rights reserved. -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following -// disclaimer in the documentation and/or other materials provided -// with the distribution. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived -// from this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -#include "v8.h" +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "src/v8.h" #if V8_TARGET_ARCH_IA32 -#include "code-stubs.h" -#include "codegen.h" -#include "compiler.h" -#include "debug.h" -#include "full-codegen.h" -#include "isolate-inl.h" -#include "parser.h" -#include "scopes.h" -#include "stub-cache.h" +#include "src/code-stubs.h" +#include "src/codegen.h" +#include "src/compiler.h" +#include "src/debug.h" +#include "src/full-codegen.h" +#include "src/isolate-inl.h" +#include "src/parser.h" +#include "src/scopes.h" +#include "src/stub-cache.h" namespace v8 { namespace internal { @@ -74,7 +51,7 @@ class JumpPatchSite BASE_EMBEDDED { void EmitPatchInfo() { if (patch_site_.is_bound()) { int delta_to_patch_site = masm_->SizeOfCodeGeneratedSince(&patch_site_); - ASSERT(is_int8(delta_to_patch_site)); + ASSERT(is_uint8(delta_to_patch_site)); __ test(eax, Immediate(delta_to_patch_site)); #ifdef DEBUG info_emitted_ = true; @@ -107,7 +84,6 @@ class JumpPatchSite BASE_EMBEDDED { // formal parameter count expected by the function. // // The live registers are: -// o ecx: CallKind // o edi: the JS function object being called (i.e. ourselves) // o esi: our context // o ebp: our caller's frame pointer @@ -119,6 +95,7 @@ void FullCodeGenerator::Generate() { CompilationInfo* info = info_; handler_table_ = isolate()->factory()->NewFixedArray(function()->handler_count(), TENURED); + profiling_counter_ = isolate()->factory()->NewCell( Handle<Smi>(Smi::FromInt(FLAG_interrupt_budget), isolate())); SetFunctionPosition(function()); @@ -133,22 +110,23 @@ void FullCodeGenerator::Generate() { } #endif - // Strict mode functions and builtins need to replace the receiver - // with undefined when called as functions (without an explicit - // receiver object). ecx is zero for method calls and non-zero for - // function calls. - if (!info->is_classic_mode() || info->is_native()) { + // Sloppy mode functions and builtins need to replace the receiver with the + // global proxy when called as functions (without an explicit receiver + // object). + if (info->strict_mode() == SLOPPY && !info->is_native()) { Label ok; - __ test(ecx, ecx); - __ j(zero, &ok, Label::kNear); // +1 for return address. int receiver_offset = (info->scope()->num_parameters() + 1) * kPointerSize; __ mov(ecx, Operand(esp, receiver_offset)); - __ JumpIfSmi(ecx, &ok); - __ CmpObjectType(ecx, JS_GLOBAL_PROXY_TYPE, ecx); + + __ cmp(ecx, isolate()->factory()->undefined_value()); __ j(not_equal, &ok, Label::kNear); - __ mov(Operand(esp, receiver_offset), - Immediate(isolate()->factory()->undefined_value())); + + __ mov(ecx, GlobalObjectOperand()); + __ mov(ecx, FieldOperand(ecx, GlobalObject::kGlobalReceiverOffset)); + + __ mov(Operand(esp, receiver_offset), ecx); + __ bind(&ok); } @@ -158,7 +136,7 @@ void FullCodeGenerator::Generate() { FrameScope frame_scope(masm_, StackFrame::MANUAL); info->set_prologue_offset(masm_->pc_offset()); - __ Prologue(BUILD_FUNCTION_FRAME); + __ Prologue(info->IsCodePreAgingActive()); info->AddNoFrameRange(0, masm_->pc_offset()); { Comment cmnt(masm_, "[ Allocate locals"); @@ -168,8 +146,34 @@ void FullCodeGenerator::Generate() { if (locals_count == 1) { __ push(Immediate(isolate()->factory()->undefined_value())); } else if (locals_count > 1) { + if (locals_count >= 128) { + Label ok; + __ mov(ecx, esp); + __ sub(ecx, Immediate(locals_count * kPointerSize)); + ExternalReference stack_limit = + ExternalReference::address_of_real_stack_limit(isolate()); + __ cmp(ecx, Operand::StaticVariable(stack_limit)); + __ j(above_equal, &ok, Label::kNear); + __ InvokeBuiltin(Builtins::STACK_OVERFLOW, CALL_FUNCTION); + __ bind(&ok); + } __ mov(eax, Immediate(isolate()->factory()->undefined_value())); - for (int i = 0; i < locals_count; i++) { + const int kMaxPushes = 32; + if (locals_count >= kMaxPushes) { + int loop_iterations = locals_count / kMaxPushes; + __ mov(ecx, loop_iterations); + Label loop_header; + __ bind(&loop_header); + // Do pushes. + for (int i = 0; i < kMaxPushes; i++) { + __ push(eax); + } + __ dec(ecx); + __ j(not_zero, &loop_header, Label::kNear); + } + int remaining = locals_count % kMaxPushes; + // Emit the remaining pushes. + for (int i = 0; i < remaining; i++) { __ push(eax); } } @@ -181,21 +185,26 @@ void FullCodeGenerator::Generate() { int heap_slots = info->scope()->num_heap_slots() - Context::MIN_CONTEXT_SLOTS; if (heap_slots > 0) { Comment cmnt(masm_, "[ Allocate context"); + bool need_write_barrier = true; // Argument to NewContext is the function, which is still in edi. - __ push(edi); if (FLAG_harmony_scoping && info->scope()->is_global_scope()) { + __ push(edi); __ Push(info->scope()->GetScopeInfo()); - __ CallRuntime(Runtime::kNewGlobalContext, 2); + __ CallRuntime(Runtime::kHiddenNewGlobalContext, 2); } else if (heap_slots <= FastNewContextStub::kMaximumSlots) { - FastNewContextStub stub(heap_slots); + FastNewContextStub stub(isolate(), heap_slots); __ CallStub(&stub); + // Result of FastNewContextStub is always in new space. + need_write_barrier = false; } else { - __ CallRuntime(Runtime::kNewFunctionContext, 1); + __ push(edi); + __ CallRuntime(Runtime::kHiddenNewFunctionContext, 1); } function_in_register = false; - // Context is returned in both eax and esi. It replaces the context - // passed to us. It's saved in the stack and kept live in esi. - __ mov(Operand(ebp, StandardFrameConstants::kContextOffset), esi); + // Context is returned in eax. It replaces the context passed to us. + // It's saved in the stack and kept live in esi. + __ mov(esi, eax); + __ mov(Operand(ebp, StandardFrameConstants::kContextOffset), eax); // Copy parameters into context if necessary. int num_parameters = info->scope()->num_parameters(); @@ -210,11 +219,18 @@ void FullCodeGenerator::Generate() { int context_offset = Context::SlotOffset(var->index()); __ mov(Operand(esi, context_offset), eax); // Update the write barrier. This clobbers eax and ebx. - __ RecordWriteContextSlot(esi, - context_offset, - eax, - ebx, - kDontSaveFPRegs); + if (need_write_barrier) { + __ RecordWriteContextSlot(esi, + context_offset, + eax, + ebx, + kDontSaveFPRegs); + } else if (FLAG_debug_code) { + Label done; + __ JumpIfInNewSpace(esi, eax, &done, Label::kNear); + __ Abort(kExpectedNewSpaceObject); + __ bind(&done); + } } } } @@ -240,14 +256,14 @@ void FullCodeGenerator::Generate() { // The stub will rewrite receiver and parameter count if the previous // stack frame was an arguments adapter frame. ArgumentsAccessStub::Type type; - if (!is_classic_mode()) { + if (strict_mode() == STRICT) { type = ArgumentsAccessStub::NEW_STRICT; } else if (function()->has_duplicate_parameters()) { - type = ArgumentsAccessStub::NEW_NON_STRICT_SLOW; + type = ArgumentsAccessStub::NEW_SLOPPY_SLOW; } else { - type = ArgumentsAccessStub::NEW_NON_STRICT_FAST; + type = ArgumentsAccessStub::NEW_SLOPPY_FAST; } - ArgumentsAccessStub stub(type); + ArgumentsAccessStub stub(isolate(), type); __ CallStub(&stub); SetVar(arguments, eax, ebx, edx); @@ -271,7 +287,7 @@ void FullCodeGenerator::Generate() { if (scope()->is_function_scope() && scope()->function() != NULL) { VariableDeclaration* function = scope()->function(); ASSERT(function->proxy()->var()->mode() == CONST || - function->proxy()->var()->mode() == CONST_HARMONY); + function->proxy()->var()->mode() == CONST_LEGACY); ASSERT(function->proxy()->var()->location() != Variable::UNALLOCATED); VisitVariableDeclaration(function); } @@ -281,8 +297,8 @@ void FullCodeGenerator::Generate() { { Comment cmnt(masm_, "[ Stack check"); PrepareForBailoutForId(BailoutId::Declarations(), NO_REGISTERS); Label ok; - ExternalReference stack_limit = - ExternalReference::address_of_stack_limit(isolate()); + ExternalReference stack_limit + = ExternalReference::address_of_stack_limit(isolate()); __ cmp(esp, Operand::StaticVariable(stack_limit)); __ j(above_equal, &ok, Label::kNear); __ call(isolate()->builtins()->StackCheck(), RelocInfo::CODE_TARGET); @@ -306,7 +322,7 @@ void FullCodeGenerator::Generate() { void FullCodeGenerator::ClearAccumulator() { - __ Set(eax, Immediate(Smi::FromInt(0))); + __ Move(eax, Immediate(Smi::FromInt(0))); } @@ -319,10 +335,6 @@ void FullCodeGenerator::EmitProfilingCounterDecrement(int delta) { void FullCodeGenerator::EmitProfilingCounterReset() { int reset_value = FLAG_interrupt_budget; - if (info_->ShouldSelfOptimize() && !FLAG_retry_self_opt) { - // Self-optimization is a one-off thing: if it fails, don't try again. - reset_value = Smi::kMaxValue; - } __ mov(ebx, Immediate(profiling_counter_)); __ mov(FieldOperand(ebx, Cell::kValueOffset), Immediate(Smi::FromInt(reset_value))); @@ -334,13 +346,10 @@ void FullCodeGenerator::EmitBackEdgeBookkeeping(IterationStatement* stmt, Comment cmnt(masm_, "[ Back edge bookkeeping"); Label ok; - int weight = 1; - if (FLAG_weighted_back_edges) { - ASSERT(back_edge_target->is_bound()); - int distance = masm_->SizeOfCodeGeneratedSince(back_edge_target); - weight = Min(kMaxBackEdgeWeight, - Max(1, distance / kCodeSizeMultiplier)); - } + ASSERT(back_edge_target->is_bound()); + int distance = masm_->SizeOfCodeGeneratedSince(back_edge_target); + int weight = Min(kMaxBackEdgeWeight, + Max(1, distance / kCodeSizeMultiplier)); EmitProfilingCounterDecrement(weight); __ j(positive, &ok, Label::kNear); __ call(isolate()->builtins()->InterruptCheck(), RelocInfo::CODE_TARGET); @@ -372,31 +381,24 @@ void FullCodeGenerator::EmitReturnSequence() { __ push(eax); __ CallRuntime(Runtime::kTraceExit, 1); } - if (FLAG_interrupt_at_exit || FLAG_self_optimization) { - // Pretend that the exit is a backwards jump to the entry. - int weight = 1; - if (info_->ShouldSelfOptimize()) { - weight = FLAG_interrupt_budget / FLAG_self_opt_count; - } else if (FLAG_weighted_back_edges) { - int distance = masm_->pc_offset(); - weight = Min(kMaxBackEdgeWeight, - Max(1, distance / kCodeSizeMultiplier)); - } - EmitProfilingCounterDecrement(weight); - Label ok; - __ j(positive, &ok, Label::kNear); - __ push(eax); - if (info_->ShouldSelfOptimize() && FLAG_direct_self_opt) { - __ push(Operand(ebp, JavaScriptFrameConstants::kFunctionOffset)); - __ CallRuntime(Runtime::kOptimizeFunctionOnNextCall, 1); - } else { - __ call(isolate()->builtins()->InterruptCheck(), - RelocInfo::CODE_TARGET); - } - __ pop(eax); - EmitProfilingCounterReset(); - __ bind(&ok); + // Pretend that the exit is a backwards jump to the entry. + int weight = 1; + if (info_->ShouldSelfOptimize()) { + weight = FLAG_interrupt_budget / FLAG_self_opt_count; + } else { + int distance = masm_->pc_offset(); + weight = Min(kMaxBackEdgeWeight, + Max(1, distance / kCodeSizeMultiplier)); } + EmitProfilingCounterDecrement(weight); + Label ok; + __ j(positive, &ok, Label::kNear); + __ push(eax); + __ call(isolate()->builtins()->InterruptCheck(), + RelocInfo::CODE_TARGET); + __ pop(eax); + EmitProfilingCounterReset(); + __ bind(&ok); #ifdef DEBUG // Add a label for checking the size of the code used for returning. Label check_exit_codesize; @@ -412,12 +414,10 @@ void FullCodeGenerator::EmitReturnSequence() { int arguments_bytes = (info_->scope()->num_parameters() + 1) * kPointerSize; __ Ret(arguments_bytes, ecx); -#ifdef ENABLE_DEBUGGER_SUPPORT // Check that the size of the code used for returning is large enough // for the debugger's requirements. ASSERT(Assembler::kJSReturnSequenceLength <= masm_->SizeOfCodeGeneratedSince(&check_exit_codesize)); -#endif info_->AddNoFrameRange(no_frame_start, masm_->pc_offset()); } } @@ -479,9 +479,9 @@ void FullCodeGenerator::EffectContext::Plug(Handle<Object> lit) const { void FullCodeGenerator::AccumulatorValueContext::Plug( Handle<Object> lit) const { if (lit->IsSmi()) { - __ SafeSet(result_register(), Immediate(lit)); + __ SafeMove(result_register(), Immediate(lit)); } else { - __ Set(result_register(), Immediate(lit)); + __ Move(result_register(), Immediate(lit)); } } @@ -638,7 +638,7 @@ void FullCodeGenerator::DoTest(Expression* condition, Label* if_false, Label* fall_through) { Handle<Code> ic = ToBooleanStub::GetUninitialized(isolate()); - CallIC(ic, RelocInfo::CODE_TARGET, condition->test_id()); + CallIC(ic, condition->test_id()); __ test(result_register(), result_register()); // The stub returns nonzero for true. Split(not_zero, if_true, if_false, fall_through); @@ -755,7 +755,7 @@ void FullCodeGenerator::VisitVariableDeclaration( VariableProxy* proxy = declaration->proxy(); VariableMode mode = declaration->mode(); Variable* variable = proxy->var(); - bool hole_init = mode == CONST || mode == CONST_HARMONY || mode == LET; + bool hole_init = mode == LET || mode == CONST || mode == CONST_LEGACY; switch (variable->location()) { case Variable::UNALLOCATED: globals_->Add(variable->name(), zone()); @@ -802,7 +802,7 @@ void FullCodeGenerator::VisitVariableDeclaration( } else { __ push(Immediate(Smi::FromInt(0))); // Indicates no initial value. } - __ CallRuntime(Runtime::kDeclareContextSlot, 4); + __ CallRuntime(Runtime::kHiddenDeclareContextSlot, 4); break; } } @@ -855,7 +855,7 @@ void FullCodeGenerator::VisitFunctionDeclaration( __ push(Immediate(variable->name())); __ push(Immediate(Smi::FromInt(NONE))); VisitForStackValue(declaration->fun()); - __ CallRuntime(Runtime::kDeclareContextSlot, 4); + __ CallRuntime(Runtime::kHiddenDeclareContextSlot, 4); break; } } @@ -925,7 +925,7 @@ void FullCodeGenerator::DeclareGlobals(Handle<FixedArray> pairs) { __ push(esi); // The context is the first argument. __ Push(pairs); __ Push(Smi::FromInt(DeclareGlobalsFlags())); - __ CallRuntime(Runtime::kDeclareGlobals, 3); + __ CallRuntime(Runtime::kHiddenDeclareGlobals, 3); // Return value is ignored. } @@ -933,7 +933,7 @@ void FullCodeGenerator::DeclareGlobals(Handle<FixedArray> pairs) { void FullCodeGenerator::DeclareModules(Handle<FixedArray> descriptions) { // Call the runtime to declare the modules. __ Push(descriptions); - __ CallRuntime(Runtime::kDeclareModules, 1); + __ CallRuntime(Runtime::kHiddenDeclareModules, 1); // Return value is ignored. } @@ -989,8 +989,18 @@ void FullCodeGenerator::VisitSwitchStatement(SwitchStatement* stmt) { // Record position before stub call for type feedback. SetSourcePosition(clause->position()); Handle<Code> ic = CompareIC::GetUninitialized(isolate(), Token::EQ_STRICT); - CallIC(ic, RelocInfo::CODE_TARGET, clause->CompareId()); + CallIC(ic, clause->CompareId()); patch_site.EmitPatchInfo(); + + Label skip; + __ jmp(&skip, Label::kNear); + PrepareForBailout(clause, TOS_REG); + __ cmp(eax, isolate()->factory()->true_value()); + __ j(not_equal, &next_test); + __ Drop(1); + __ jmp(clause->body_target()); + __ bind(&skip); + __ test(eax, eax); __ j(not_equal, &next_test); __ Drop(1); // Switch value is no longer needed. @@ -1023,6 +1033,8 @@ void FullCodeGenerator::VisitSwitchStatement(SwitchStatement* stmt) { void FullCodeGenerator::VisitForInStatement(ForInStatement* stmt) { Comment cmnt(masm_, "[ ForInStatement"); + int slot = stmt->ForInFeedbackSlot(); + SetStatementPosition(stmt); Label loop, exit; @@ -1101,20 +1113,17 @@ void FullCodeGenerator::VisitForInStatement(ForInStatement* stmt) { Label non_proxy; __ bind(&fixed_array); - Handle<Cell> cell = isolate()->factory()->NewCell( - Handle<Object>(Smi::FromInt(TypeFeedbackCells::kForInFastCaseMarker), - isolate())); - RecordTypeFeedbackCell(stmt->ForInFeedbackId(), cell); - __ LoadHeapObject(ebx, cell); - __ mov(FieldOperand(ebx, Cell::kValueOffset), - Immediate(Smi::FromInt(TypeFeedbackCells::kForInSlowCaseMarker))); + // No need for a write barrier, we are storing a Smi in the feedback vector. + __ LoadHeapObject(ebx, FeedbackVector()); + __ mov(FieldOperand(ebx, FixedArray::OffsetOfElementAt(slot)), + Immediate(TypeFeedbackInfo::MegamorphicSentinel(isolate()))); __ mov(ebx, Immediate(Smi::FromInt(1))); // Smi indicates slow check __ mov(ecx, Operand(esp, 0 * kPointerSize)); // Get enumerated object STATIC_ASSERT(FIRST_JS_PROXY_TYPE == FIRST_SPEC_OBJECT_TYPE); __ CmpObjectType(ecx, LAST_JS_PROXY_TYPE, ecx); __ j(above, &non_proxy); - __ Set(ebx, Immediate(Smi::FromInt(0))); // Zero indicates proxy + __ Move(ebx, Immediate(Smi::FromInt(0))); // Zero indicates proxy __ bind(&non_proxy); __ push(ebx); // Smi __ push(eax); // Array @@ -1198,8 +1207,8 @@ void FullCodeGenerator::VisitForOfStatement(ForOfStatement* stmt) { Iteration loop_statement(this, stmt); increment_loop_depth(); - // var iterator = iterable[@@iterator]() - VisitForAccumulatorValue(stmt->assign_iterator()); + // var iterable = subject + VisitForAccumulatorValue(stmt->assign_iterable()); // As with for-in, skip the loop if the iterator is null or undefined. __ CompareRoot(eax, Heap::kUndefinedValueRootIndex); @@ -1207,15 +1216,8 @@ void FullCodeGenerator::VisitForOfStatement(ForOfStatement* stmt) { __ CompareRoot(eax, Heap::kNullValueRootIndex); __ j(equal, loop_statement.break_label()); - // Convert the iterator to a JS object. - Label convert, done_convert; - __ JumpIfSmi(eax, &convert); - __ CmpObjectType(eax, FIRST_SPEC_OBJECT_TYPE, ecx); - __ j(above_equal, &done_convert); - __ bind(&convert); - __ push(eax); - __ InvokeBuiltin(Builtins::TO_OBJECT, CALL_FUNCTION); - __ bind(&done_convert); + // var iterator = iterable[Symbol.iterator](); + VisitForEffect(stmt->assign_iterator()); // Loop entry. __ bind(loop_statement.continue_label()); @@ -1262,7 +1264,9 @@ void FullCodeGenerator::EmitNewClosure(Handle<SharedFunctionInfo> info, !pretenure && scope()->is_function_scope() && info->num_literals() == 0) { - FastNewClosureStub stub(info->language_mode(), info->is_generator()); + FastNewClosureStub stub(isolate(), + info->strict_mode(), + info->is_generator()); __ mov(ebx, Immediate(info)); __ CallStub(&stub); } else { @@ -1271,7 +1275,7 @@ void FullCodeGenerator::EmitNewClosure(Handle<SharedFunctionInfo> info, __ push(Immediate(pretenure ? isolate()->factory()->true_value() : isolate()->factory()->false_value())); - __ CallRuntime(Runtime::kNewClosure, 3); + __ CallRuntime(Runtime::kHiddenNewClosure, 3); } context()->Plug(eax); } @@ -1292,7 +1296,7 @@ void FullCodeGenerator::EmitLoadGlobalCheckExtensions(Variable* var, Scope* s = scope(); while (s != NULL) { if (s->num_heap_slots() > 0) { - if (s->calls_non_strict_eval()) { + if (s->calls_sloppy_eval()) { // Check that extension is NULL. __ cmp(ContextOperand(context, Context::EXTENSION_INDEX), Immediate(0)); @@ -1306,7 +1310,7 @@ void FullCodeGenerator::EmitLoadGlobalCheckExtensions(Variable* var, // If no outer scope calls eval, we do not need to check more // context extensions. If we have reached an eval scope, we check // all extensions from this point. - if (!s->outer_scope_calls_non_strict_eval() || s->is_eval_scope()) break; + if (!s->outer_scope_calls_sloppy_eval() || s->is_eval_scope()) break; s = s->outer_scope(); } @@ -1335,11 +1339,11 @@ void FullCodeGenerator::EmitLoadGlobalCheckExtensions(Variable* var, // load IC call. __ mov(edx, GlobalObjectOperand()); __ mov(ecx, var->name()); - Handle<Code> ic = isolate()->builtins()->LoadIC_Initialize(); - RelocInfo::Mode mode = (typeof_state == INSIDE_TYPEOF) - ? RelocInfo::CODE_TARGET - : RelocInfo::CODE_TARGET_CONTEXT; - CallIC(ic, mode); + ContextualMode mode = (typeof_state == INSIDE_TYPEOF) + ? NOT_CONTEXTUAL + : CONTEXTUAL; + + CallLoadIC(mode); } @@ -1351,7 +1355,7 @@ MemOperand FullCodeGenerator::ContextSlotOperandCheckExtensions(Variable* var, for (Scope* s = scope(); s != var->scope(); s = s->outer_scope()) { if (s->num_heap_slots() > 0) { - if (s->calls_non_strict_eval()) { + if (s->calls_sloppy_eval()) { // Check that extension is NULL. __ cmp(ContextOperand(context, Context::EXTENSION_INDEX), Immediate(0)); @@ -1388,16 +1392,15 @@ void FullCodeGenerator::EmitDynamicLookupFastCase(Variable* var, } else if (var->mode() == DYNAMIC_LOCAL) { Variable* local = var->local_if_not_shadowed(); __ mov(eax, ContextSlotOperandCheckExtensions(local, slow)); - if (local->mode() == LET || - local->mode() == CONST || - local->mode() == CONST_HARMONY) { + if (local->mode() == LET || local->mode() == CONST || + local->mode() == CONST_LEGACY) { __ cmp(eax, isolate()->factory()->the_hole_value()); __ j(not_equal, done); - if (local->mode() == CONST) { + if (local->mode() == CONST_LEGACY) { __ mov(eax, isolate()->factory()->undefined_value()); - } else { // LET || CONST_HARMONY + } else { // LET || CONST __ push(Immediate(var->name())); - __ CallRuntime(Runtime::kThrowReferenceError, 1); + __ CallRuntime(Runtime::kHiddenThrowReferenceError, 1); } } __ jmp(done); @@ -1414,13 +1417,12 @@ void FullCodeGenerator::EmitVariableLoad(VariableProxy* proxy) { // variables. switch (var->location()) { case Variable::UNALLOCATED: { - Comment cmnt(masm_, "Global variable"); + Comment cmnt(masm_, "[ Global variable"); // Use inline caching. Variable name is passed in ecx and the global // object in eax. __ mov(edx, GlobalObjectOperand()); __ mov(ecx, var->name()); - Handle<Code> ic = isolate()->builtins()->LoadIC_Initialize(); - CallIC(ic, RelocInfo::CODE_TARGET_CONTEXT); + CallLoadIC(CONTEXTUAL); context()->Plug(eax); break; } @@ -1428,9 +1430,8 @@ void FullCodeGenerator::EmitVariableLoad(VariableProxy* proxy) { case Variable::PARAMETER: case Variable::LOCAL: case Variable::CONTEXT: { - Comment cmnt(masm_, var->IsContextSlot() - ? "Context variable" - : "Stack variable"); + Comment cmnt(masm_, var->IsContextSlot() ? "[ Context variable" + : "[ Stack variable"); if (var->binding_needs_init()) { // var->scope() may be NULL when the proxy is located in eval code and // refers to a potential outside binding. Currently those bindings are @@ -1462,7 +1463,7 @@ void FullCodeGenerator::EmitVariableLoad(VariableProxy* proxy) { // Check that we always have valid source position. ASSERT(var->initializer_position() != RelocInfo::kNoPosition); ASSERT(proxy->position() != RelocInfo::kNoPosition); - skip_init_check = var->mode() != CONST && + skip_init_check = var->mode() != CONST_LEGACY && var->initializer_position() < proxy->position(); } @@ -1472,14 +1473,14 @@ void FullCodeGenerator::EmitVariableLoad(VariableProxy* proxy) { GetVar(eax, var); __ cmp(eax, isolate()->factory()->the_hole_value()); __ j(not_equal, &done, Label::kNear); - if (var->mode() == LET || var->mode() == CONST_HARMONY) { + if (var->mode() == LET || var->mode() == CONST) { // Throw a reference error when using an uninitialized let/const // binding in harmony mode. __ push(Immediate(var->name())); - __ CallRuntime(Runtime::kThrowReferenceError, 1); + __ CallRuntime(Runtime::kHiddenThrowReferenceError, 1); } else { // Uninitalized const bindings outside of harmony mode are unholed. - ASSERT(var->mode() == CONST); + ASSERT(var->mode() == CONST_LEGACY); __ mov(eax, isolate()->factory()->undefined_value()); } __ bind(&done); @@ -1492,15 +1493,15 @@ void FullCodeGenerator::EmitVariableLoad(VariableProxy* proxy) { } case Variable::LOOKUP: { + Comment cmnt(masm_, "[ Lookup variable"); Label done, slow; // Generate code for loading from variables potentially shadowed // by eval-introduced variables. EmitDynamicLookupFastCase(var, NOT_INSIDE_TYPEOF, &slow, &done); __ bind(&slow); - Comment cmnt(masm_, "Lookup variable"); __ push(esi); // Context. __ push(Immediate(var->name())); - __ CallRuntime(Runtime::kLoadContextSlot, 2); + __ CallRuntime(Runtime::kHiddenLoadContextSlot, 2); __ bind(&done); context()->Plug(eax); break; @@ -1531,7 +1532,7 @@ void FullCodeGenerator::VisitRegExpLiteral(RegExpLiteral* expr) { __ push(Immediate(Smi::FromInt(expr->literal_index()))); __ push(Immediate(expr->pattern())); __ push(Immediate(expr->flags())); - __ CallRuntime(Runtime::kMaterializeRegExpLiteral, 4); + __ CallRuntime(Runtime::kHiddenMaterializeRegExpLiteral, 4); __ mov(ebx, eax); __ bind(&materialized); @@ -1543,7 +1544,7 @@ void FullCodeGenerator::VisitRegExpLiteral(RegExpLiteral* expr) { __ bind(&runtime_allocate); __ push(ebx); __ push(Immediate(Smi::FromInt(size))); - __ CallRuntime(Runtime::kAllocateInNewSpace, 1); + __ CallRuntime(Runtime::kHiddenAllocateInNewSpace, 1); __ pop(ebx); __ bind(&allocated); @@ -1584,8 +1585,8 @@ void FullCodeGenerator::VisitObjectLiteral(ObjectLiteral* expr) { ? ObjectLiteral::kHasFunction : ObjectLiteral::kNoFlags; int properties_count = constant_properties->length() / 2; - if ((FLAG_track_double_fields && expr->may_store_doubles()) || - expr->depth() > 1 || Serializer::enabled() || + if (expr->may_store_doubles() || expr->depth() > 1 || + masm()->serializer_enabled() || flags != ObjectLiteral::kFastElements || properties_count > FastCloneShallowObjectStub::kMaximumClonedProperties) { __ mov(edi, Operand(ebp, JavaScriptFrameConstants::kFunctionOffset)); @@ -1593,14 +1594,14 @@ void FullCodeGenerator::VisitObjectLiteral(ObjectLiteral* expr) { __ push(Immediate(Smi::FromInt(expr->literal_index()))); __ push(Immediate(constant_properties)); __ push(Immediate(Smi::FromInt(flags))); - __ CallRuntime(Runtime::kCreateObjectLiteral, 4); + __ CallRuntime(Runtime::kHiddenCreateObjectLiteral, 4); } else { __ mov(edi, Operand(ebp, JavaScriptFrameConstants::kFunctionOffset)); __ mov(eax, FieldOperand(edi, JSFunction::kLiteralsOffset)); __ mov(ebx, Immediate(Smi::FromInt(expr->literal_index()))); __ mov(ecx, Immediate(constant_properties)); __ mov(edx, Immediate(Smi::FromInt(flags))); - FastCloneShallowObjectStub stub(properties_count); + FastCloneShallowObjectStub stub(isolate(), properties_count); __ CallStub(&stub); } @@ -1636,10 +1637,7 @@ void FullCodeGenerator::VisitObjectLiteral(ObjectLiteral* expr) { VisitForAccumulatorValue(value); __ mov(ecx, Immediate(key->value())); __ mov(edx, Operand(esp, 0)); - Handle<Code> ic = is_classic_mode() - ? isolate()->builtins()->StoreIC_Initialize() - : isolate()->builtins()->StoreIC_Initialize_Strict(); - CallIC(ic, RelocInfo::CODE_TARGET, key->LiteralFeedbackId()); + CallStoreIC(key->LiteralFeedbackId()); PrepareForBailoutForId(key->id(), NO_REGISTERS); } else { VisitForEffect(value); @@ -1720,54 +1718,26 @@ void FullCodeGenerator::VisitArrayLiteral(ArrayLiteral* expr) { Handle<FixedArrayBase> constant_elements_values( FixedArrayBase::cast(constant_elements->get(1))); - AllocationSiteMode allocation_site_mode = FLAG_track_allocation_sites - ? TRACK_ALLOCATION_SITE : DONT_TRACK_ALLOCATION_SITE; + AllocationSiteMode allocation_site_mode = TRACK_ALLOCATION_SITE; if (has_constant_fast_elements && !FLAG_allocation_site_pretenuring) { // If the only customer of allocation sites is transitioning, then // we can turn it off if we don't have anywhere else to transition to. allocation_site_mode = DONT_TRACK_ALLOCATION_SITE; } - Heap* heap = isolate()->heap(); - if (has_constant_fast_elements && - constant_elements_values->map() == heap->fixed_cow_array_map()) { - // If the elements are already FAST_*_ELEMENTS, the boilerplate cannot - // change, so it's possible to specialize the stub in advance. - __ IncrementCounter(isolate()->counters()->cow_arrays_created_stub(), 1); - __ mov(ebx, Operand(ebp, JavaScriptFrameConstants::kFunctionOffset)); - __ mov(eax, FieldOperand(ebx, JSFunction::kLiteralsOffset)); - __ mov(ebx, Immediate(Smi::FromInt(expr->literal_index()))); - __ mov(ecx, Immediate(constant_elements)); - FastCloneShallowArrayStub stub( - FastCloneShallowArrayStub::COPY_ON_WRITE_ELEMENTS, - allocation_site_mode, - length); - __ CallStub(&stub); - } else if (expr->depth() > 1 || Serializer::enabled() || - length > FastCloneShallowArrayStub::kMaximumClonedLength) { + if (expr->depth() > 1 || length > JSObject::kInitialMaxFastElementArray) { __ mov(ebx, Operand(ebp, JavaScriptFrameConstants::kFunctionOffset)); __ push(FieldOperand(ebx, JSFunction::kLiteralsOffset)); __ push(Immediate(Smi::FromInt(expr->literal_index()))); __ push(Immediate(constant_elements)); __ push(Immediate(Smi::FromInt(flags))); - __ CallRuntime(Runtime::kCreateArrayLiteral, 4); + __ CallRuntime(Runtime::kHiddenCreateArrayLiteral, 4); } else { - ASSERT(IsFastSmiOrObjectElementsKind(constant_elements_kind) || - FLAG_smi_only_arrays); - FastCloneShallowArrayStub::Mode mode = - FastCloneShallowArrayStub::CLONE_ANY_ELEMENTS; - - // If the elements are already FAST_*_ELEMENTS, the boilerplate cannot - // change, so it's possible to specialize the stub in advance. - if (has_constant_fast_elements) { - mode = FastCloneShallowArrayStub::CLONE_ELEMENTS; - } - __ mov(ebx, Operand(ebp, JavaScriptFrameConstants::kFunctionOffset)); __ mov(eax, FieldOperand(ebx, JSFunction::kLiteralsOffset)); __ mov(ebx, Immediate(Smi::FromInt(expr->literal_index()))); __ mov(ecx, Immediate(constant_elements)); - FastCloneShallowArrayStub stub(mode, allocation_site_mode, length); + FastCloneShallowArrayStub stub(isolate(), allocation_site_mode); __ CallStub(&stub); } @@ -1804,7 +1774,7 @@ void FullCodeGenerator::VisitArrayLiteral(ArrayLiteral* expr) { } else { // Store the subexpression value in the array's elements. __ mov(ecx, Immediate(Smi::FromInt(i))); - StoreArrayLiteralElementStub stub; + StoreArrayLiteralElementStub stub(isolate()); __ CallStub(&stub); } @@ -1821,13 +1791,9 @@ void FullCodeGenerator::VisitArrayLiteral(ArrayLiteral* expr) { void FullCodeGenerator::VisitAssignment(Assignment* expr) { + ASSERT(expr->target()->IsValidReferenceExpression()); + Comment cmnt(masm_, "[ Assignment"); - // Invalid left-hand sides are rewritten to have a 'throw ReferenceError' - // on the left-hand side. - if (!expr->target()->IsValidLeftHandSide()) { - VisitForEffect(expr->target()); - return; - } // Left-hand side can only be a property, a global or a (parameter or local) // slot. @@ -1967,7 +1933,7 @@ void FullCodeGenerator::VisitYield(Yield* expr) { __ cmp(esp, ebx); __ j(equal, &post_runtime); __ push(eax); // generator object - __ CallRuntime(Runtime::kSuspendJSGeneratorObject, 1); + __ CallRuntime(Runtime::kHiddenSuspendJSGeneratorObject, 1); __ mov(context_register(), Operand(ebp, StandardFrameConstants::kContextOffset)); __ bind(&post_runtime); @@ -2035,7 +2001,7 @@ void FullCodeGenerator::VisitYield(Yield* expr) { __ mov(ecx, esi); __ RecordWriteField(eax, JSGeneratorObject::kContextOffset, ecx, edx, kDontSaveFPRegs); - __ CallRuntime(Runtime::kSuspendJSGeneratorObject, 1); + __ CallRuntime(Runtime::kHiddenSuspendJSGeneratorObject, 1); __ mov(context_register(), Operand(ebp, StandardFrameConstants::kContextOffset)); __ pop(eax); // result @@ -2052,29 +2018,33 @@ void FullCodeGenerator::VisitYield(Yield* expr) { // result = receiver[f](arg); __ bind(&l_call); - Handle<Code> ic = isolate()->stub_cache()->ComputeKeyedCallInitialize(1); - CallIC(ic); + __ mov(edx, Operand(esp, kPointerSize)); + Handle<Code> ic = isolate()->builtins()->KeyedLoadIC_Initialize(); + CallIC(ic, TypeFeedbackId::None()); + __ mov(edi, eax); + __ mov(Operand(esp, 2 * kPointerSize), edi); + CallFunctionStub stub(isolate(), 1, CALL_AS_METHOD); + __ CallStub(&stub); + __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset)); - __ Drop(1); // The key is still on the stack; drop it. + __ Drop(1); // The function is still on the stack; drop it. // if (!result.done) goto l_try; __ bind(&l_loop); __ push(eax); // save result __ mov(edx, eax); // result __ mov(ecx, isolate()->factory()->done_string()); // "done" - Handle<Code> done_ic = isolate()->builtins()->LoadIC_Initialize(); - CallIC(done_ic); // result.done in eax + CallLoadIC(NOT_CONTEXTUAL); // result.done in eax Handle<Code> bool_ic = ToBooleanStub::GetUninitialized(isolate()); CallIC(bool_ic); __ test(eax, eax); __ j(zero, &l_try); // result.value - __ pop(edx); // result + __ pop(edx); // result __ mov(ecx, isolate()->factory()->value_string()); // "value" - Handle<Code> value_ic = isolate()->builtins()->LoadIC_Initialize(); - CallIC(value_ic); // result.value in eax - context()->DropAndPlug(2, eax); // drop iter and g + CallLoadIC(NOT_CONTEXTUAL); // result.value in eax + context()->DropAndPlug(2, eax); // drop iter and g break; } } @@ -2085,19 +2055,21 @@ void FullCodeGenerator::EmitGeneratorResume(Expression *generator, Expression *value, JSGeneratorObject::ResumeMode resume_mode) { // The value stays in eax, and is ultimately read by the resumed generator, as - // if the CallRuntime(Runtime::kSuspendJSGeneratorObject) returned it. ebx - // will hold the generator object until the activation has been resumed. + // if CallRuntime(Runtime::kHiddenSuspendJSGeneratorObject) returned it. Or it + // is read to throw the value when the resumed generator is already closed. + // ebx will hold the generator object until the activation has been resumed. VisitForStackValue(generator); VisitForAccumulatorValue(value); __ pop(ebx); // Check generator state. - Label wrong_state, done; - STATIC_ASSERT(JSGeneratorObject::kGeneratorExecuting <= 0); - STATIC_ASSERT(JSGeneratorObject::kGeneratorClosed <= 0); + Label wrong_state, closed_state, done; + STATIC_ASSERT(JSGeneratorObject::kGeneratorExecuting < 0); + STATIC_ASSERT(JSGeneratorObject::kGeneratorClosed == 0); __ cmp(FieldOperand(ebx, JSGeneratorObject::kContinuationOffset), Immediate(Smi::FromInt(0))); - __ j(less_equal, &wrong_state); + __ j(equal, &closed_state); + __ j(less, &wrong_state); // Load suspended function and context. __ mov(esi, FieldOperand(ebx, JSGeneratorObject::kContextOffset)); @@ -2163,14 +2135,28 @@ void FullCodeGenerator::EmitGeneratorResume(Expression *generator, __ push(ebx); __ push(result_register()); __ Push(Smi::FromInt(resume_mode)); - __ CallRuntime(Runtime::kResumeJSGeneratorObject, 3); + __ CallRuntime(Runtime::kHiddenResumeJSGeneratorObject, 3); // Not reached: the runtime call returns elsewhere. __ Abort(kGeneratorFailedToResume); + // Reach here when generator is closed. + __ bind(&closed_state); + if (resume_mode == JSGeneratorObject::NEXT) { + // Return completed iterator result when generator is closed. + __ push(Immediate(isolate()->factory()->undefined_value())); + // Pop value from top-of-stack slot; box result into result register. + EmitCreateIteratorResult(true); + } else { + // Throw the provided value. + __ push(eax); + __ CallRuntime(Runtime::kHiddenThrow, 1); + } + __ jmp(&done); + // Throw error if we attempt to operate on a running generator. __ bind(&wrong_state); __ push(ebx); - __ CallRuntime(Runtime::kThrowGeneratorStateError, 1); + __ CallRuntime(Runtime::kHiddenThrowGeneratorStateError, 1); __ bind(&done); context()->Plug(result_register()); @@ -2181,14 +2167,14 @@ void FullCodeGenerator::EmitCreateIteratorResult(bool done) { Label gc_required; Label allocated; - Handle<Map> map(isolate()->native_context()->generator_result_map()); + Handle<Map> map(isolate()->native_context()->iterator_result_map()); __ Allocate(map->instance_size(), eax, ecx, edx, &gc_required, TAG_OBJECT); __ jmp(&allocated); __ bind(&gc_required); __ Push(Smi::FromInt(map->instance_size())); - __ CallRuntime(Runtime::kAllocateInNewSpace, 1); + __ CallRuntime(Runtime::kHiddenAllocateInNewSpace, 1); __ mov(context_register(), Operand(ebp, StandardFrameConstants::kContextOffset)); @@ -2217,15 +2203,14 @@ void FullCodeGenerator::EmitNamedPropertyLoad(Property* prop) { Literal* key = prop->key()->AsLiteral(); ASSERT(!key->value()->IsSmi()); __ mov(ecx, Immediate(key->value())); - Handle<Code> ic = isolate()->builtins()->LoadIC_Initialize(); - CallIC(ic, RelocInfo::CODE_TARGET, prop->PropertyFeedbackId()); + CallLoadIC(NOT_CONTEXTUAL, prop->PropertyFeedbackId()); } void FullCodeGenerator::EmitKeyedPropertyLoad(Property* prop) { SetSourcePosition(prop->position()); Handle<Code> ic = isolate()->builtins()->KeyedLoadIC_Initialize(); - CallIC(ic, RelocInfo::CODE_TARGET, prop->PropertyFeedbackId()); + CallIC(ic, prop->PropertyFeedbackId()); } @@ -2245,9 +2230,8 @@ void FullCodeGenerator::EmitInlineSmiBinaryOp(BinaryOperation* expr, __ bind(&stub_call); __ mov(eax, ecx); - BinaryOpICStub stub(op, mode); - CallIC(stub.GetCode(isolate()), RelocInfo::CODE_TARGET, - expr->BinaryOperationFeedbackId()); + BinaryOpICStub stub(isolate(), op, mode); + CallIC(stub.GetCode(), expr->BinaryOperationFeedbackId()); patch_site.EmitPatchInfo(); __ jmp(&done, Label::kNear); @@ -2257,10 +2241,9 @@ void FullCodeGenerator::EmitInlineSmiBinaryOp(BinaryOperation* expr, switch (op) { case Token::SAR: - __ SmiUntag(eax); __ SmiUntag(ecx); __ sar_cl(eax); // No checks of result necessary - __ SmiTag(eax); + __ and_(eax, Immediate(~kSmiTagMask)); break; case Token::SHL: { Label result_ok; @@ -2330,22 +2313,16 @@ void FullCodeGenerator::EmitBinaryOp(BinaryOperation* expr, Token::Value op, OverwriteMode mode) { __ pop(edx); - BinaryOpICStub stub(op, mode); + BinaryOpICStub stub(isolate(), op, mode); JumpPatchSite patch_site(masm_); // unbound, signals no inlined smi code. - CallIC(stub.GetCode(isolate()), RelocInfo::CODE_TARGET, - expr->BinaryOperationFeedbackId()); + CallIC(stub.GetCode(), expr->BinaryOperationFeedbackId()); patch_site.EmitPatchInfo(); context()->Plug(eax); } void FullCodeGenerator::EmitAssignment(Expression* expr) { - // Invalid left-hand sides are rewritten by the parser to have a 'throw - // ReferenceError' on the left-hand side. - if (!expr->IsValidLeftHandSide()) { - VisitForEffect(expr); - return; - } + ASSERT(expr->IsValidReferenceExpression()); // Left-hand side can only be a property, a global or a (parameter or local) // slot. @@ -2371,10 +2348,7 @@ void FullCodeGenerator::EmitAssignment(Expression* expr) { __ mov(edx, eax); __ pop(eax); // Restore value. __ mov(ecx, prop->key()->AsLiteral()->value()); - Handle<Code> ic = is_classic_mode() - ? isolate()->builtins()->StoreIC_Initialize() - : isolate()->builtins()->StoreIC_Initialize_Strict(); - CallIC(ic); + CallStoreIC(); break; } case KEYED_PROPERTY: { @@ -2384,7 +2358,7 @@ void FullCodeGenerator::EmitAssignment(Expression* expr) { __ mov(ecx, eax); __ pop(edx); // Receiver. __ pop(eax); // Restore value. - Handle<Code> ic = is_classic_mode() + Handle<Code> ic = strict_mode() == SLOPPY ? isolate()->builtins()->KeyedStoreIC_Initialize() : isolate()->builtins()->KeyedStoreIC_Initialize_Strict(); CallIC(ic); @@ -2395,48 +2369,58 @@ void FullCodeGenerator::EmitAssignment(Expression* expr) { } +void FullCodeGenerator::EmitStoreToStackLocalOrContextSlot( + Variable* var, MemOperand location) { + __ mov(location, eax); + if (var->IsContextSlot()) { + __ mov(edx, eax); + int offset = Context::SlotOffset(var->index()); + __ RecordWriteContextSlot(ecx, offset, edx, ebx, kDontSaveFPRegs); + } +} + + +void FullCodeGenerator::EmitCallStoreContextSlot( + Handle<String> name, StrictMode strict_mode) { + __ push(eax); // Value. + __ push(esi); // Context. + __ push(Immediate(name)); + __ push(Immediate(Smi::FromInt(strict_mode))); + __ CallRuntime(Runtime::kHiddenStoreContextSlot, 4); +} + + void FullCodeGenerator::EmitVariableAssignment(Variable* var, Token::Value op) { if (var->IsUnallocated()) { // Global var, const, or let. __ mov(ecx, var->name()); __ mov(edx, GlobalObjectOperand()); - Handle<Code> ic = is_classic_mode() - ? isolate()->builtins()->StoreIC_Initialize() - : isolate()->builtins()->StoreIC_Initialize_Strict(); - CallIC(ic, RelocInfo::CODE_TARGET_CONTEXT); + CallStoreIC(); - } else if (op == Token::INIT_CONST) { + } else if (op == Token::INIT_CONST_LEGACY) { // Const initializers need a write barrier. ASSERT(!var->IsParameter()); // No const parameters. - if (var->IsStackLocal()) { - Label skip; - __ mov(edx, StackOperand(var)); - __ cmp(edx, isolate()->factory()->the_hole_value()); - __ j(not_equal, &skip); - __ mov(StackOperand(var), eax); - __ bind(&skip); - } else { - ASSERT(var->IsContextSlot() || var->IsLookupSlot()); - // Like var declarations, const declarations are hoisted to function - // scope. However, unlike var initializers, const initializers are - // able to drill a hole to that function context, even from inside a - // 'with' context. We thus bypass the normal static scope lookup for - // var->IsContextSlot(). + if (var->IsLookupSlot()) { __ push(eax); __ push(esi); __ push(Immediate(var->name())); - __ CallRuntime(Runtime::kInitializeConstContextSlot, 3); + __ CallRuntime(Runtime::kHiddenInitializeConstContextSlot, 3); + } else { + ASSERT(var->IsStackLocal() || var->IsContextSlot()); + Label skip; + MemOperand location = VarOperand(var, ecx); + __ mov(edx, location); + __ cmp(edx, isolate()->factory()->the_hole_value()); + __ j(not_equal, &skip, Label::kNear); + EmitStoreToStackLocalOrContextSlot(var, location); + __ bind(&skip); } } else if (var->mode() == LET && op != Token::INIT_LET) { // Non-initializing assignment to let variable needs a write barrier. if (var->IsLookupSlot()) { - __ push(eax); // Value. - __ push(esi); // Context. - __ push(Immediate(var->name())); - __ push(Immediate(Smi::FromInt(language_mode()))); - __ CallRuntime(Runtime::kStoreContextSlot, 4); + EmitCallStoreContextSlot(var->name(), strict_mode()); } else { ASSERT(var->IsStackAllocated() || var->IsContextSlot()); Label assign; @@ -2445,20 +2429,18 @@ void FullCodeGenerator::EmitVariableAssignment(Variable* var, __ cmp(edx, isolate()->factory()->the_hole_value()); __ j(not_equal, &assign, Label::kNear); __ push(Immediate(var->name())); - __ CallRuntime(Runtime::kThrowReferenceError, 1); + __ CallRuntime(Runtime::kHiddenThrowReferenceError, 1); __ bind(&assign); - __ mov(location, eax); - if (var->IsContextSlot()) { - __ mov(edx, eax); - int offset = Context::SlotOffset(var->index()); - __ RecordWriteContextSlot(ecx, offset, edx, ebx, kDontSaveFPRegs); - } + EmitStoreToStackLocalOrContextSlot(var, location); } - } else if (!var->is_const_mode() || op == Token::INIT_CONST_HARMONY) { + } else if (!var->is_const_mode() || op == Token::INIT_CONST) { // Assignment to var or initializing assignment to let/const // in harmony mode. - if (var->IsStackAllocated() || var->IsContextSlot()) { + if (var->IsLookupSlot()) { + EmitCallStoreContextSlot(var->name(), strict_mode()); + } else { + ASSERT(var->IsStackAllocated() || var->IsContextSlot()); MemOperand location = VarOperand(var, ecx); if (generate_debug_code_ && op == Token::INIT_LET) { // Check for an uninitialized let binding. @@ -2466,20 +2448,7 @@ void FullCodeGenerator::EmitVariableAssignment(Variable* var, __ cmp(edx, isolate()->factory()->the_hole_value()); __ Check(equal, kLetBindingReInitialization); } - // Perform the assignment. - __ mov(location, eax); - if (var->IsContextSlot()) { - __ mov(edx, eax); - int offset = Context::SlotOffset(var->index()); - __ RecordWriteContextSlot(ecx, offset, edx, ebx, kDontSaveFPRegs); - } - } else { - ASSERT(var->IsLookupSlot()); - __ push(eax); // Value. - __ push(esi); // Context. - __ push(Immediate(var->name())); - __ push(Immediate(Smi::FromInt(language_mode()))); - __ CallRuntime(Runtime::kStoreContextSlot, 4); + EmitStoreToStackLocalOrContextSlot(var, location); } } // Non-initializing assignments to consts are ignored. @@ -2493,17 +2462,13 @@ void FullCodeGenerator::EmitNamedPropertyAssignment(Assignment* expr) { Property* prop = expr->target()->AsProperty(); ASSERT(prop != NULL); - ASSERT(prop->key()->AsLiteral() != NULL); + ASSERT(prop->key()->IsLiteral()); // Record source code position before IC call. SetSourcePosition(expr->position()); __ mov(ecx, prop->key()->AsLiteral()->value()); __ pop(edx); - Handle<Code> ic = is_classic_mode() - ? isolate()->builtins()->StoreIC_Initialize() - : isolate()->builtins()->StoreIC_Initialize_Strict(); - CallIC(ic, RelocInfo::CODE_TARGET, expr->AssignmentFeedbackId()); - + CallStoreIC(expr->AssignmentFeedbackId()); PrepareForBailoutForId(expr->AssignmentId(), TOS_REG); context()->Plug(eax); } @@ -2519,10 +2484,10 @@ void FullCodeGenerator::EmitKeyedPropertyAssignment(Assignment* expr) { __ pop(edx); // Record source code position before IC call. SetSourcePosition(expr->position()); - Handle<Code> ic = is_classic_mode() + Handle<Code> ic = strict_mode() == SLOPPY ? isolate()->builtins()->KeyedStoreIC_Initialize() : isolate()->builtins()->KeyedStoreIC_Initialize_Strict(); - CallIC(ic, RelocInfo::CODE_TARGET, expr->AssignmentFeedbackId()); + CallIC(ic, expr->AssignmentFeedbackId()); PrepareForBailoutForId(expr->AssignmentId(), TOS_REG); context()->Plug(eax); @@ -2551,73 +2516,69 @@ void FullCodeGenerator::VisitProperty(Property* expr) { void FullCodeGenerator::CallIC(Handle<Code> code, - RelocInfo::Mode rmode, TypeFeedbackId ast_id) { ic_total_count_++; - __ call(code, rmode, ast_id); + __ call(code, RelocInfo::CODE_TARGET, ast_id); } +// Code common for calls using the IC. +void FullCodeGenerator::EmitCallWithLoadIC(Call* expr) { + Expression* callee = expr->expression(); - -void FullCodeGenerator::EmitCallWithIC(Call* expr, - Handle<Object> name, - RelocInfo::Mode mode) { - // Code common for calls using the IC. - ZoneList<Expression*>* args = expr->arguments(); - int arg_count = args->length(); - { PreservePositionScope scope(masm()->positions_recorder()); - for (int i = 0; i < arg_count; i++) { - VisitForStackValue(args->at(i)); + CallIC::CallType call_type = callee->IsVariableProxy() + ? CallIC::FUNCTION + : CallIC::METHOD; + // Get the target function. + if (call_type == CallIC::FUNCTION) { + { StackValueContext context(this); + EmitVariableLoad(callee->AsVariableProxy()); + PrepareForBailout(callee, NO_REGISTERS); } - __ Set(ecx, Immediate(name)); + // Push undefined as receiver. This is patched in the method prologue if it + // is a sloppy mode method. + __ push(Immediate(isolate()->factory()->undefined_value())); + } else { + // Load the function from the receiver. + ASSERT(callee->IsProperty()); + __ mov(edx, Operand(esp, 0)); + EmitNamedPropertyLoad(callee->AsProperty()); + PrepareForBailoutForId(callee->AsProperty()->LoadId(), TOS_REG); + // Push the target function under the receiver. + __ push(Operand(esp, 0)); + __ mov(Operand(esp, kPointerSize), eax); } - // Record source position of the IC call. - SetSourcePosition(expr->position()); - Handle<Code> ic = - isolate()->stub_cache()->ComputeCallInitialize(arg_count, mode); - CallIC(ic, mode, expr->CallFeedbackId()); - RecordJSReturnSite(expr); - // Restore context register. - __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset)); - context()->Plug(eax); + + EmitCall(expr, call_type); } -void FullCodeGenerator::EmitKeyedCallWithIC(Call* expr, - Expression* key) { +// Code common for calls using the IC. +void FullCodeGenerator::EmitKeyedCallWithLoadIC(Call* expr, + Expression* key) { // Load the key. VisitForAccumulatorValue(key); - // Swap the name of the function and the receiver on the stack to follow - // the calling convention for call ICs. - __ pop(ecx); - __ push(eax); - __ push(ecx); + Expression* callee = expr->expression(); - // Load the arguments. - ZoneList<Expression*>* args = expr->arguments(); - int arg_count = args->length(); - { PreservePositionScope scope(masm()->positions_recorder()); - for (int i = 0; i < arg_count; i++) { - VisitForStackValue(args->at(i)); - } - } - // Record source position of the IC call. - SetSourcePosition(expr->position()); - Handle<Code> ic = - isolate()->stub_cache()->ComputeKeyedCallInitialize(arg_count); - __ mov(ecx, Operand(esp, (arg_count + 1) * kPointerSize)); // Key. - CallIC(ic, RelocInfo::CODE_TARGET, expr->CallFeedbackId()); - RecordJSReturnSite(expr); - // Restore context register. - __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset)); - context()->DropAndPlug(1, eax); // Drop the key still on the stack. + // Load the function from the receiver. + ASSERT(callee->IsProperty()); + __ mov(edx, Operand(esp, 0)); + // Move the key into the right register for the keyed load IC. + __ mov(ecx, eax); + EmitKeyedPropertyLoad(callee->AsProperty()); + PrepareForBailoutForId(callee->AsProperty()->LoadId(), TOS_REG); + + // Push the target function under the receiver. + __ push(Operand(esp, 0)); + __ mov(Operand(esp, kPointerSize), eax); + + EmitCall(expr, CallIC::METHOD); } -void FullCodeGenerator::EmitCallWithStub(Call* expr, CallFunctionFlags flags) { - // Code common for calls using the call stub. +void FullCodeGenerator::EmitCall(Call* expr, CallIC::CallType call_type) { + // Load the arguments. ZoneList<Expression*>* args = expr->arguments(); int arg_count = args->length(); { PreservePositionScope scope(masm()->positions_recorder()); @@ -2625,24 +2586,22 @@ void FullCodeGenerator::EmitCallWithStub(Call* expr, CallFunctionFlags flags) { VisitForStackValue(args->at(i)); } } - // Record source position for debugger. - SetSourcePosition(expr->position()); - // Record call targets in unoptimized code. - flags = static_cast<CallFunctionFlags>(flags | RECORD_CALL_TARGET); - Handle<Object> uninitialized = - TypeFeedbackCells::UninitializedSentinel(isolate()); - Handle<Cell> cell = isolate()->factory()->NewCell(uninitialized); - RecordTypeFeedbackCell(expr->CallFeedbackId(), cell); - __ mov(ebx, cell); - - CallFunctionStub stub(arg_count, flags); + // Record source position of the IC call. + SetSourcePosition(expr->position()); + Handle<Code> ic = CallIC::initialize_stub( + isolate(), arg_count, call_type); + __ Move(edx, Immediate(Smi::FromInt(expr->CallFeedbackSlot()))); __ mov(edi, Operand(esp, (arg_count + 1) * kPointerSize)); - __ CallStub(&stub, expr->CallFeedbackId()); + // Don't assign a type feedback id to the IC, since type feedback is provided + // by the vector above. + CallIC(ic); RecordJSReturnSite(expr); + // Restore context register. __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset)); + context()->DropAndPlug(1, eax); } @@ -2658,13 +2617,13 @@ void FullCodeGenerator::EmitResolvePossiblyDirectEval(int arg_count) { // Push the receiver of the enclosing function. __ push(Operand(ebp, (2 + info_->scope()->num_parameters()) * kPointerSize)); // Push the language mode. - __ push(Immediate(Smi::FromInt(language_mode()))); + __ push(Immediate(Smi::FromInt(strict_mode()))); // Push the start position of the scope the calls resides in. __ push(Immediate(Smi::FromInt(scope()->start_position()))); // Do the runtime call. - __ CallRuntime(Runtime::kResolvePossiblyDirectEval, 5); + __ CallRuntime(Runtime::kHiddenResolvePossiblyDirectEval, 5); } @@ -2677,12 +2636,11 @@ void FullCodeGenerator::VisitCall(Call* expr) { Comment cmnt(masm_, "[ Call"); Expression* callee = expr->expression(); - VariableProxy* proxy = callee->AsVariableProxy(); - Property* property = callee->AsProperty(); + Call::CallType call_type = expr->GetCallType(isolate()); - if (proxy != NULL && proxy->var()->is_possibly_eval(isolate())) { - // In a call to eval, we first call %ResolvePossiblyDirectEval to - // resolve the function we need to call and the receiver of the call. + if (call_type == Call::POSSIBLY_EVAL_CALL) { + // In a call to eval, we first call RuntimeHidden_ResolvePossiblyDirectEval + // to resolve the function we need to call and the receiver of the call. // Then we call the resolved function using the given arguments. ZoneList<Expression*>* args = expr->arguments(); int arg_count = args->length(); @@ -2707,7 +2665,7 @@ void FullCodeGenerator::VisitCall(Call* expr) { } // Record source position for debugger. SetSourcePosition(expr->position()); - CallFunctionStub stub(arg_count, RECEIVER_MIGHT_BE_IMPLICIT); + CallFunctionStub stub(isolate(), arg_count, NO_CALL_FUNCTION_FLAGS); __ mov(edi, Operand(esp, (arg_count + 1) * kPointerSize)); __ CallStub(&stub); RecordJSReturnSite(expr); @@ -2715,13 +2673,12 @@ void FullCodeGenerator::VisitCall(Call* expr) { __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset)); context()->DropAndPlug(1, eax); - } else if (proxy != NULL && proxy->var()->IsUnallocated()) { - // Push global object as receiver for the call IC. - __ push(GlobalObjectOperand()); - EmitCallWithIC(expr, proxy->name(), RelocInfo::CODE_TARGET_CONTEXT); + } else if (call_type == Call::GLOBAL_CALL) { + EmitCallWithLoadIC(expr); - } else if (proxy != NULL && proxy->var()->IsLookupSlot()) { + } else if (call_type == Call::LOOKUP_SLOT_CALL) { // Call to a lookup slot (dynamically introduced variable). + VariableProxy* proxy = callee->AsVariableProxy(); Label slow, done; { PreservePositionScope scope(masm()->positions_recorder()); // Generate code for loading from variables potentially shadowed by @@ -2733,7 +2690,7 @@ void FullCodeGenerator::VisitCall(Call* expr) { // the object holding it (returned in edx). __ push(context_register()); __ push(Immediate(proxy->name())); - __ CallRuntime(Runtime::kLoadContextSlot, 2); + __ CallRuntime(Runtime::kHiddenLoadContextSlot, 2); __ push(eax); // Function. __ push(edx); // Receiver. @@ -2747,37 +2704,34 @@ void FullCodeGenerator::VisitCall(Call* expr) { __ push(eax); // The receiver is implicitly the global receiver. Indicate this by // passing the hole to the call function stub. - __ push(Immediate(isolate()->factory()->the_hole_value())); + __ push(Immediate(isolate()->factory()->undefined_value())); __ bind(&call); } // The receiver is either the global receiver or an object found by - // LoadContextSlot. That object could be the hole if the receiver is - // implicitly the global object. - EmitCallWithStub(expr, RECEIVER_MIGHT_BE_IMPLICIT); + // LoadContextSlot. + EmitCall(expr); - } else if (property != NULL) { + } else if (call_type == Call::PROPERTY_CALL) { + Property* property = callee->AsProperty(); { PreservePositionScope scope(masm()->positions_recorder()); VisitForStackValue(property->obj()); } if (property->key()->IsPropertyName()) { - EmitCallWithIC(expr, - property->key()->AsLiteral()->value(), - RelocInfo::CODE_TARGET); + EmitCallWithLoadIC(expr); } else { - EmitKeyedCallWithIC(expr, property->key()); + EmitKeyedCallWithLoadIC(expr, property->key()); } } else { + ASSERT(call_type == Call::OTHER_CALL); // Call to an arbitrary expression not handled specially above. { PreservePositionScope scope(masm()->positions_recorder()); VisitForStackValue(callee); } - // Load global receiver object. - __ mov(ebx, GlobalObjectOperand()); - __ push(FieldOperand(ebx, GlobalObject::kGlobalReceiverOffset)); + __ push(Immediate(isolate()->factory()->undefined_value())); // Emit function call. - EmitCallWithStub(expr, NO_CALL_FUNCTION_FLAGS); + EmitCall(expr); } #ifdef DEBUG @@ -2810,18 +2764,21 @@ void FullCodeGenerator::VisitCallNew(CallNew* expr) { SetSourcePosition(expr->position()); // Load function and argument count into edi and eax. - __ Set(eax, Immediate(arg_count)); + __ Move(eax, Immediate(arg_count)); __ mov(edi, Operand(esp, arg_count * kPointerSize)); // Record call targets in unoptimized code. - Handle<Object> uninitialized = - TypeFeedbackCells::UninitializedSentinel(isolate()); - Handle<Cell> cell = isolate()->factory()->NewCell(uninitialized); - RecordTypeFeedbackCell(expr->CallNewFeedbackId(), cell); - __ mov(ebx, cell); - - CallConstructStub stub(RECORD_CALL_TARGET); - __ call(stub.GetCode(isolate()), RelocInfo::CONSTRUCT_CALL); + if (FLAG_pretenuring_call_new) { + EnsureSlotContainsAllocationSite(expr->AllocationSiteFeedbackSlot()); + ASSERT(expr->AllocationSiteFeedbackSlot() == + expr->CallNewFeedbackSlot() + 1); + } + + __ LoadHeapObject(ebx, FeedbackVector()); + __ mov(edx, Immediate(Smi::FromInt(expr->CallNewFeedbackSlot()))); + + CallConstructStub stub(isolate(), RECORD_CONSTRUCTOR_TARGET); + __ call(stub.GetCode(), RelocInfo::CONSTRUCT_CALL); PrepareForBailoutForId(expr->ReturnId(), TOS_REG); context()->Plug(eax); } @@ -2994,7 +2951,7 @@ void FullCodeGenerator::EmitIsStringWrapperSafeForDefaultValueOf( STATIC_ASSERT(kSmiTagSize == 1); STATIC_ASSERT(kPointerSize == 4); __ imul(ecx, ecx, DescriptorArray::kDescriptorSize); - __ lea(ecx, Operand(ebx, ecx, times_2, DescriptorArray::kFirstOffset)); + __ lea(ecx, Operand(ebx, ecx, times_4, DescriptorArray::kFirstOffset)); // Calculate location of the first key name. __ add(ebx, Immediate(DescriptorArray::kFirstOffset)); // Loop through all the keys in the descriptor array. If one of these is the @@ -3075,9 +3032,11 @@ void FullCodeGenerator::EmitIsMinusZero(CallRuntime* expr) { Handle<Map> map = masm()->isolate()->factory()->heap_number_map(); __ CheckMap(eax, map, if_false, DO_SMI_CHECK); - __ cmp(FieldOperand(eax, HeapNumber::kExponentOffset), Immediate(0x80000000)); - __ j(not_equal, if_false); - __ cmp(FieldOperand(eax, HeapNumber::kMantissaOffset), Immediate(0x00000000)); + // Check if the exponent half is 0x80000000. Comparing against 1 and + // checking for overflow is the shortest possible encoding. + __ cmp(FieldOperand(eax, HeapNumber::kExponentOffset), Immediate(0x1)); + __ j(no_overflow, if_false); + __ cmp(FieldOperand(eax, HeapNumber::kMantissaOffset), Immediate(0x0)); PrepareForBailoutBeforeSplit(expr, true, if_true, if_false); Split(equal, if_true, if_false, fall_through); @@ -3194,8 +3153,8 @@ void FullCodeGenerator::EmitArguments(CallRuntime* expr) { // parameter count in eax. VisitForAccumulatorValue(args->at(0)); __ mov(edx, eax); - __ Set(eax, Immediate(Smi::FromInt(info_->scope()->num_parameters()))); - ArgumentsAccessStub stub(ArgumentsAccessStub::READ_ELEMENT); + __ Move(eax, Immediate(Smi::FromInt(info_->scope()->num_parameters()))); + ArgumentsAccessStub stub(isolate(), ArgumentsAccessStub::READ_ELEMENT); __ CallStub(&stub); context()->Plug(eax); } @@ -3206,7 +3165,7 @@ void FullCodeGenerator::EmitArgumentsLength(CallRuntime* expr) { Label exit; // Get the number of formal parameters. - __ Set(eax, Immediate(Smi::FromInt(info_->scope()->num_parameters()))); + __ Move(eax, Immediate(Smi::FromInt(info_->scope()->num_parameters()))); // Check if the calling frame is an arguments adaptor frame. __ mov(ebx, Operand(ebp, StandardFrameConstants::kCallerFPOffset)); @@ -3285,30 +3244,9 @@ void FullCodeGenerator::EmitClassOf(CallRuntime* expr) { } -void FullCodeGenerator::EmitLog(CallRuntime* expr) { - // Conditionally generate a log call. - // Args: - // 0 (literal string): The type of logging (corresponds to the flags). - // This is used to determine whether or not to generate the log call. - // 1 (string): Format string. Access the string at argument index 2 - // with '%2s' (see Logger::LogRuntime for all the formats). - // 2 (array): Arguments to the format string. - ZoneList<Expression*>* args = expr->arguments(); - ASSERT_EQ(args->length(), 3); - if (CodeGenerator::ShouldGenerateLog(isolate(), args->at(0))) { - VisitForStackValue(args->at(1)); - VisitForStackValue(args->at(2)); - __ CallRuntime(Runtime::kLog, 2); - } - // Finally, we're expected to leave a value on the top of the stack. - __ mov(eax, isolate()->factory()->undefined_value()); - context()->Plug(eax); -} - - void FullCodeGenerator::EmitSubString(CallRuntime* expr) { // Load the arguments on the stack and call the stub. - SubStringStub stub; + SubStringStub stub(isolate()); ZoneList<Expression*>* args = expr->arguments(); ASSERT(args->length() == 3); VisitForStackValue(args->at(0)); @@ -3321,7 +3259,7 @@ void FullCodeGenerator::EmitSubString(CallRuntime* expr) { void FullCodeGenerator::EmitRegExpExec(CallRuntime* expr) { // Load the arguments on the stack and call the stub. - RegExpExecStub stub; + RegExpExecStub stub(isolate()); ZoneList<Expression*>* args = expr->arguments(); ASSERT(args->length() == 4); VisitForStackValue(args->at(0)); @@ -3391,7 +3329,7 @@ void FullCodeGenerator::EmitDateField(CallRuntime* expr) { } __ bind(¬_date_object); - __ CallRuntime(Runtime::kThrowNotDateError, 0); + __ CallRuntime(Runtime::kHiddenThrowNotDateError, 0); __ bind(&done); context()->Plug(result); } @@ -3414,9 +3352,9 @@ void FullCodeGenerator::EmitOneByteSeqStringSetChar(CallRuntime* expr) { if (FLAG_debug_code) { __ test(value, Immediate(kSmiTagMask)); - __ ThrowIf(not_zero, kNonSmiValue); + __ Check(zero, kNonSmiValue); __ test(index, Immediate(kSmiTagMask)); - __ ThrowIf(not_zero, kNonSmiValue); + __ Check(zero, kNonSmiValue); } __ SmiUntag(value); @@ -3449,9 +3387,9 @@ void FullCodeGenerator::EmitTwoByteSeqStringSetChar(CallRuntime* expr) { if (FLAG_debug_code) { __ test(value, Immediate(kSmiTagMask)); - __ ThrowIf(not_zero, kNonSmiValue); + __ Check(zero, kNonSmiValue); __ test(index, Immediate(kSmiTagMask)); - __ ThrowIf(not_zero, kNonSmiValue); + __ Check(zero, kNonSmiValue); __ SmiUntag(index); static const uint32_t two_byte_seq_type = kSeqStringTag | kTwoByteStringTag; __ EmitSeqStringSetCharCheck(string, index, value, two_byte_seq_type); @@ -3473,12 +3411,8 @@ void FullCodeGenerator::EmitMathPow(CallRuntime* expr) { VisitForStackValue(args->at(0)); VisitForStackValue(args->at(1)); - if (CpuFeatures::IsSupported(SSE2)) { - MathPowStub stub(MathPowStub::ON_STACK); - __ CallStub(&stub); - } else { - __ CallRuntime(Runtime::kMath_pow, 2); - } + MathPowStub stub(isolate(), MathPowStub::ON_STACK); + __ CallStub(&stub); context()->Plug(eax); } @@ -3519,7 +3453,7 @@ void FullCodeGenerator::EmitNumberToString(CallRuntime* expr) { // Load the argument into eax and call the stub. VisitForAccumulatorValue(args->at(0)); - NumberToStringStub stub; + NumberToStringStub stub(isolate()); __ CallStub(&stub); context()->Plug(eax); } @@ -3573,13 +3507,13 @@ void FullCodeGenerator::EmitStringCharCodeAt(CallRuntime* expr) { __ bind(&index_out_of_range); // When the index is out of range, the spec requires us to return // NaN. - __ Set(result, Immediate(isolate()->factory()->nan_value())); + __ Move(result, Immediate(isolate()->factory()->nan_value())); __ jmp(&done); __ bind(&need_conversion); // Move the undefined value into the result register, which will // trigger conversion. - __ Set(result, Immediate(isolate()->factory()->undefined_value())); + __ Move(result, Immediate(isolate()->factory()->undefined_value())); __ jmp(&done); NopRuntimeCallHelper call_helper; @@ -3621,13 +3555,13 @@ void FullCodeGenerator::EmitStringCharAt(CallRuntime* expr) { __ bind(&index_out_of_range); // When the index is out of range, the spec requires us to return // the empty string. - __ Set(result, Immediate(isolate()->factory()->empty_string())); + __ Move(result, Immediate(isolate()->factory()->empty_string())); __ jmp(&done); __ bind(&need_conversion); // Move smi zero into the result register, which will trigger // conversion. - __ Set(result, Immediate(Smi::FromInt(0))); + __ Move(result, Immediate(Smi::FromInt(0))); __ jmp(&done); NopRuntimeCallHelper call_helper; @@ -3641,21 +3575,12 @@ void FullCodeGenerator::EmitStringCharAt(CallRuntime* expr) { void FullCodeGenerator::EmitStringAdd(CallRuntime* expr) { ZoneList<Expression*>* args = expr->arguments(); ASSERT_EQ(2, args->length()); + VisitForStackValue(args->at(0)); + VisitForAccumulatorValue(args->at(1)); - if (FLAG_new_string_add) { - VisitForStackValue(args->at(0)); - VisitForAccumulatorValue(args->at(1)); - - __ pop(edx); - NewStringAddStub stub(STRING_ADD_CHECK_BOTH, NOT_TENURED); - __ CallStub(&stub); - } else { - VisitForStackValue(args->at(0)); - VisitForStackValue(args->at(1)); - - StringAddStub stub(STRING_ADD_CHECK_BOTH); - __ CallStub(&stub); - } + __ pop(edx); + StringAddStub stub(isolate(), STRING_ADD_CHECK_BOTH, NOT_TENURED); + __ CallStub(&stub); context()->Plug(eax); } @@ -3667,34 +3592,12 @@ void FullCodeGenerator::EmitStringCompare(CallRuntime* expr) { VisitForStackValue(args->at(0)); VisitForStackValue(args->at(1)); - StringCompareStub stub; + StringCompareStub stub(isolate()); __ CallStub(&stub); context()->Plug(eax); } -void FullCodeGenerator::EmitMathLog(CallRuntime* expr) { - // Load the argument on the stack and call the stub. - TranscendentalCacheStub stub(TranscendentalCache::LOG, - TranscendentalCacheStub::TAGGED); - ZoneList<Expression*>* args = expr->arguments(); - ASSERT(args->length() == 1); - VisitForStackValue(args->at(0)); - __ CallStub(&stub); - context()->Plug(eax); -} - - -void FullCodeGenerator::EmitMathSqrt(CallRuntime* expr) { - // Load the argument on the stack and call the runtime function. - ZoneList<Expression*>* args = expr->arguments(); - ASSERT(args->length() == 1); - VisitForStackValue(args->at(0)); - __ CallRuntime(Runtime::kMath_sqrt, 1); - context()->Plug(eax); -} - - void FullCodeGenerator::EmitCallFunction(CallRuntime* expr) { ZoneList<Expression*>* args = expr->arguments(); ASSERT(args->length() >= 2); @@ -3714,8 +3617,7 @@ void FullCodeGenerator::EmitCallFunction(CallRuntime* expr) { // InvokeFunction requires the function in edi. Move it in there. __ mov(edi, result_register()); ParameterCount count(arg_count); - __ InvokeFunction(edi, count, CALL_FUNCTION, - NullCallWrapper(), CALL_AS_METHOD); + __ InvokeFunction(edi, count, CALL_FUNCTION, NullCallWrapper()); __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset)); __ jmp(&done); @@ -3730,12 +3632,14 @@ void FullCodeGenerator::EmitCallFunction(CallRuntime* expr) { void FullCodeGenerator::EmitRegExpConstructResult(CallRuntime* expr) { // Load the arguments on the stack and call the stub. - RegExpConstructResultStub stub; + RegExpConstructResultStub stub(isolate()); ZoneList<Expression*>* args = expr->arguments(); ASSERT(args->length() == 3); VisitForStackValue(args->at(0)); VisitForStackValue(args->at(1)); - VisitForStackValue(args->at(2)); + VisitForAccumulatorValue(args->at(2)); + __ pop(ebx); + __ pop(ecx); __ CallStub(&stub); context()->Plug(eax); } @@ -3770,60 +3674,22 @@ void FullCodeGenerator::EmitGetFromCache(CallRuntime* expr) { FieldOperand(cache, FixedArray::OffsetOfElementAt(cache_id))); Label done, not_found; - // tmp now holds finger offset as a smi. STATIC_ASSERT(kSmiTag == 0 && kSmiTagSize == 1); __ mov(tmp, FieldOperand(cache, JSFunctionResultCache::kFingerOffset)); - __ cmp(key, CodeGenerator::FixedArrayElementOperand(cache, tmp)); + // tmp now holds finger offset as a smi. + __ cmp(key, FixedArrayElementOperand(cache, tmp)); __ j(not_equal, ¬_found); - __ mov(eax, CodeGenerator::FixedArrayElementOperand(cache, tmp, 1)); + __ mov(eax, FixedArrayElementOperand(cache, tmp, 1)); __ jmp(&done); __ bind(¬_found); // Call runtime to perform the lookup. __ push(cache); __ push(key); - __ CallRuntime(Runtime::kGetFromCache, 2); - - __ bind(&done); - context()->Plug(eax); -} - + __ CallRuntime(Runtime::kHiddenGetFromCache, 2); -void FullCodeGenerator::EmitIsRegExpEquivalent(CallRuntime* expr) { - ZoneList<Expression*>* args = expr->arguments(); - ASSERT_EQ(2, args->length()); - - Register right = eax; - Register left = ebx; - Register tmp = ecx; - - VisitForStackValue(args->at(0)); - VisitForAccumulatorValue(args->at(1)); - __ pop(left); - - Label done, fail, ok; - __ cmp(left, right); - __ j(equal, &ok); - // Fail if either is a non-HeapObject. - __ mov(tmp, left); - __ and_(tmp, right); - __ JumpIfSmi(tmp, &fail); - __ mov(tmp, FieldOperand(left, HeapObject::kMapOffset)); - __ CmpInstanceType(tmp, JS_REGEXP_TYPE); - __ j(not_equal, &fail); - __ cmp(tmp, FieldOperand(right, HeapObject::kMapOffset)); - __ j(not_equal, &fail); - __ mov(tmp, FieldOperand(left, JSRegExp::kDataOffset)); - __ cmp(tmp, FieldOperand(right, JSRegExp::kDataOffset)); - __ j(equal, &ok); - __ bind(&fail); - __ mov(eax, Immediate(isolate()->factory()->false_value())); - __ jmp(&done); - __ bind(&ok); - __ mov(eax, Immediate(isolate()->factory()->true_value())); __ bind(&done); - context()->Plug(eax); } @@ -3926,8 +3792,8 @@ void FullCodeGenerator::EmitFastAsciiArrayJoin(CallRuntime* expr) { // Check that all array elements are sequential ASCII strings, and // accumulate the sum of their lengths, as a smi-encoded value. - __ Set(index, Immediate(0)); - __ Set(string_length, Immediate(0)); + __ Move(index, Immediate(0)); + __ Move(string_length, Immediate(0)); // Loop condition: while (index < length). // Live loop registers: index, array_length, string, // scratch, string_length, elements. @@ -4043,7 +3909,7 @@ void FullCodeGenerator::EmitFastAsciiArrayJoin(CallRuntime* expr) { __ mov_b(scratch, FieldOperand(string, SeqOneByteString::kHeaderSize)); __ mov_b(separator_operand, scratch); - __ Set(index, Immediate(0)); + __ Move(index, Immediate(0)); // Jump into the loop after the code that copies the separator, so the first // element is not preceded by a separator __ jmp(&loop_2_entry); @@ -4080,7 +3946,7 @@ void FullCodeGenerator::EmitFastAsciiArrayJoin(CallRuntime* expr) { // Long separator case (separator is more than one character). __ bind(&long_separator); - __ Set(index, Immediate(0)); + __ Move(index, Immediate(0)); // Jump into the loop after the code that copies the separator, so the first // element is not preceded by a separator __ jmp(&loop_3_entry); @@ -4131,8 +3997,8 @@ void FullCodeGenerator::EmitFastAsciiArrayJoin(CallRuntime* expr) { void FullCodeGenerator::VisitCallRuntime(CallRuntime* expr) { - Handle<String> name = expr->name(); - if (name->length() > 0 && name->Get(0) == '_') { + if (expr->function() != NULL && + expr->function()->intrinsic_type == Runtime::INLINE) { Comment cmnt(masm_, "[ InlineRuntimeCall"); EmitInlineRuntimeCall(expr); return; @@ -4142,31 +4008,47 @@ void FullCodeGenerator::VisitCallRuntime(CallRuntime* expr) { ZoneList<Expression*>* args = expr->arguments(); if (expr->is_jsruntime()) { - // Prepare for calling JS runtime function. + // Push the builtins object as receiver. __ mov(eax, GlobalObjectOperand()); __ push(FieldOperand(eax, GlobalObject::kBuiltinsOffset)); - } - // Push the arguments ("left-to-right"). - int arg_count = args->length(); - for (int i = 0; i < arg_count; i++) { - VisitForStackValue(args->at(i)); - } + // Load the function from the receiver. + __ mov(edx, Operand(esp, 0)); + __ mov(ecx, Immediate(expr->name())); + CallLoadIC(NOT_CONTEXTUAL, expr->CallRuntimeFeedbackId()); - if (expr->is_jsruntime()) { - // Call the JS runtime function via a call IC. - __ Set(ecx, Immediate(expr->name())); - RelocInfo::Mode mode = RelocInfo::CODE_TARGET; - Handle<Code> ic = - isolate()->stub_cache()->ComputeCallInitialize(arg_count, mode); - CallIC(ic, mode, expr->CallRuntimeFeedbackId()); + // Push the target function under the receiver. + __ push(Operand(esp, 0)); + __ mov(Operand(esp, kPointerSize), eax); + + // Code common for calls using the IC. + ZoneList<Expression*>* args = expr->arguments(); + int arg_count = args->length(); + for (int i = 0; i < arg_count; i++) { + VisitForStackValue(args->at(i)); + } + + // Record source position of the IC call. + SetSourcePosition(expr->position()); + CallFunctionStub stub(isolate(), arg_count, NO_CALL_FUNCTION_FLAGS); + __ mov(edi, Operand(esp, (arg_count + 1) * kPointerSize)); + __ CallStub(&stub); // Restore context register. __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset)); + context()->DropAndPlug(1, eax); + } else { + // Push the arguments ("left-to-right"). + int arg_count = args->length(); + for (int i = 0; i < arg_count; i++) { + VisitForStackValue(args->at(i)); + } + // Call the C runtime function. __ CallRuntime(expr->function(), arg_count); + + context()->Plug(eax); } - context()->Plug(eax); } @@ -4180,20 +4062,18 @@ void FullCodeGenerator::VisitUnaryOperation(UnaryOperation* expr) { if (property != NULL) { VisitForStackValue(property->obj()); VisitForStackValue(property->key()); - StrictModeFlag strict_mode_flag = (language_mode() == CLASSIC_MODE) - ? kNonStrictMode : kStrictMode; - __ push(Immediate(Smi::FromInt(strict_mode_flag))); + __ push(Immediate(Smi::FromInt(strict_mode()))); __ InvokeBuiltin(Builtins::DELETE, CALL_FUNCTION); context()->Plug(eax); } else if (proxy != NULL) { Variable* var = proxy->var(); // Delete of an unqualified identifier is disallowed in strict mode // but "delete this" is allowed. - ASSERT(language_mode() == CLASSIC_MODE || var->is_this()); + ASSERT(strict_mode() == SLOPPY || var->is_this()); if (var->IsUnallocated()) { __ push(GlobalObjectOperand()); __ push(Immediate(var->name())); - __ push(Immediate(Smi::FromInt(kNonStrictMode))); + __ push(Immediate(Smi::FromInt(SLOPPY))); __ InvokeBuiltin(Builtins::DELETE, CALL_FUNCTION); context()->Plug(eax); } else if (var->IsStackAllocated() || var->IsContextSlot()) { @@ -4206,7 +4086,7 @@ void FullCodeGenerator::VisitUnaryOperation(UnaryOperation* expr) { // context where the variable was introduced. __ push(context_register()); __ push(Immediate(var->name())); - __ CallRuntime(Runtime::kDeleteContextSlot, 2); + __ CallRuntime(Runtime::kHiddenDeleteContextSlot, 2); context()->Plug(eax); } } else { @@ -4287,16 +4167,11 @@ void FullCodeGenerator::VisitUnaryOperation(UnaryOperation* expr) { void FullCodeGenerator::VisitCountOperation(CountOperation* expr) { + ASSERT(expr->expression()->IsValidReferenceExpression()); + Comment cmnt(masm_, "[ CountOperation"); SetSourcePosition(expr->position()); - // Invalid left-hand sides are rewritten to have a 'throw ReferenceError' - // as the left-hand side. - if (!expr->expression()->IsValidLeftHandSide()) { - VisitForEffect(expr->expression()); - return; - } - // Expression can only be a property, a global or a (parameter or local) // slot. enum LhsKind { VARIABLE, NAMED_PROPERTY, KEYED_PROPERTY }; @@ -4384,7 +4259,7 @@ void FullCodeGenerator::VisitCountOperation(CountOperation* expr) { __ jmp(&stub_call, Label::kNear); __ bind(&slow); } - ToNumberStub convert_stub; + ToNumberStub convert_stub(isolate()); __ CallStub(&convert_stub); // Save result for postfix expressions. @@ -4414,10 +4289,8 @@ void FullCodeGenerator::VisitCountOperation(CountOperation* expr) { __ bind(&stub_call); __ mov(edx, eax); __ mov(eax, Immediate(Smi::FromInt(1))); - BinaryOpICStub stub(expr->binary_op(), NO_OVERWRITE); - CallIC(stub.GetCode(isolate()), - RelocInfo::CODE_TARGET, - expr->CountBinOpFeedbackId()); + BinaryOpICStub stub(isolate(), expr->binary_op(), NO_OVERWRITE); + CallIC(stub.GetCode(), expr->CountBinOpFeedbackId()); patch_site.EmitPatchInfo(); __ bind(&done); @@ -4448,10 +4321,7 @@ void FullCodeGenerator::VisitCountOperation(CountOperation* expr) { case NAMED_PROPERTY: { __ mov(ecx, prop->key()->AsLiteral()->value()); __ pop(edx); - Handle<Code> ic = is_classic_mode() - ? isolate()->builtins()->StoreIC_Initialize() - : isolate()->builtins()->StoreIC_Initialize_Strict(); - CallIC(ic, RelocInfo::CODE_TARGET, expr->CountStoreFeedbackId()); + CallStoreIC(expr->CountStoreFeedbackId()); PrepareForBailoutForId(expr->AssignmentId(), TOS_REG); if (expr->is_postfix()) { if (!context()->IsEffect()) { @@ -4465,10 +4335,10 @@ void FullCodeGenerator::VisitCountOperation(CountOperation* expr) { case KEYED_PROPERTY: { __ pop(ecx); __ pop(edx); - Handle<Code> ic = is_classic_mode() + Handle<Code> ic = strict_mode() == SLOPPY ? isolate()->builtins()->KeyedStoreIC_Initialize() : isolate()->builtins()->KeyedStoreIC_Initialize_Strict(); - CallIC(ic, RelocInfo::CODE_TARGET, expr->CountStoreFeedbackId()); + CallIC(ic, expr->CountStoreFeedbackId()); PrepareForBailoutForId(expr->AssignmentId(), TOS_REG); if (expr->is_postfix()) { // Result is on the stack @@ -4490,16 +4360,16 @@ void FullCodeGenerator::VisitForTypeofValue(Expression* expr) { ASSERT(!context()->IsTest()); if (proxy != NULL && proxy->var()->IsUnallocated()) { - Comment cmnt(masm_, "Global variable"); + Comment cmnt(masm_, "[ Global variable"); __ mov(edx, GlobalObjectOperand()); __ mov(ecx, Immediate(proxy->name())); - Handle<Code> ic = isolate()->builtins()->LoadIC_Initialize(); // Use a regular load, not a contextual load, to avoid a reference // error. - CallIC(ic); + CallLoadIC(NOT_CONTEXTUAL); PrepareForBailout(expr, TOS_REG); context()->Plug(eax); } else if (proxy != NULL && proxy->var()->IsLookupSlot()) { + Comment cmnt(masm_, "[ Lookup slot"); Label done, slow; // Generate code for loading from variables potentially shadowed @@ -4509,7 +4379,7 @@ void FullCodeGenerator::VisitForTypeofValue(Expression* expr) { __ bind(&slow); __ push(esi); __ push(Immediate(proxy->name())); - __ CallRuntime(Runtime::kLoadContextSlotNoReferenceError, 2); + __ CallRuntime(Runtime::kHiddenLoadContextSlotNoReferenceError, 2); PrepareForBailout(expr, TOS_REG); __ bind(&done); @@ -4536,12 +4406,13 @@ void FullCodeGenerator::EmitLiteralCompareTypeof(Expression* expr, } PrepareForBailoutBeforeSplit(expr, true, if_true, if_false); - if (check->Equals(isolate()->heap()->number_string())) { + Factory* factory = isolate()->factory(); + if (String::Equals(check, factory->number_string())) { __ JumpIfSmi(eax, if_true); __ cmp(FieldOperand(eax, HeapObject::kMapOffset), isolate()->factory()->heap_number_map()); Split(equal, if_true, if_false, fall_through); - } else if (check->Equals(isolate()->heap()->string_string())) { + } else if (String::Equals(check, factory->string_string())) { __ JumpIfSmi(eax, if_false); __ CmpObjectType(eax, FIRST_NONSTRING_TYPE, edx); __ j(above_equal, if_false); @@ -4549,20 +4420,20 @@ void FullCodeGenerator::EmitLiteralCompareTypeof(Expression* expr, __ test_b(FieldOperand(edx, Map::kBitFieldOffset), 1 << Map::kIsUndetectable); Split(zero, if_true, if_false, fall_through); - } else if (check->Equals(isolate()->heap()->symbol_string())) { + } else if (String::Equals(check, factory->symbol_string())) { __ JumpIfSmi(eax, if_false); __ CmpObjectType(eax, SYMBOL_TYPE, edx); Split(equal, if_true, if_false, fall_through); - } else if (check->Equals(isolate()->heap()->boolean_string())) { + } else if (String::Equals(check, factory->boolean_string())) { __ cmp(eax, isolate()->factory()->true_value()); __ j(equal, if_true); __ cmp(eax, isolate()->factory()->false_value()); Split(equal, if_true, if_false, fall_through); } else if (FLAG_harmony_typeof && - check->Equals(isolate()->heap()->null_string())) { + String::Equals(check, factory->null_string())) { __ cmp(eax, isolate()->factory()->null_value()); Split(equal, if_true, if_false, fall_through); - } else if (check->Equals(isolate()->heap()->undefined_string())) { + } else if (String::Equals(check, factory->undefined_string())) { __ cmp(eax, isolate()->factory()->undefined_value()); __ j(equal, if_true); __ JumpIfSmi(eax, if_false); @@ -4571,14 +4442,14 @@ void FullCodeGenerator::EmitLiteralCompareTypeof(Expression* expr, __ movzx_b(ecx, FieldOperand(edx, Map::kBitFieldOffset)); __ test(ecx, Immediate(1 << Map::kIsUndetectable)); Split(not_zero, if_true, if_false, fall_through); - } else if (check->Equals(isolate()->heap()->function_string())) { + } else if (String::Equals(check, factory->function_string())) { __ JumpIfSmi(eax, if_false); STATIC_ASSERT(NUM_OF_CALLABLE_SPEC_OBJECT_TYPES == 2); __ CmpObjectType(eax, JS_FUNCTION_TYPE, edx); __ j(equal, if_true); __ CmpInstanceType(edx, JS_FUNCTION_PROXY_TYPE); Split(equal, if_true, if_false, fall_through); - } else if (check->Equals(isolate()->heap()->object_string())) { + } else if (String::Equals(check, factory->object_string())) { __ JumpIfSmi(eax, if_false); if (!FLAG_harmony_typeof) { __ cmp(eax, isolate()->factory()->null_value()); @@ -4629,7 +4500,7 @@ void FullCodeGenerator::VisitCompareOperation(CompareOperation* expr) { case Token::INSTANCEOF: { VisitForStackValue(expr->right()); - InstanceofStub stub(InstanceofStub::kNoFlags); + InstanceofStub stub(isolate(), InstanceofStub::kNoFlags); __ CallStub(&stub); PrepareForBailoutBeforeSplit(expr, true, if_true, if_false); __ test(eax, eax); @@ -4658,7 +4529,7 @@ void FullCodeGenerator::VisitCompareOperation(CompareOperation* expr) { // Record position and call the compare IC. SetSourcePosition(expr->position()); Handle<Code> ic = CompareIC::GetUninitialized(isolate(), op); - CallIC(ic, RelocInfo::CODE_TARGET, expr->CompareOperationFeedbackId()); + CallIC(ic, expr->CompareOperationFeedbackId()); patch_site.EmitPatchInfo(); PrepareForBailoutBeforeSplit(expr, true, if_true, if_false); @@ -4694,7 +4565,7 @@ void FullCodeGenerator::EmitLiteralCompareNil(CompareOperation* expr, Split(equal, if_true, if_false, fall_through); } else { Handle<Code> ic = CompareNilICStub::GetUninitialized(isolate(), nil); - CallIC(ic, RelocInfo::CODE_TARGET, expr->CompareOperationFeedbackId()); + CallIC(ic, expr->CompareOperationFeedbackId()); __ test(eax, eax); Split(not_zero, if_true, if_false, fall_through); } @@ -4847,9 +4718,11 @@ FullCodeGenerator::NestedStatement* FullCodeGenerator::TryFinally::Exit( static const byte kJnsInstruction = 0x79; static const byte kJnsOffset = 0x11; -static const byte kCallInstruction = 0xe8; static const byte kNopByteOne = 0x66; static const byte kNopByteTwo = 0x90; +#ifdef DEBUG +static const byte kCallInstruction = 0xe8; +#endif void BackEdgeTable::PatchAt(Code* unoptimized_code, @@ -4882,6 +4755,7 @@ void BackEdgeTable::PatchAt(Code* unoptimized_code, } Assembler::set_target_address_at(call_target_address, + unoptimized_code, replacement_code->entry()); unoptimized_code->GetHeap()->incremental_marking()->RecordCodeTargetPatch( unoptimized_code, call_target_address, replacement_code); @@ -4899,20 +4773,22 @@ BackEdgeTable::BackEdgeState BackEdgeTable::GetBackEdgeState( if (*jns_instr_address == kJnsInstruction) { ASSERT_EQ(kJnsOffset, *(call_target_address - 2)); ASSERT_EQ(isolate->builtins()->InterruptCheck()->entry(), - Assembler::target_address_at(call_target_address)); + Assembler::target_address_at(call_target_address, + unoptimized_code)); return INTERRUPT; } ASSERT_EQ(kNopByteOne, *jns_instr_address); ASSERT_EQ(kNopByteTwo, *(call_target_address - 2)); - if (Assembler::target_address_at(call_target_address) == + if (Assembler::target_address_at(call_target_address, unoptimized_code) == isolate->builtins()->OnStackReplacement()->entry()) { return ON_STACK_REPLACEMENT; } ASSERT_EQ(isolate->builtins()->OsrAfterStackCheck()->entry(), - Assembler::target_address_at(call_target_address)); + Assembler::target_address_at(call_target_address, + unoptimized_code)); return OSR_AFTER_STACK_CHECK; } |