| Index: src/ia32/full-codegen-ia32.cc
|
| ===================================================================
|
| --- src/ia32/full-codegen-ia32.cc (revision 8618)
|
| +++ src/ia32/full-codegen-ia32.cc (working copy)
|
| @@ -78,16 +78,18 @@
|
| }
|
|
|
| void EmitPatchInfo() {
|
| - int delta_to_patch_site = masm_->SizeOfCodeGeneratedSince(&patch_site_);
|
| - ASSERT(is_int8(delta_to_patch_site));
|
| - __ test(eax, Immediate(delta_to_patch_site));
|
| + if (patch_site_.is_bound()) {
|
| + int delta_to_patch_site = masm_->SizeOfCodeGeneratedSince(&patch_site_);
|
| + ASSERT(is_int8(delta_to_patch_site));
|
| + __ test(eax, Immediate(delta_to_patch_site));
|
| #ifdef DEBUG
|
| - info_emitted_ = true;
|
| + info_emitted_ = true;
|
| #endif
|
| + } else {
|
| + __ nop(); // Signals no inlined code.
|
| + }
|
| }
|
|
|
| - bool is_bound() const { return patch_site_.is_bound(); }
|
| -
|
| private:
|
| // jc will be patched with jz, jnc will become jnz.
|
| void EmitJump(Condition cc, Label* target, Label::Distance distance) {
|
| @@ -121,6 +123,7 @@
|
| void FullCodeGenerator::Generate(CompilationInfo* info) {
|
| ASSERT(info_ == NULL);
|
| info_ = info;
|
| + scope_ = info->scope();
|
| SetFunctionPosition(function());
|
| Comment cmnt(masm_, "[ function compiled by full code generator");
|
|
|
| @@ -131,16 +134,16 @@
|
| }
|
| #endif
|
|
|
| - // Strict mode functions 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_strict_mode()) {
|
| + // 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_strict_mode() || info->is_native()) {
|
| Label ok;
|
| __ test(ecx, Operand(ecx));
|
| __ j(zero, &ok, Label::kNear);
|
| // +1 for return address.
|
| - int receiver_offset = (scope()->num_parameters() + 1) * kPointerSize;
|
| + int receiver_offset = (info->scope()->num_parameters() + 1) * kPointerSize;
|
| __ mov(Operand(esp, receiver_offset),
|
| Immediate(isolate()->factory()->undefined_value()));
|
| __ bind(&ok);
|
| @@ -152,7 +155,7 @@
|
| __ push(edi); // Callee's JS Function.
|
|
|
| { Comment cmnt(masm_, "[ Allocate locals");
|
| - int locals_count = scope()->num_stack_slots();
|
| + int locals_count = info->scope()->num_stack_slots();
|
| if (locals_count == 1) {
|
| __ push(Immediate(isolate()->factory()->undefined_value()));
|
| } else if (locals_count > 1) {
|
| @@ -166,7 +169,7 @@
|
| bool function_in_register = true;
|
|
|
| // Possibly allocate a local context.
|
| - int heap_slots = scope()->num_heap_slots() - Context::MIN_CONTEXT_SLOTS;
|
| + int heap_slots = info->scope()->num_heap_slots() - Context::MIN_CONTEXT_SLOTS;
|
| if (heap_slots > 0) {
|
| Comment cmnt(masm_, "[ Allocate local context");
|
| // Argument to NewContext is the function, which is still in edi.
|
| @@ -175,7 +178,7 @@
|
| FastNewContextStub stub(heap_slots);
|
| __ CallStub(&stub);
|
| } else {
|
| - __ CallRuntime(Runtime::kNewContext, 1);
|
| + __ CallRuntime(Runtime::kNewFunctionContext, 1);
|
| }
|
| function_in_register = false;
|
| // Context is returned in both eax and esi. It replaces the context
|
| @@ -183,7 +186,7 @@
|
| __ mov(Operand(ebp, StandardFrameConstants::kContextOffset), esi);
|
|
|
| // Copy parameters into context if necessary.
|
| - int num_parameters = scope()->num_parameters();
|
| + int num_parameters = info->scope()->num_parameters();
|
| for (int i = 0; i < num_parameters; i++) {
|
| Slot* slot = scope()->parameter(i)->AsSlot();
|
| if (slot != NULL && slot->type() == Slot::CONTEXT) {
|
| @@ -214,25 +217,27 @@
|
| __ push(Operand(ebp, JavaScriptFrameConstants::kFunctionOffset));
|
| }
|
| // Receiver is just before the parameters on the caller's stack.
|
| - int offset = scope()->num_parameters() * kPointerSize;
|
| + int num_parameters = info->scope()->num_parameters();
|
| + int offset = num_parameters * kPointerSize;
|
| __ lea(edx,
|
| Operand(ebp, StandardFrameConstants::kCallerSPOffset + offset));
|
| __ push(edx);
|
| - __ SafePush(Immediate(Smi::FromInt(scope()->num_parameters())));
|
| - // Arguments to ArgumentsAccessStub:
|
| + __ SafePush(Immediate(Smi::FromInt(num_parameters)));
|
| + // Arguments to ArgumentsAccessStub and/or New...:
|
| // function, receiver address, parameter count.
|
| // The stub will rewrite receiver and parameter count if the previous
|
| // stack frame was an arguments adapter frame.
|
| - ArgumentsAccessStub stub(
|
| - is_strict_mode() ? ArgumentsAccessStub::NEW_STRICT
|
| - : ArgumentsAccessStub::NEW_NON_STRICT);
|
| + ArgumentsAccessStub::Type type;
|
| + if (is_strict_mode()) {
|
| + type = ArgumentsAccessStub::NEW_STRICT;
|
| + } else if (function()->has_duplicate_parameters()) {
|
| + type = ArgumentsAccessStub::NEW_NON_STRICT_SLOW;
|
| + } else {
|
| + type = ArgumentsAccessStub::NEW_NON_STRICT_FAST;
|
| + }
|
| + ArgumentsAccessStub stub(type);
|
| __ CallStub(&stub);
|
|
|
| - Variable* arguments_shadow = scope()->arguments_shadow();
|
| - if (arguments_shadow != NULL) {
|
| - __ mov(ecx, eax); // Duplicate result.
|
| - Move(arguments_shadow->AsSlot(), ecx, ebx, edx);
|
| - }
|
| Move(arguments->AsSlot(), eax, ebx, edx);
|
| }
|
|
|
| @@ -342,7 +347,7 @@
|
| __ mov(esp, ebp);
|
| __ pop(ebp);
|
|
|
| - int arguments_bytes = (scope()->num_parameters() + 1) * kPointerSize;
|
| + 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
|
| @@ -375,7 +380,7 @@
|
| // For simplicity we always test the accumulator register.
|
| codegen()->Move(result_register(), slot);
|
| codegen()->PrepareForBailoutBeforeSplit(TOS_REG, false, NULL, NULL);
|
| - codegen()->DoTest(true_label_, false_label_, fall_through_);
|
| + codegen()->DoTest(this);
|
| }
|
|
|
|
|
| @@ -449,7 +454,7 @@
|
| } else {
|
| // For simplicity we always test the accumulator register.
|
| __ mov(result_register(), lit);
|
| - codegen()->DoTest(true_label_, false_label_, fall_through_);
|
| + codegen()->DoTest(this);
|
| }
|
| }
|
|
|
| @@ -485,7 +490,7 @@
|
| __ Drop(count);
|
| __ Move(result_register(), reg);
|
| codegen()->PrepareForBailoutBeforeSplit(TOS_REG, false, NULL, NULL);
|
| - codegen()->DoTest(true_label_, false_label_, fall_through_);
|
| + codegen()->DoTest(this);
|
| }
|
|
|
|
|
| @@ -562,13 +567,14 @@
|
| }
|
|
|
|
|
| -void FullCodeGenerator::DoTest(Label* if_true,
|
| +void FullCodeGenerator::DoTest(Expression* condition,
|
| + Label* if_true,
|
| Label* if_false,
|
| Label* fall_through) {
|
| - ToBooleanStub stub;
|
| + ToBooleanStub stub(result_register());
|
| __ push(result_register());
|
| __ CallStub(&stub);
|
| - __ test(eax, Operand(eax));
|
| + __ test(result_register(), Operand(result_register()));
|
| // The stub returns nonzero for true.
|
| Split(not_zero, if_true, if_false, fall_through);
|
| }
|
| @@ -687,15 +693,18 @@
|
| // context.
|
| ASSERT_EQ(0, scope()->ContextChainLength(variable->scope()));
|
| if (FLAG_debug_code) {
|
| - // Check that we're not inside a 'with'.
|
| - __ mov(ebx, ContextOperand(esi, Context::FCONTEXT_INDEX));
|
| - __ cmp(ebx, Operand(esi));
|
| - __ Check(equal, "Unexpected declaration in current context.");
|
| + // Check that we're not inside a with or catch context.
|
| + __ mov(ebx, FieldOperand(esi, HeapObject::kMapOffset));
|
| + __ cmp(ebx, isolate()->factory()->with_context_map());
|
| + __ Check(not_equal, "Declaration in with context.");
|
| + __ cmp(ebx, isolate()->factory()->catch_context_map());
|
| + __ Check(not_equal, "Declaration in catch context.");
|
| }
|
| if (mode == Variable::CONST) {
|
| __ mov(ContextOperand(esi, slot->index()),
|
| Immediate(isolate()->factory()->the_hole_value()));
|
| - // No write barrier since the hole value is in old space.
|
| + // No write barrier since the hole value is in old space, root and is
|
| + // never evacuated from the page.
|
| } else if (function != NULL) {
|
| VisitForAccumulatorValue(function);
|
| __ mov(ContextOperand(esi, slot->index()), result_register());
|
| @@ -758,7 +767,7 @@
|
| Handle<Code> ic = is_strict_mode()
|
| ? isolate()->builtins()->KeyedStoreIC_Initialize_Strict()
|
| : isolate()->builtins()->KeyedStoreIC_Initialize();
|
| - EmitCallIC(ic, RelocInfo::CODE_TARGET, AstNode::kNoNumber);
|
| + __ call(ic);
|
| }
|
| }
|
| }
|
| @@ -831,7 +840,8 @@
|
| // Record position before stub call for type feedback.
|
| SetSourcePosition(clause->position());
|
| Handle<Code> ic = CompareIC::GetUninitialized(Token::EQ_STRICT);
|
| - EmitCallIC(ic, &patch_site, clause->CompareId());
|
| + __ call(ic, RelocInfo::CODE_TARGET, clause->CompareId());
|
| + patch_site.EmitPatchInfo();
|
| __ test(eax, Operand(eax));
|
| __ j(not_equal, &next_test);
|
| __ Drop(1); // Switch value is no longer needed.
|
| @@ -881,9 +891,8 @@
|
|
|
| // Convert the object to a JS object.
|
| Label convert, done_convert;
|
| - __ test(eax, Immediate(kSmiTagMask));
|
| - __ j(zero, &convert, Label::kNear);
|
| - __ CmpObjectType(eax, FIRST_JS_OBJECT_TYPE, ecx);
|
| + __ JumpIfSmi(eax, &convert, Label::kNear);
|
| + __ CmpObjectType(eax, FIRST_SPEC_OBJECT_TYPE, ecx);
|
| __ j(above_equal, &done_convert, Label::kNear);
|
| __ bind(&convert);
|
| __ push(eax);
|
| @@ -916,8 +925,7 @@
|
| // descriptors (edx). This is the case if the next enumeration
|
| // index field does not contain a smi.
|
| __ mov(edx, FieldOperand(edx, DescriptorArray::kEnumerationIndexOffset));
|
| - __ test(edx, Immediate(kSmiTagMask));
|
| - __ j(zero, &call_runtime);
|
| + __ JumpIfSmi(edx, &call_runtime);
|
|
|
| // For all objects but the receiver, check that the cache is empty.
|
| Label check_prototype;
|
| @@ -1086,8 +1094,7 @@
|
| __ j(not_equal, slow);
|
| }
|
| // Load next context in chain.
|
| - __ mov(temp, ContextOperand(context, Context::CLOSURE_INDEX));
|
| - __ mov(temp, FieldOperand(temp, JSFunction::kContextOffset));
|
| + __ mov(temp, ContextOperand(context, Context::PREVIOUS_INDEX));
|
| // Walk the rest of the chain without clobbering esi.
|
| context = temp;
|
| }
|
| @@ -1114,8 +1121,7 @@
|
| __ cmp(ContextOperand(temp, Context::EXTENSION_INDEX), Immediate(0));
|
| __ j(not_equal, slow);
|
| // Load next context in chain.
|
| - __ mov(temp, ContextOperand(temp, Context::CLOSURE_INDEX));
|
| - __ mov(temp, FieldOperand(temp, JSFunction::kContextOffset));
|
| + __ mov(temp, ContextOperand(temp, Context::PREVIOUS_INDEX));
|
| __ jmp(&next);
|
| __ bind(&fast);
|
| }
|
| @@ -1128,7 +1134,7 @@
|
| RelocInfo::Mode mode = (typeof_state == INSIDE_TYPEOF)
|
| ? RelocInfo::CODE_TARGET
|
| : RelocInfo::CODE_TARGET_CONTEXT;
|
| - EmitCallIC(ic, mode, AstNode::kNoNumber);
|
| + __ call(ic, mode);
|
| }
|
|
|
|
|
| @@ -1147,8 +1153,7 @@
|
| Immediate(0));
|
| __ j(not_equal, slow);
|
| }
|
| - __ mov(temp, ContextOperand(context, Context::CLOSURE_INDEX));
|
| - __ mov(temp, FieldOperand(temp, JSFunction::kContextOffset));
|
| + __ mov(temp, ContextOperand(context, Context::PREVIOUS_INDEX));
|
| // Walk the rest of the chain without clobbering esi.
|
| context = temp;
|
| }
|
| @@ -1209,7 +1214,7 @@
|
| __ SafeSet(eax, Immediate(key_literal->handle()));
|
| Handle<Code> ic =
|
| isolate()->builtins()->KeyedLoadIC_Initialize();
|
| - EmitCallIC(ic, RelocInfo::CODE_TARGET, GetPropertyId(property));
|
| + __ call(ic, RelocInfo::CODE_TARGET, GetPropertyId(property));
|
| __ jmp(done);
|
| }
|
| }
|
| @@ -1219,23 +1224,22 @@
|
|
|
|
|
| void FullCodeGenerator::EmitVariableLoad(Variable* var) {
|
| - // Four cases: non-this global variables, lookup slots, all other
|
| - // types of slots, and parameters that rewrite to explicit property
|
| - // accesses on the arguments object.
|
| + // Three cases: non-this global variables, lookup slots, and all other
|
| + // types of slots.
|
| Slot* slot = var->AsSlot();
|
| - Property* property = var->AsProperty();
|
| + ASSERT((var->is_global() && !var->is_this()) == (slot == NULL));
|
|
|
| - if (var->is_global() && !var->is_this()) {
|
| + if (slot == NULL) {
|
| Comment cmnt(masm_, "Global variable");
|
| // Use inline caching. Variable name is passed in ecx and the global
|
| // object on the stack.
|
| __ mov(eax, GlobalObjectOperand());
|
| __ mov(ecx, var->name());
|
| Handle<Code> ic = isolate()->builtins()->LoadIC_Initialize();
|
| - EmitCallIC(ic, RelocInfo::CODE_TARGET_CONTEXT, AstNode::kNoNumber);
|
| + __ call(ic, RelocInfo::CODE_TARGET_CONTEXT);
|
| context()->Plug(eax);
|
|
|
| - } else if (slot != NULL && slot->type() == Slot::LOOKUP) {
|
| + } else if (slot->type() == Slot::LOOKUP) {
|
| Label done, slow;
|
|
|
| // Generate code for loading from variables potentially shadowed
|
| @@ -1251,7 +1255,7 @@
|
|
|
| context()->Plug(eax);
|
|
|
| - } else if (slot != NULL) {
|
| + } else {
|
| Comment cmnt(masm_, (slot->type() == Slot::CONTEXT)
|
| ? "Context slot"
|
| : "Stack slot");
|
| @@ -1269,36 +1273,6 @@
|
| } else {
|
| context()->Plug(slot);
|
| }
|
| -
|
| - } else {
|
| - Comment cmnt(masm_, "Rewritten parameter");
|
| - ASSERT_NOT_NULL(property);
|
| - // Rewritten parameter accesses are of the form "slot[literal]".
|
| -
|
| - // Assert that the object is in a slot.
|
| - Variable* object_var = property->obj()->AsVariableProxy()->AsVariable();
|
| - ASSERT_NOT_NULL(object_var);
|
| - Slot* object_slot = object_var->AsSlot();
|
| - ASSERT_NOT_NULL(object_slot);
|
| -
|
| - // Load the object.
|
| - MemOperand object_loc = EmitSlotSearch(object_slot, eax);
|
| - __ mov(edx, object_loc);
|
| -
|
| - // Assert that the key is a smi.
|
| - Literal* key_literal = property->key()->AsLiteral();
|
| - ASSERT_NOT_NULL(key_literal);
|
| - ASSERT(key_literal->handle()->IsSmi());
|
| -
|
| - // Load the key.
|
| - __ SafeSet(eax, Immediate(key_literal->handle()));
|
| -
|
| - // Do a keyed property load.
|
| - Handle<Code> ic = isolate()->builtins()->KeyedLoadIC_Initialize();
|
| - EmitCallIC(ic, RelocInfo::CODE_TARGET, GetPropertyId(property));
|
| -
|
| - // Drop key and object left on the stack by IC.
|
| - context()->Plug(eax);
|
| }
|
| }
|
|
|
| @@ -1408,7 +1382,7 @@
|
| Handle<Code> ic = is_strict_mode()
|
| ? isolate()->builtins()->StoreIC_Initialize_Strict()
|
| : isolate()->builtins()->StoreIC_Initialize();
|
| - EmitCallIC(ic, RelocInfo::CODE_TARGET, key->id());
|
| + __ call(ic, RelocInfo::CODE_TARGET, key->id());
|
| PrepareForBailoutForId(key->id(), NO_REGISTERS);
|
| } else {
|
| VisitForEffect(value);
|
| @@ -1531,7 +1505,7 @@
|
| }
|
|
|
| // Left-hand side can only be a property, a global or a (parameter or local)
|
| - // slot. Variables with rewrite to .arguments are treated as KEYED_PROPERTY.
|
| + // slot.
|
| enum LhsKind { VARIABLE, NAMED_PROPERTY, KEYED_PROPERTY };
|
| LhsKind assign_type = VARIABLE;
|
| Property* property = expr->target()->AsProperty();
|
| @@ -1557,29 +1531,13 @@
|
| break;
|
| case KEYED_PROPERTY: {
|
| if (expr->is_compound()) {
|
| - if (property->is_arguments_access()) {
|
| - VariableProxy* obj_proxy = property->obj()->AsVariableProxy();
|
| - MemOperand slot_operand =
|
| - EmitSlotSearch(obj_proxy->var()->AsSlot(), ecx);
|
| - __ push(slot_operand);
|
| - __ SafeSet(eax, Immediate(property->key()->AsLiteral()->handle()));
|
| - } else {
|
| - VisitForStackValue(property->obj());
|
| - VisitForAccumulatorValue(property->key());
|
| - }
|
| + VisitForStackValue(property->obj());
|
| + VisitForAccumulatorValue(property->key());
|
| __ mov(edx, Operand(esp, 0));
|
| __ push(eax);
|
| } else {
|
| - if (property->is_arguments_access()) {
|
| - VariableProxy* obj_proxy = property->obj()->AsVariableProxy();
|
| - MemOperand slot_operand =
|
| - EmitSlotSearch(obj_proxy->var()->AsSlot(), ecx);
|
| - __ push(slot_operand);
|
| - __ SafePush(Immediate(property->key()->AsLiteral()->handle()));
|
| - } else {
|
| - VisitForStackValue(property->obj());
|
| - VisitForStackValue(property->key());
|
| - }
|
| + VisitForStackValue(property->obj());
|
| + VisitForStackValue(property->key());
|
| }
|
| break;
|
| }
|
| @@ -1657,14 +1615,14 @@
|
| ASSERT(!key->handle()->IsSmi());
|
| __ mov(ecx, Immediate(key->handle()));
|
| Handle<Code> ic = isolate()->builtins()->LoadIC_Initialize();
|
| - EmitCallIC(ic, RelocInfo::CODE_TARGET, GetPropertyId(prop));
|
| + __ call(ic, RelocInfo::CODE_TARGET, GetPropertyId(prop));
|
| }
|
|
|
|
|
| void FullCodeGenerator::EmitKeyedPropertyLoad(Property* prop) {
|
| SetSourcePosition(prop->position());
|
| Handle<Code> ic = isolate()->builtins()->KeyedLoadIC_Initialize();
|
| - EmitCallIC(ic, RelocInfo::CODE_TARGET, GetPropertyId(prop));
|
| + __ call(ic, RelocInfo::CODE_TARGET, GetPropertyId(prop));
|
| }
|
|
|
|
|
| @@ -1685,7 +1643,8 @@
|
| __ bind(&stub_call);
|
| __ mov(eax, ecx);
|
| BinaryOpStub stub(op, mode);
|
| - EmitCallIC(stub.GetCode(), &patch_site, expr->id());
|
| + __ call(stub.GetCode(), RelocInfo::CODE_TARGET, expr->id());
|
| + patch_site.EmitPatchInfo();
|
| __ jmp(&done, Label::kNear);
|
|
|
| // Smi case.
|
| @@ -1768,8 +1727,9 @@
|
| OverwriteMode mode) {
|
| __ pop(edx);
|
| BinaryOpStub stub(op, mode);
|
| - // NULL signals no inlined smi code.
|
| - EmitCallIC(stub.GetCode(), NULL, expr->id());
|
| + JumpPatchSite patch_site(masm_); // unbound, signals no inlined smi code.
|
| + __ call(stub.GetCode(), RelocInfo::CODE_TARGET, expr->id());
|
| + patch_site.EmitPatchInfo();
|
| context()->Plug(eax);
|
| }
|
|
|
| @@ -1783,7 +1743,7 @@
|
| }
|
|
|
| // Left-hand side can only be a property, a global or a (parameter or local)
|
| - // slot. Variables with rewrite to .arguments are treated as KEYED_PROPERTY.
|
| + // slot.
|
| enum LhsKind { VARIABLE, NAMED_PROPERTY, KEYED_PROPERTY };
|
| LhsKind assign_type = VARIABLE;
|
| Property* prop = expr->AsProperty();
|
| @@ -1809,7 +1769,7 @@
|
| Handle<Code> ic = is_strict_mode()
|
| ? isolate()->builtins()->StoreIC_Initialize_Strict()
|
| : isolate()->builtins()->StoreIC_Initialize();
|
| - EmitCallIC(ic, RelocInfo::CODE_TARGET, AstNode::kNoNumber);
|
| + __ call(ic);
|
| break;
|
| }
|
| case KEYED_PROPERTY: {
|
| @@ -1832,7 +1792,7 @@
|
| Handle<Code> ic = is_strict_mode()
|
| ? isolate()->builtins()->KeyedStoreIC_Initialize_Strict()
|
| : isolate()->builtins()->KeyedStoreIC_Initialize();
|
| - EmitCallIC(ic, RelocInfo::CODE_TARGET, AstNode::kNoNumber);
|
| + __ call(ic);
|
| break;
|
| }
|
| }
|
| @@ -1843,8 +1803,6 @@
|
|
|
| void FullCodeGenerator::EmitVariableAssignment(Variable* var,
|
| Token::Value op) {
|
| - // Left-hand sides that rewrite to explicit property accesses do not reach
|
| - // here.
|
| ASSERT(var != NULL);
|
| ASSERT(var->is_global() || var->AsSlot() != NULL);
|
|
|
| @@ -1858,7 +1816,7 @@
|
| Handle<Code> ic = is_strict_mode()
|
| ? isolate()->builtins()->StoreIC_Initialize_Strict()
|
| : isolate()->builtins()->StoreIC_Initialize();
|
| - EmitCallIC(ic, RelocInfo::CODE_TARGET_CONTEXT, AstNode::kNoNumber);
|
| + __ call(ic, RelocInfo::CODE_TARGET_CONTEXT);
|
|
|
| } else if (op == Token::INIT_CONST) {
|
| // Like var declarations, const declarations are hoisted to function
|
| @@ -1878,17 +1836,7 @@
|
| __ j(not_equal, &skip);
|
| __ mov(Operand(ebp, SlotOffset(slot)), eax);
|
| break;
|
| - case Slot::CONTEXT: {
|
| - __ mov(ecx, ContextOperand(esi, Context::FCONTEXT_INDEX));
|
| - __ mov(edx, ContextOperand(ecx, slot->index()));
|
| - __ cmp(edx, isolate()->factory()->the_hole_value());
|
| - __ j(not_equal, &skip);
|
| - __ mov(ContextOperand(ecx, slot->index()), eax);
|
| - int offset = Context::SlotOffset(slot->index());
|
| - __ mov(edx, eax); // Preserve the stored value in eax.
|
| - __ RecordWriteContextSlot(ecx, offset, edx, ebx, kDontSaveFPRegs);
|
| - break;
|
| - }
|
| + case Slot::CONTEXT:
|
| case Slot::LOOKUP:
|
| __ push(eax);
|
| __ push(esi);
|
| @@ -1962,7 +1910,7 @@
|
| Handle<Code> ic = is_strict_mode()
|
| ? isolate()->builtins()->StoreIC_Initialize_Strict()
|
| : isolate()->builtins()->StoreIC_Initialize();
|
| - EmitCallIC(ic, RelocInfo::CODE_TARGET, expr->id());
|
| + __ call(ic, RelocInfo::CODE_TARGET, expr->id());
|
|
|
| // If the assignment ends an initialization block, revert to fast case.
|
| if (expr->ends_initialization_block()) {
|
| @@ -2002,7 +1950,7 @@
|
| Handle<Code> ic = is_strict_mode()
|
| ? isolate()->builtins()->KeyedStoreIC_Initialize_Strict()
|
| : isolate()->builtins()->KeyedStoreIC_Initialize();
|
| - EmitCallIC(ic, RelocInfo::CODE_TARGET, expr->id());
|
| + __ call(ic, RelocInfo::CODE_TARGET, expr->id());
|
|
|
| // If the assignment ends an initialization block, revert to fast case.
|
| if (expr->ends_initialization_block()) {
|
| @@ -2053,7 +2001,7 @@
|
| InLoopFlag in_loop = (loop_depth() > 0) ? IN_LOOP : NOT_IN_LOOP;
|
| Handle<Code> ic =
|
| isolate()->stub_cache()->ComputeCallInitialize(arg_count, in_loop, mode);
|
| - EmitCallIC(ic, mode, expr->id());
|
| + __ call(ic, mode, expr->id());
|
| RecordJSReturnSite(expr);
|
| // Restore context register.
|
| __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset));
|
| @@ -2086,7 +2034,7 @@
|
| Handle<Code> ic = isolate()->stub_cache()->ComputeKeyedCallInitialize(
|
| arg_count, in_loop);
|
| __ mov(ecx, Operand(esp, (arg_count + 1) * kPointerSize)); // Key.
|
| - EmitCallIC(ic, RelocInfo::CODE_TARGET, expr->id());
|
| + __ call(ic, RelocInfo::CODE_TARGET, expr->id());
|
| RecordJSReturnSite(expr);
|
| // Restore context register.
|
| __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset));
|
| @@ -2125,7 +2073,7 @@
|
| }
|
|
|
| // Push the receiver of the enclosing function.
|
| - __ push(Operand(ebp, (2 + scope()->num_parameters()) * kPointerSize));
|
| + __ push(Operand(ebp, (2 + info_->scope()->num_parameters()) * kPointerSize));
|
|
|
| // Push the strict mode flag.
|
| __ push(Immediate(Smi::FromInt(strict_mode_flag())));
|
| @@ -2239,9 +2187,9 @@
|
| __ bind(&done);
|
| // Push function.
|
| __ push(eax);
|
| - // Push global receiver.
|
| - __ mov(ebx, GlobalObjectOperand());
|
| - __ push(FieldOperand(ebx, GlobalObject::kGlobalReceiverOffset));
|
| + // 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()));
|
| __ bind(&call);
|
| }
|
|
|
| @@ -2262,7 +2210,7 @@
|
| } else {
|
| // Call to a keyed property.
|
| // For a synthetic property use keyed load IC followed by function call,
|
| - // for a regular property use keyed EmitCallIC.
|
| + // for a regular property use EmitKeyedCallWithIC.
|
| if (prop->is_synthetic()) {
|
| // Do not visit the object and key subexpressions (they are shared
|
| // by all occurrences of the same rewritten parameter).
|
| @@ -2280,7 +2228,7 @@
|
| SetSourcePosition(prop->position());
|
|
|
| Handle<Code> ic = isolate()->builtins()->KeyedLoadIC_Initialize();
|
| - EmitCallIC(ic, RelocInfo::CODE_TARGET, GetPropertyId(prop));
|
| + __ call(ic, RelocInfo::CODE_TARGET, GetPropertyId(prop));
|
| // Push result (function).
|
| __ push(eax);
|
| // Push Global receiver.
|
| @@ -2397,8 +2345,7 @@
|
| context()->PrepareTest(&materialize_true, &materialize_false,
|
| &if_true, &if_false, &fall_through);
|
|
|
| - __ test(eax, Immediate(kSmiTagMask));
|
| - __ j(zero, if_false);
|
| + __ JumpIfSmi(eax, if_false);
|
| __ cmp(eax, isolate()->factory()->null_value());
|
| __ j(equal, if_true);
|
| __ mov(ebx, FieldOperand(eax, HeapObject::kMapOffset));
|
| @@ -2407,9 +2354,9 @@
|
| __ test(ecx, Immediate(1 << Map::kIsUndetectable));
|
| __ j(not_zero, if_false);
|
| __ movzx_b(ecx, FieldOperand(ebx, Map::kInstanceTypeOffset));
|
| - __ cmp(ecx, FIRST_JS_OBJECT_TYPE);
|
| + __ cmp(ecx, FIRST_NONCALLABLE_SPEC_OBJECT_TYPE);
|
| __ j(below, if_false);
|
| - __ cmp(ecx, LAST_JS_OBJECT_TYPE);
|
| + __ cmp(ecx, LAST_NONCALLABLE_SPEC_OBJECT_TYPE);
|
| PrepareForBailoutBeforeSplit(TOS_REG, true, if_true, if_false);
|
| Split(below_equal, if_true, if_false, fall_through);
|
|
|
| @@ -2429,9 +2376,8 @@
|
| context()->PrepareTest(&materialize_true, &materialize_false,
|
| &if_true, &if_false, &fall_through);
|
|
|
| - __ test(eax, Immediate(kSmiTagMask));
|
| - __ j(equal, if_false);
|
| - __ CmpObjectType(eax, FIRST_JS_OBJECT_TYPE, ebx);
|
| + __ JumpIfSmi(eax, if_false);
|
| + __ CmpObjectType(eax, FIRST_SPEC_OBJECT_TYPE, ebx);
|
| PrepareForBailoutBeforeSplit(TOS_REG, true, if_true, if_false);
|
| Split(above_equal, if_true, if_false, fall_through);
|
|
|
| @@ -2451,8 +2397,7 @@
|
| context()->PrepareTest(&materialize_true, &materialize_false,
|
| &if_true, &if_false, &fall_through);
|
|
|
| - __ test(eax, Immediate(kSmiTagMask));
|
| - __ j(zero, if_false);
|
| + __ JumpIfSmi(eax, if_false);
|
| __ mov(ebx, FieldOperand(eax, HeapObject::kMapOffset));
|
| __ movzx_b(ebx, FieldOperand(ebx, Map::kBitFieldOffset));
|
| __ test(ebx, Immediate(1 << Map::kIsUndetectable));
|
| @@ -2526,8 +2471,7 @@
|
| // If a valueOf property is not found on the object check that it's
|
| // prototype is the un-modified String prototype. If not result is false.
|
| __ mov(ecx, FieldOperand(ebx, Map::kPrototypeOffset));
|
| - __ test(ecx, Immediate(kSmiTagMask));
|
| - __ j(zero, if_false);
|
| + __ JumpIfSmi(ecx, if_false);
|
| __ mov(ecx, FieldOperand(ecx, HeapObject::kMapOffset));
|
| __ mov(edx, Operand(esi, Context::SlotOffset(Context::GLOBAL_INDEX)));
|
| __ mov(edx,
|
| @@ -2559,8 +2503,7 @@
|
| context()->PrepareTest(&materialize_true, &materialize_false,
|
| &if_true, &if_false, &fall_through);
|
|
|
| - __ test(eax, Immediate(kSmiTagMask));
|
| - __ j(zero, if_false);
|
| + __ JumpIfSmi(eax, if_false);
|
| __ CmpObjectType(eax, JS_FUNCTION_TYPE, ebx);
|
| PrepareForBailoutBeforeSplit(TOS_REG, true, if_true, if_false);
|
| Split(equal, if_true, if_false, fall_through);
|
| @@ -2581,8 +2524,7 @@
|
| context()->PrepareTest(&materialize_true, &materialize_false,
|
| &if_true, &if_false, &fall_through);
|
|
|
| - __ test(eax, Immediate(kSmiTagMask));
|
| - __ j(equal, if_false);
|
| + __ JumpIfSmi(eax, if_false);
|
| __ CmpObjectType(eax, JS_ARRAY_TYPE, ebx);
|
| PrepareForBailoutBeforeSplit(TOS_REG, true, if_true, if_false);
|
| Split(equal, if_true, if_false, fall_through);
|
| @@ -2603,8 +2545,7 @@
|
| context()->PrepareTest(&materialize_true, &materialize_false,
|
| &if_true, &if_false, &fall_through);
|
|
|
| - __ test(eax, Immediate(kSmiTagMask));
|
| - __ j(equal, if_false);
|
| + __ JumpIfSmi(eax, if_false);
|
| __ CmpObjectType(eax, JS_REGEXP_TYPE, ebx);
|
| PrepareForBailoutBeforeSplit(TOS_REG, true, if_true, if_false);
|
| Split(equal, if_true, if_false, fall_through);
|
| @@ -2675,7 +2616,7 @@
|
| // parameter count in eax.
|
| VisitForAccumulatorValue(args->at(0));
|
| __ mov(edx, eax);
|
| - __ SafeSet(eax, Immediate(Smi::FromInt(scope()->num_parameters())));
|
| + __ SafeSet(eax, Immediate(Smi::FromInt(info_->scope()->num_parameters())));
|
| ArgumentsAccessStub stub(ArgumentsAccessStub::READ_ELEMENT);
|
| __ CallStub(&stub);
|
| context()->Plug(eax);
|
| @@ -2687,7 +2628,7 @@
|
|
|
| Label exit;
|
| // Get the number of formal parameters.
|
| - __ SafeSet(eax, Immediate(Smi::FromInt(scope()->num_parameters())));
|
| + __ SafeSet(eax, Immediate(Smi::FromInt(info_->scope()->num_parameters())));
|
|
|
| // Check if the calling frame is an arguments adaptor frame.
|
| __ mov(ebx, Operand(ebp, StandardFrameConstants::kCallerFPOffset));
|
| @@ -2712,21 +2653,22 @@
|
| VisitForAccumulatorValue(args->at(0));
|
|
|
| // If the object is a smi, we return null.
|
| - __ test(eax, Immediate(kSmiTagMask));
|
| - __ j(zero, &null);
|
| + __ JumpIfSmi(eax, &null);
|
|
|
| // Check that the object is a JS object but take special care of JS
|
| // functions to make sure they have 'Function' as their class.
|
| - __ CmpObjectType(eax, FIRST_JS_OBJECT_TYPE, eax); // Map is now in eax.
|
| + __ CmpObjectType(eax, FIRST_SPEC_OBJECT_TYPE, eax);
|
| + // Map is now in eax.
|
| __ j(below, &null);
|
|
|
| - // As long as JS_FUNCTION_TYPE is the last instance type and it is
|
| - // right after LAST_JS_OBJECT_TYPE, we can avoid checking for
|
| - // LAST_JS_OBJECT_TYPE.
|
| - ASSERT(LAST_TYPE == JS_FUNCTION_TYPE);
|
| - ASSERT(JS_FUNCTION_TYPE == LAST_JS_OBJECT_TYPE + 1);
|
| - __ CmpInstanceType(eax, JS_FUNCTION_TYPE);
|
| - __ j(equal, &function);
|
| + // As long as LAST_CALLABLE_SPEC_OBJECT_TYPE is the last instance type, and
|
| + // FIRST_CALLABLE_SPEC_OBJECT_TYPE comes right after
|
| + // LAST_NONCALLABLE_SPEC_OBJECT_TYPE, we can avoid checking for the latter.
|
| + STATIC_ASSERT(LAST_TYPE == LAST_CALLABLE_SPEC_OBJECT_TYPE);
|
| + STATIC_ASSERT(FIRST_CALLABLE_SPEC_OBJECT_TYPE ==
|
| + LAST_NONCALLABLE_SPEC_OBJECT_TYPE + 1);
|
| + __ CmpInstanceType(eax, FIRST_CALLABLE_SPEC_OBJECT_TYPE);
|
| + __ j(above_equal, &function);
|
|
|
| // Check if the constructor in the map is a function.
|
| __ mov(eax, FieldOperand(eax, Map::kConstructorOffset));
|
| @@ -2864,8 +2806,7 @@
|
|
|
| Label done;
|
| // If the object is a smi return the object.
|
| - __ test(eax, Immediate(kSmiTagMask));
|
| - __ j(zero, &done, Label::kNear);
|
| + __ JumpIfSmi(eax, &done, Label::kNear);
|
| // If the object is not a value type, return the object.
|
| __ CmpObjectType(eax, JS_VALUE_TYPE, ebx);
|
| __ j(not_equal, &done, Label::kNear);
|
| @@ -2901,8 +2842,7 @@
|
|
|
| Label done;
|
| // If the object is a smi, return the value.
|
| - __ test(ebx, Immediate(kSmiTagMask));
|
| - __ j(zero, &done, Label::kNear);
|
| + __ JumpIfSmi(ebx, &done, Label::kNear);
|
|
|
| // If the object is not a value type, return the value.
|
| __ CmpObjectType(ebx, JS_VALUE_TYPE, ecx);
|
| @@ -3125,7 +3065,8 @@
|
| // InvokeFunction requires the function in edi. Move it in there.
|
| __ mov(edi, result_register());
|
| ParameterCount count(arg_count);
|
| - __ InvokeFunction(edi, count, CALL_FUNCTION);
|
| + __ InvokeFunction(edi, count, CALL_FUNCTION,
|
| + NullCallWrapper(), CALL_AS_METHOD);
|
| __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset));
|
| context()->Plug(eax);
|
| }
|
| @@ -3176,8 +3117,7 @@
|
| __ mov(index_2, Operand(esp, 0));
|
| __ mov(temp, index_1);
|
| __ or_(temp, Operand(index_2));
|
| - __ test(temp, Immediate(kSmiTagMask));
|
| - __ j(not_zero, &slow_case);
|
| + __ JumpIfNotSmi(temp, &slow_case);
|
|
|
| // Check that both indices are valid.
|
| __ mov(temp, FieldOperand(object, JSArray::kLengthOffset));
|
| @@ -3295,8 +3235,7 @@
|
| // Fail if either is a non-HeapObject.
|
| __ mov(tmp, left);
|
| __ and_(Operand(tmp), right);
|
| - __ test(Operand(tmp), Immediate(kSmiTagMask));
|
| - __ j(zero, &fail);
|
| + __ JumpIfSmi(tmp, &fail);
|
| __ mov(tmp, FieldOperand(left, HeapObject::kMapOffset));
|
| __ CmpInstanceType(tmp, JS_REGEXP_TYPE);
|
| __ j(not_equal, &fail);
|
| @@ -3388,15 +3327,12 @@
|
| __ sub(Operand(esp), Immediate(2 * kPointerSize));
|
| __ cld();
|
| // Check that the array is a JSArray
|
| - __ test(array, Immediate(kSmiTagMask));
|
| - __ j(zero, &bailout);
|
| + __ JumpIfSmi(array, &bailout);
|
| __ CmpObjectType(array, JS_ARRAY_TYPE, scratch);
|
| __ j(not_equal, &bailout);
|
|
|
| // Check that the array has fast elements.
|
| - __ test_b(FieldOperand(scratch, Map::kBitField2Offset),
|
| - 1 << Map::kHasFastElements);
|
| - __ j(zero, &bailout);
|
| + __ CheckFastElements(scratch, &bailout);
|
|
|
| // If the array has length zero, return the empty string.
|
| __ mov(array_length, FieldOperand(array, JSArray::kLengthOffset));
|
| @@ -3432,8 +3368,7 @@
|
| index,
|
| times_pointer_size,
|
| FixedArray::kHeaderSize));
|
| - __ test(string, Immediate(kSmiTagMask));
|
| - __ j(zero, &bailout);
|
| + __ JumpIfSmi(string, &bailout);
|
| __ mov(scratch, FieldOperand(string, HeapObject::kMapOffset));
|
| __ movzx_b(scratch, FieldOperand(scratch, Map::kInstanceTypeOffset));
|
| __ and_(scratch, Immediate(
|
| @@ -3466,8 +3401,7 @@
|
|
|
| // Check that the separator is a flat ASCII string.
|
| __ mov(string, separator_operand);
|
| - __ test(string, Immediate(kSmiTagMask));
|
| - __ j(zero, &bailout);
|
| + __ JumpIfSmi(string, &bailout);
|
| __ mov(scratch, FieldOperand(string, HeapObject::kMapOffset));
|
| __ movzx_b(scratch, FieldOperand(scratch, Map::kInstanceTypeOffset));
|
| __ and_(scratch, Immediate(
|
| @@ -3624,6 +3558,39 @@
|
| }
|
|
|
|
|
| +void FullCodeGenerator::EmitIsNativeOrStrictMode(ZoneList<Expression*>* args) {
|
| + ASSERT(args->length() == 1);
|
| +
|
| + // Load the function into eax.
|
| + VisitForAccumulatorValue(args->at(0));
|
| +
|
| + // Prepare for the test.
|
| + Label materialize_true, materialize_false;
|
| + Label* if_true = NULL;
|
| + Label* if_false = NULL;
|
| + Label* fall_through = NULL;
|
| + context()->PrepareTest(&materialize_true, &materialize_false,
|
| + &if_true, &if_false, &fall_through);
|
| +
|
| + // Test for strict mode function.
|
| + __ mov(ecx, FieldOperand(eax, JSFunction::kSharedFunctionInfoOffset));
|
| + __ test_b(FieldOperand(ecx, SharedFunctionInfo::kStrictModeByteOffset),
|
| + 1 << SharedFunctionInfo::kStrictModeBitWithinByte);
|
| + __ j(not_equal, if_true);
|
| +
|
| + // Test for native function.
|
| + __ test_b(FieldOperand(ecx, SharedFunctionInfo::kNativeByteOffset),
|
| + 1 << SharedFunctionInfo::kNativeBitWithinByte);
|
| + __ j(not_equal, if_true);
|
| +
|
| + // Not native or strict-mode function.
|
| + __ jmp(if_false);
|
| +
|
| + PrepareForBailoutBeforeSplit(TOS_REG, true, if_true, if_false);
|
| + context()->Plug(if_true, if_false);
|
| +}
|
| +
|
| +
|
| void FullCodeGenerator::VisitCallRuntime(CallRuntime* expr) {
|
| Handle<String> name = expr->name();
|
| if (name->length() > 0 && name->Get(0) == '_') {
|
| @@ -3654,7 +3621,7 @@
|
| RelocInfo::Mode mode = RelocInfo::CODE_TARGET;
|
| Handle<Code> ic = isolate()->stub_cache()->ComputeCallInitialize(
|
| arg_count, in_loop, mode);
|
| - EmitCallIC(ic, mode, expr->id());
|
| + __ call(ic, mode, expr->id());
|
| // Restore context register.
|
| __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset));
|
| } else {
|
| @@ -3759,8 +3726,7 @@
|
| Comment cmt(masm_, "[ UnaryOperation (ADD)");
|
| VisitForAccumulatorValue(expr->expression());
|
| Label no_conversion;
|
| - __ test(result_register(), Immediate(kSmiTagMask));
|
| - __ j(zero, &no_conversion);
|
| + __ JumpIfSmi(result_register(), &no_conversion);
|
| ToNumberStub convert_stub;
|
| __ CallStub(&convert_stub);
|
| __ bind(&no_conversion);
|
| @@ -3794,7 +3760,7 @@
|
| // accumulator register eax.
|
| VisitForAccumulatorValue(expr->expression());
|
| SetSourcePosition(expr->position());
|
| - EmitCallIC(stub.GetCode(), NULL, expr->id());
|
| + __ call(stub.GetCode(), RelocInfo::CODE_TARGET, expr->id());
|
| context()->Plug(eax);
|
| }
|
|
|
| @@ -3811,7 +3777,7 @@
|
| }
|
|
|
| // Expression can only be a property, a global or a (parameter or local)
|
| - // slot. Variables with rewrite to .arguments are treated as KEYED_PROPERTY.
|
| + // slot.
|
| enum LhsKind { VARIABLE, NAMED_PROPERTY, KEYED_PROPERTY };
|
| LhsKind assign_type = VARIABLE;
|
| Property* prop = expr->expression()->AsProperty();
|
| @@ -3838,16 +3804,8 @@
|
| __ push(eax);
|
| EmitNamedPropertyLoad(prop);
|
| } else {
|
| - if (prop->is_arguments_access()) {
|
| - VariableProxy* obj_proxy = prop->obj()->AsVariableProxy();
|
| - MemOperand slot_operand =
|
| - EmitSlotSearch(obj_proxy->var()->AsSlot(), ecx);
|
| - __ push(slot_operand);
|
| - __ SafeSet(eax, Immediate(prop->key()->AsLiteral()->handle()));
|
| - } else {
|
| - VisitForStackValue(prop->obj());
|
| - VisitForAccumulatorValue(prop->key());
|
| - }
|
| + VisitForStackValue(prop->obj());
|
| + VisitForAccumulatorValue(prop->key());
|
| __ mov(edx, Operand(esp, 0));
|
| __ push(eax);
|
| EmitKeyedPropertyLoad(prop);
|
| @@ -3865,8 +3823,7 @@
|
| // Call ToNumber only if operand is not a smi.
|
| Label no_conversion;
|
| if (ShouldInlineSmiCase(expr->op())) {
|
| - __ test(eax, Immediate(kSmiTagMask));
|
| - __ j(zero, &no_conversion, Label::kNear);
|
| + __ JumpIfSmi(eax, &no_conversion, Label::kNear);
|
| }
|
| ToNumberStub convert_stub;
|
| __ CallStub(&convert_stub);
|
| @@ -3923,7 +3880,8 @@
|
| __ mov(edx, eax);
|
| __ mov(eax, Immediate(Smi::FromInt(1)));
|
| BinaryOpStub stub(expr->binary_op(), NO_OVERWRITE);
|
| - EmitCallIC(stub.GetCode(), &patch_site, expr->CountId());
|
| + __ call(stub.GetCode(), RelocInfo::CODE_TARGET, expr->CountId());
|
| + patch_site.EmitPatchInfo();
|
| __ bind(&done);
|
|
|
| // Store the value returned in eax.
|
| @@ -3956,7 +3914,7 @@
|
| Handle<Code> ic = is_strict_mode()
|
| ? isolate()->builtins()->StoreIC_Initialize_Strict()
|
| : isolate()->builtins()->StoreIC_Initialize();
|
| - EmitCallIC(ic, RelocInfo::CODE_TARGET, expr->id());
|
| + __ call(ic, RelocInfo::CODE_TARGET, expr->id());
|
| PrepareForBailoutForId(expr->AssignmentId(), TOS_REG);
|
| if (expr->is_postfix()) {
|
| if (!context()->IsEffect()) {
|
| @@ -3973,7 +3931,7 @@
|
| Handle<Code> ic = is_strict_mode()
|
| ? isolate()->builtins()->KeyedStoreIC_Initialize_Strict()
|
| : isolate()->builtins()->KeyedStoreIC_Initialize();
|
| - EmitCallIC(ic, RelocInfo::CODE_TARGET, expr->id());
|
| + __ call(ic, RelocInfo::CODE_TARGET, expr->id());
|
| PrepareForBailoutForId(expr->AssignmentId(), TOS_REG);
|
| if (expr->is_postfix()) {
|
| // Result is on the stack
|
| @@ -4001,7 +3959,7 @@
|
| Handle<Code> ic = isolate()->builtins()->LoadIC_Initialize();
|
| // Use a regular load, not a contextual load, to avoid a reference
|
| // error.
|
| - EmitCallIC(ic, RelocInfo::CODE_TARGET, AstNode::kNoNumber);
|
| + __ call(ic);
|
| PrepareForBailout(expr, TOS_REG);
|
| context()->Plug(eax);
|
| } else if (proxy != NULL &&
|
| @@ -4024,30 +3982,18 @@
|
| context()->Plug(eax);
|
| } else {
|
| // This expression cannot throw a reference error at the top level.
|
| - context()->HandleExpression(expr);
|
| + VisitInCurrentContext(expr);
|
| }
|
| }
|
|
|
|
|
| -bool FullCodeGenerator::TryLiteralCompare(Token::Value op,
|
| - Expression* left,
|
| - Expression* right,
|
| - Label* if_true,
|
| - Label* if_false,
|
| - Label* fall_through) {
|
| - if (op != Token::EQ && op != Token::EQ_STRICT) return false;
|
| -
|
| - // Check for the pattern: typeof <expression> == <string literal>.
|
| - Literal* right_literal = right->AsLiteral();
|
| - if (right_literal == NULL) return false;
|
| - Handle<Object> right_literal_value = right_literal->handle();
|
| - if (!right_literal_value->IsString()) return false;
|
| - UnaryOperation* left_unary = left->AsUnaryOperation();
|
| - if (left_unary == NULL || left_unary->op() != Token::TYPEOF) return false;
|
| - Handle<String> check = Handle<String>::cast(right_literal_value);
|
| -
|
| +void FullCodeGenerator::EmitLiteralCompareTypeof(Expression* expr,
|
| + Handle<String> check,
|
| + Label* if_true,
|
| + Label* if_false,
|
| + Label* fall_through) {
|
| { AccumulatorValueContext context(this);
|
| - VisitForTypeofValue(left_unary->expression());
|
| + VisitForTypeofValue(expr);
|
| }
|
| PrepareForBailoutBeforeSplit(TOS_REG, true, if_true, if_false);
|
|
|
| @@ -4080,16 +4026,16 @@
|
| Split(not_zero, if_true, if_false, fall_through);
|
| } else if (check->Equals(isolate()->heap()->function_symbol())) {
|
| __ JumpIfSmi(eax, if_false);
|
| - __ CmpObjectType(eax, FIRST_FUNCTION_CLASS_TYPE, edx);
|
| + __ CmpObjectType(eax, FIRST_CALLABLE_SPEC_OBJECT_TYPE, edx);
|
| Split(above_equal, if_true, if_false, fall_through);
|
| } else if (check->Equals(isolate()->heap()->object_symbol())) {
|
| __ JumpIfSmi(eax, if_false);
|
| __ cmp(eax, isolate()->factory()->null_value());
|
| __ j(equal, if_true);
|
| - __ CmpObjectType(eax, FIRST_JS_OBJECT_TYPE, edx);
|
| + __ CmpObjectType(eax, FIRST_NONCALLABLE_SPEC_OBJECT_TYPE, edx);
|
| __ j(below, if_false);
|
| - __ CmpInstanceType(edx, FIRST_FUNCTION_CLASS_TYPE);
|
| - __ j(above_equal, if_false);
|
| + __ CmpInstanceType(edx, LAST_NONCALLABLE_SPEC_OBJECT_TYPE);
|
| + __ j(above, if_false);
|
| // Check for undetectable objects => false.
|
| __ test_b(FieldOperand(edx, Map::kBitFieldOffset),
|
| 1 << Map::kIsUndetectable);
|
| @@ -4097,8 +4043,18 @@
|
| } else {
|
| if (if_false != fall_through) __ jmp(if_false);
|
| }
|
| +}
|
|
|
| - return true;
|
| +
|
| +void FullCodeGenerator::EmitLiteralCompareUndefined(Expression* expr,
|
| + Label* if_true,
|
| + Label* if_false,
|
| + Label* fall_through) {
|
| + VisitForAccumulatorValue(expr);
|
| + PrepareForBailoutBeforeSplit(TOS_REG, true, if_true, if_false);
|
| +
|
| + __ cmp(eax, isolate()->factory()->undefined_value());
|
| + Split(equal, if_true, if_false, fall_through);
|
| }
|
|
|
|
|
| @@ -4118,14 +4074,12 @@
|
|
|
| // First we try a fast inlined version of the compare when one of
|
| // the operands is a literal.
|
| - Token::Value op = expr->op();
|
| - Expression* left = expr->left();
|
| - Expression* right = expr->right();
|
| - if (TryLiteralCompare(op, left, right, if_true, if_false, fall_through)) {
|
| + if (TryLiteralCompare(expr, if_true, if_false, fall_through)) {
|
| context()->Plug(if_true, if_false);
|
| return;
|
| }
|
|
|
| + Token::Value op = expr->op();
|
| VisitForStackValue(expr->left());
|
| switch (expr->op()) {
|
| case Token::IN:
|
| @@ -4200,7 +4154,8 @@
|
| // Record position and call the compare IC.
|
| SetSourcePosition(expr->position());
|
| Handle<Code> ic = CompareIC::GetUninitialized(op);
|
| - EmitCallIC(ic, &patch_site, expr->id());
|
| + __ call(ic, RelocInfo::CODE_TARGET, expr->id());
|
| + patch_site.EmitPatchInfo();
|
|
|
| PrepareForBailoutBeforeSplit(TOS_REG, true, if_true, if_false);
|
| __ test(eax, Operand(eax));
|
| @@ -4232,8 +4187,7 @@
|
| __ j(equal, if_true);
|
| __ cmp(eax, isolate()->factory()->undefined_value());
|
| __ j(equal, if_true);
|
| - __ test(eax, Immediate(kSmiTagMask));
|
| - __ j(zero, if_false);
|
| + __ JumpIfSmi(eax, if_false);
|
| // It can be an undetectable object.
|
| __ mov(edx, FieldOperand(eax, HeapObject::kMapOffset));
|
| __ movzx_b(edx, FieldOperand(edx, Map::kBitFieldOffset));
|
| @@ -4260,58 +4214,6 @@
|
| }
|
|
|
|
|
| -void FullCodeGenerator::EmitCallIC(Handle<Code> ic,
|
| - RelocInfo::Mode mode,
|
| - unsigned ast_id) {
|
| - ASSERT(mode == RelocInfo::CODE_TARGET ||
|
| - mode == RelocInfo::CODE_TARGET_CONTEXT);
|
| - switch (ic->kind()) {
|
| - case Code::LOAD_IC:
|
| - __ IncrementCounter(isolate()->counters()->named_load_full(), 1);
|
| - break;
|
| - case Code::KEYED_LOAD_IC:
|
| - __ IncrementCounter(isolate()->counters()->keyed_load_full(), 1);
|
| - break;
|
| - case Code::STORE_IC:
|
| - __ IncrementCounter(isolate()->counters()->named_store_full(), 1);
|
| - break;
|
| - case Code::KEYED_STORE_IC:
|
| - __ IncrementCounter(isolate()->counters()->keyed_store_full(), 1);
|
| - default:
|
| - break;
|
| - }
|
| - __ call(ic, mode, ast_id);
|
| -}
|
| -
|
| -
|
| -void FullCodeGenerator::EmitCallIC(Handle<Code> ic,
|
| - JumpPatchSite* patch_site,
|
| - unsigned ast_id) {
|
| - Counters* counters = isolate()->counters();
|
| - switch (ic->kind()) {
|
| - case Code::LOAD_IC:
|
| - __ IncrementCounter(counters->named_load_full(), 1);
|
| - break;
|
| - case Code::KEYED_LOAD_IC:
|
| - __ IncrementCounter(counters->keyed_load_full(), 1);
|
| - break;
|
| - case Code::STORE_IC:
|
| - __ IncrementCounter(counters->named_store_full(), 1);
|
| - break;
|
| - case Code::KEYED_STORE_IC:
|
| - __ IncrementCounter(counters->keyed_store_full(), 1);
|
| - default:
|
| - break;
|
| - }
|
| - __ call(ic, RelocInfo::CODE_TARGET, ast_id);
|
| - if (patch_site != NULL && patch_site->is_bound()) {
|
| - patch_site->EmitPatchInfo();
|
| - } else {
|
| - __ nop(); // Signals no inlined code.
|
| - }
|
| -}
|
| -
|
| -
|
| void FullCodeGenerator::StoreToFrameField(int frame_offset, Register value) {
|
| ASSERT_EQ(POINTER_SIZE_ALIGN(frame_offset), frame_offset);
|
| __ mov(Operand(ebp, frame_offset), value);
|
| @@ -4323,18 +4225,38 @@
|
| }
|
|
|
|
|
| +void FullCodeGenerator::PushFunctionArgumentForContextAllocation() {
|
| + Scope* declaration_scope = scope()->DeclarationScope();
|
| + if (declaration_scope->is_global_scope()) {
|
| + // Contexts nested in the global context have a canonical empty function
|
| + // as their closure, not the anonymous closure containing the global
|
| + // code. Pass a smi sentinel and let the runtime look up the empty
|
| + // function.
|
| + __ push(Immediate(Smi::FromInt(0)));
|
| + } else if (declaration_scope->is_eval_scope()) {
|
| + // Contexts nested inside eval code have the same closure as the context
|
| + // calling eval, not the anonymous closure containing the eval code.
|
| + // Fetch it from the context.
|
| + __ push(ContextOperand(esi, Context::CLOSURE_INDEX));
|
| + } else {
|
| + ASSERT(declaration_scope->is_function_scope());
|
| + __ push(Operand(ebp, JavaScriptFrameConstants::kFunctionOffset));
|
| + }
|
| +}
|
| +
|
| +
|
| // ----------------------------------------------------------------------------
|
| // Non-local control flow support.
|
|
|
| void FullCodeGenerator::EnterFinallyBlock() {
|
| // Cook return address on top of stack (smi encoded Code* delta)
|
| ASSERT(!result_register().is(edx));
|
| - __ mov(edx, Operand(esp, 0));
|
| + __ pop(edx);
|
| __ sub(Operand(edx), Immediate(masm_->CodeObject()));
|
| ASSERT_EQ(1, kSmiTagSize + kSmiShiftSize);
|
| ASSERT_EQ(0, kSmiTag);
|
| - __ add(edx, Operand(edx)); // Convert to smi.
|
| - __ mov(Operand(esp, 0), edx);
|
| + __ SmiTag(edx);
|
| + __ push(edx);
|
| // Store result register while executing finally block.
|
| __ push(result_register());
|
| }
|
| @@ -4342,15 +4264,12 @@
|
|
|
| void FullCodeGenerator::ExitFinallyBlock() {
|
| ASSERT(!result_register().is(edx));
|
| - // Restore result register from stack.
|
| __ pop(result_register());
|
| // Uncook return address.
|
| - __ mov(edx, Operand(esp, 0));
|
| - __ sar(edx, 1); // Convert smi to int.
|
| + __ pop(edx);
|
| + __ SmiUntag(edx);
|
| __ add(Operand(edx), Immediate(masm_->CodeObject()));
|
| - __ mov(Operand(esp, 0), edx);
|
| - // And return.
|
| - __ ret(0);
|
| + __ jmp(Operand(edx));
|
| }
|
|
|
|
|
|
|