📄 codegen-ia32.cc.svn-base
字号:
masm->mov(tmp, ContextOperand(context, Context::CLOSURE_INDEX)); // Load the function context (which is the incoming, outer context). masm->mov(tmp, FieldOperand(tmp, JSFunction::kContextOffset)); context = tmp; } // We may have a 'with' context now. Get the function context. // (In fact this mov may never be the needed, since the scope analysis // may not permit a direct context access in this case and thus we are // always at a function context. However it is safe to dereference be- // cause the function context of a function context is itself. Before // deleting this mov we should try to create a counter-example first, // though...) masm->mov(tmp, ContextOperand(context, Context::FCONTEXT_INDEX)); return ContextOperand(tmp, index); } default: UNREACHABLE(); return Operand(eax); }}// Loads a value on TOS. If it is a boolean value, the result may have been// (partially) translated into branches, or it may have set the condition code// register. If force_cc is set, the value is forced to set the condition code// register and no value is pushed. If the condition code register was set,// has_cc() is true and cc_reg_ contains the condition to test for 'true'.void Ia32CodeGenerator::LoadCondition(Expression* x, CodeGenState::AccessType access, Label* true_target, Label* false_target, bool force_cc) { ASSERT(access == CodeGenState::LOAD || access == CodeGenState::LOAD_TYPEOF_EXPR); ASSERT(!has_cc() && !is_referenced()); { CodeGenState new_state(this, access, true_target, false_target); Visit(x); } if (force_cc && !has_cc()) { ToBoolean(true_target, false_target); } ASSERT(has_cc() || !force_cc);}void Ia32CodeGenerator::Load(Expression* x, CodeGenState::AccessType access) { ASSERT(access == CodeGenState::LOAD || access == CodeGenState::LOAD_TYPEOF_EXPR); Label true_target; Label false_target; LoadCondition(x, access, &true_target, &false_target, false); if (has_cc()) { // convert cc_reg_ into a bool Label loaded, materialize_true; __ j(cc_reg_, &materialize_true); __ push(Immediate(Factory::false_value())); __ jmp(&loaded); __ bind(&materialize_true); __ push(Immediate(Factory::true_value())); __ bind(&loaded); cc_reg_ = no_condition; } if (true_target.is_linked() || false_target.is_linked()) { // we have at least one condition value // that has been "translated" into a branch, // thus it needs to be loaded explicitly again Label loaded; __ jmp(&loaded); // don't lose current TOS bool both = true_target.is_linked() && false_target.is_linked(); // reincarnate "true", if necessary if (true_target.is_linked()) { __ bind(&true_target); __ push(Immediate(Factory::true_value())); } // if both "true" and "false" need to be reincarnated, // jump across code for "false" if (both) __ jmp(&loaded); // reincarnate "false", if necessary if (false_target.is_linked()) { __ bind(&false_target); __ push(Immediate(Factory::false_value())); } // everything is loaded at this point __ bind(&loaded); } ASSERT(!has_cc());}void Ia32CodeGenerator::LoadGlobal() { __ push(GlobalObject());}// TODO(1241834): Get rid of this function in favor of just using Load, now// that we have the LOAD_TYPEOF_EXPR access type. => Need to handle// global variables w/o reference errors elsewhere.void Ia32CodeGenerator::LoadTypeofExpression(Expression* x) { Variable* variable = x->AsVariableProxy()->AsVariable(); if (variable != NULL && !variable->is_this() && variable->is_global()) { // NOTE: This is somewhat nasty. We force the compiler to load // the variable as if through '<global>.<variable>' to make sure we // do not get reference errors. Slot global(variable, Slot::CONTEXT, Context::GLOBAL_INDEX); Literal key(variable->name()); // TODO(1241834): Fetch the position from the variable instead of using // no position. Property property(&global, &key, RelocInfo::kNoPosition); Load(&property); } else { Load(x, CodeGenState::LOAD_TYPEOF_EXPR); }}Reference::Reference(Ia32CodeGenerator* cgen, Expression* expression) : cgen_(cgen), expression_(expression), type_(ILLEGAL) { cgen->LoadReference(this);}Reference::~Reference() { cgen_->UnloadReference(this);}void Ia32CodeGenerator::LoadReference(Reference* ref) { Expression* e = ref->expression(); Property* property = e->AsProperty(); Variable* var = e->AsVariableProxy()->AsVariable(); if (property != NULL) { Load(property->obj()); // Used a named reference if the key is a literal symbol. // We don't use a named reference if they key is a string that can be // legally parsed as an integer. This is because, otherwise we don't // get into the slow case code that handles [] on String objects. Literal* literal = property->key()->AsLiteral(); uint32_t dummy; if (literal != NULL && literal->handle()->IsSymbol() && !String::cast(*(literal->handle()))->AsArrayIndex(&dummy)) { ref->set_type(Reference::NAMED); } else { Load(property->key()); ref->set_type(Reference::KEYED); } } else if (var != NULL) { if (var->is_global()) { // global variable LoadGlobal(); ref->set_type(Reference::NAMED); } else { // local variable ref->set_type(Reference::EMPTY); } } else { Load(e); __ CallRuntime(Runtime::kThrowReferenceError, 1); __ push(eax); }}void Ia32CodeGenerator::UnloadReference(Reference* ref) { // Pop n references on the stack while preserving TOS Comment cmnt(masm_, "[ UnloadReference"); int size = ref->size(); if (size <= 0) { // Do nothing. No popping is necessary. } else if (size == 1) { __ pop(eax); __ mov(TOS, eax); } else { __ pop(eax); __ add(Operand(esp), Immediate(size * kPointerSize)); __ push(eax); }}void Property::GenerateStoreCode(MacroAssembler* masm, Scope* scope, Reference* ref, InitState init_state) { Comment cmnt(masm, "[ Store to Property"); masm->RecordPosition(position()); Ia32CodeGenerator::SetReferenceProperty(masm, ref, key());}void VariableProxy::GenerateStoreCode(MacroAssembler* masm, Scope* scope, Reference* ref, InitState init_state) { Comment cmnt(masm, "[ Store to VariableProxy"); Variable* node = var(); Expression* expr = node->rewrite(); if (expr != NULL) { expr->GenerateStoreCode(masm, scope, ref, init_state); } else { ASSERT(node->is_global()); if (node->AsProperty() != NULL) { masm->RecordPosition(node->AsProperty()->position()); } Ia32CodeGenerator::SetReferenceProperty(masm, ref, new Literal(node->name())); }}void Slot::GenerateStoreCode(MacroAssembler* masm, Scope* scope, Reference* ref, InitState init_state) { Comment cmnt(masm, "[ Store to Slot"); if (type() == Slot::LOOKUP) { ASSERT(var()->mode() == Variable::DYNAMIC); // For now, just do a runtime call. masm->push(Operand(esi)); masm->push(Immediate(var()->name())); if (init_state == CONST_INIT) { // Same as the case for a normal store, but ignores attribute // (e.g. READ_ONLY) of context slot so that we can initialize const // properties (introduced via eval("const foo = (some expr);")). Also, // uses the current function context instead of the top context. // // Note that we must declare the foo upon entry of eval(), via a // context slot declaration, but we cannot initialize it at the same // time, because the const declaration may be at the end of the eval // code (sigh...) and the const variable may have been used before // (where its value is 'undefined'). Thus, we can only do the // initialization when we actually encounter the expression and when // the expression operands are defined and valid, and thus we need the // split into 2 operations: declaration of the context slot followed // by initialization. masm->CallRuntime(Runtime::kInitializeConstContextSlot, 3); } else { masm->CallRuntime(Runtime::kStoreContextSlot, 3); } // Storing a variable must keep the (new) value on the expression // stack. This is necessary for compiling assignment expressions. masm->push(eax); } else { ASSERT(var()->mode() != Variable::DYNAMIC); Label exit; if (init_state == CONST_INIT) { ASSERT(var()->mode() == Variable::CONST); // Only the first const initialization must be executed (the slot // still contains 'the hole' value). When the assignment is executed, // the code is identical to a normal store (see below). Comment cmnt(masm, "[ Init const"); masm->mov(eax, Ia32CodeGenerator::SlotOperand(masm, scope, this, ecx)); masm->cmp(eax, Factory::the_hole_value()); masm->j(not_equal, &exit); } // We must execute the store. // Storing a variable must keep the (new) value on the stack. This is // necessary for compiling assignment expressions. ecx may be loaded // with context; used below in RecordWrite. // // Note: We will reach here even with node->var()->mode() == // Variable::CONST because of const declarations which will initialize // consts to 'the hole' value and by doing so, end up calling this // code. masm->pop(eax); masm->mov(Ia32CodeGenerator::SlotOperand(masm, scope, this, ecx), eax); masm->push(eax); // RecordWrite may destroy the value in eax. if (type() == Slot::CONTEXT) { // ecx is loaded with context when calling SlotOperand above. int offset = FixedArray::kHeaderSize + index() * kPointerSize; masm->RecordWrite(ecx, offset, eax, ebx); } // If we definitely did not jump over the assignment, we do not need to // bind the exit label. Doing so can defeat peephole optimization. if (init_state == CONST_INIT) masm->bind(&exit); }}#undef __#define __ masm->class ToBooleanStub: public CodeStub { public: ToBooleanStub() { } void Generate(MacroAssembler* masm); private: Major MajorKey() { return ToBoolean; } int MinorKey() { return 0; } const char* GetName() { return "ToBooleanStub"; }#ifdef DEBUG void Print() { PrintF("ToBooleanStub\n"); }#endif};// NOTE: The stub does not handle the inlined cases (Smis, Booleans, undefined).void ToBooleanStub::Generate(MacroAssembler* masm) { Label false_result, true_result, not_string; __ mov(eax, Operand(esp, 1 * kPointerSize)); // 'null' => false. __ cmp(eax, Factory::null_value()); __ j(equal, &false_result); // Get the map and type of the heap object. __ mov(edx, FieldOperand(eax, HeapObject::kMapOffset)); __ movzx_b(ecx, FieldOperand(edx, Map::kInstanceTypeOffset)); // Undetectable => false. __ movzx_b(ebx, FieldOperand(edx, Map::kBitFieldOffset)); __ and_(ebx, 1 << Map::kIsUndetectable); __ j(not_zero, &false_result); // JavaScript object => true. __ cmp(ecx, FIRST_JS_OBJECT_TYPE); __ j(above_equal, &true_result); // String value => false iff empty. __ cmp(ecx, FIRST_NONSTRING_TYPE); __ j(above_equal, ¬_string); __ and_(ecx, kStringSizeMask); __ cmp(ecx, kShortStringTag); __ j(not_equal, &true_result); // Empty string is always short. __ mov(edx, FieldOperand(eax, String::kLengthOffset)); __ shr(edx, String::kShortLengthShift); __ j(zero, &false_result); __ jmp(&true_result); __ bind(¬_string); // HeapNumber => false iff +0, -0, or NaN. __ cmp(edx, Factory::heap_number_map()); __ j(not_equal, &true_result); __ fldz(); __ fld_d(FieldOperand(eax, HeapNumber::kValueOffset)); __ fucompp(); __ push(eax); __ fnstsw_ax(); __ sahf(); __ pop(eax); __ j(zero, &false_result); __ jmp(&true_result); // Return 1/0 for true/false in eax. __ bind(&true_result); __ mov(eax, 1); __ ret(1 * kPointerSize); __ bind(&false_result); __ mov(eax, 0); __ ret(1 * kPointerSize);}#undef __#define __ masm_->// ECMA-262, section 9.2, page 30: ToBoolean(). Pop the top of stack and// convert it to a boolean in the condition code register or jump to// 'false_target'/'true_target' as appropriate.void Ia32CodeGenerator::ToBoolean(Label* true_target, Label* false_target) { Comment cmnt(masm_, "[ ToBoolean");
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -