function main() { global $scriptPath, $output_file, $extension_src_path; global $extension_lib_path, $extensions; $ext_func_info = array(); $ext_class_info = array(); $mangleMap = array(); parseIDLForFunctions($ext_func_info, $mangleMap, $scriptPath . '/../../idl/'); parseIDLForMethods($ext_class_info, $mangleMap, $scriptPath . '/../../idl/'); $sepExtDirs = getSepExtDirs($extension_src_path, $extensions); $sepExtHeaders = getSepExtHeaders($extension_src_path, $extensions); foreach ($sepExtDirs as $dir) { parseIDLForFunctions($ext_func_info, $mangleMap, $dir); parseIDLForMethods($ext_class_info, $mangleMap, $dir); } try { $outfile_tempnam = tempnam('/tmp', 'ext_hhvm.cpp.tmp'); $outfile = fopen($outfile_tempnam, 'w'); emit_include($outfile, "runtime/ext_hhvm/ext_hhvm.h"); emit_include($outfile, "runtime/ext/ext.h"); fwrite($outfile, "#include \"ext_hhvm_infotabs.h\"\n"); fwrite($outfile, "namespace HPHP {\n" . " struct TypedValue;\n" . " namespace VM { struct ActRec; struct Class; }\n" . "}\n\n"); fwrite($outfile, "namespace HPHP {\n\n"); // First declare all the stubs we need to be able to register. foreach ($ext_func_info as $obj) { fwrite($outfile, "TypedValue* fg_" . $obj->name . "(VM::ActRec *ar);\n"); } foreach ($ext_class_info as $cname => $method_info) { fwrite($outfile, "VM::Instance* new_" . $cname . "_Instance(" . "VM::Class*);\n"); foreach ($method_info as $obj) { fwrite($outfile, "TypedValue* tg_" . getUniqueFuncName($obj) . "(VM::ActRec *ar);\n"); } } fwrite($outfile, "\n"); fwrite($outfile, "const long long hhbc_ext_funcs_count = " . count($ext_func_info) . ";\n"); fwrite($outfile, "const HhbcExtFuncInfo hhbc_ext_funcs[] = {\n "); $firstParam = true; foreach ($ext_func_info as $obj) { if (!$firstParam) { fwrite($outfile, ",\n "); } $firstParam = false; fwrite($outfile, '{ "' . $obj->name . '", fg_' . $obj->name); fwrite($outfile, ', (void *)&fh_' . $obj->name . ' }'); } fwrite($outfile, "\n};\n\n"); foreach ($ext_class_info as $cname => $method_info) { fwrite($outfile, "static const long long hhbc_ext_method_count_" . $cname . " = " . count($method_info) . ";\n"); fwrite($outfile, "static const HhbcExtMethodInfo hhbc_ext_methods_" . $cname . "[] = {\n "); $firstParam = true; foreach ($method_info as $obj) { if (!$firstParam) { fwrite($outfile, ",\n "); } $firstParam = false; fwrite($outfile, '{ "' . $obj->name . '", tg_' . getUniqueFuncName($obj) . ' }'); } fwrite($outfile, "\n};\n\n"); } fwrite($outfile, "const long long hhbc_ext_class_count = " . count($ext_class_info) . ";\n"); fwrite($outfile, "const HhbcExtClassInfo hhbc_ext_classes[] = {\n "); $firstParam = true; foreach ($ext_class_info as $cname => $method_info) { if (!$firstParam) { fwrite($outfile, ",\n "); } $firstParam = false; fwrite($outfile, '{ "' . $cname . '", new_' . $cname . '_Instance' . ', sizeof(c_' . $cname . ')' . ', hhbc_ext_method_count_' . $cname . ', hhbc_ext_methods_' . $cname . ' }'); } fwrite($outfile, "\n};\n\n"); fwrite($outfile, "\n} // !HPHP\n\n"); fclose($outfile); $outfile = null; `mv -f {$outfile_tempnam} {$output_file}`; } catch (Exception $e) { if ($outfile) { fclose($outfile); } if ($outfile_tempnam) { `rm -rf {$outfile_tempnam}`; } } }
function phase2() { global $scriptPath, $output_file, $extension_src_path; global $extension_lib_path, $extensions; $ext_func_info = array(); $ext_class_info = array(); $mangleMap = generateMangleMap(); parseIDLForFunctions($ext_func_info, $mangleMap, $scriptPath . '/../../idl/', 0); parseIDLForMethods($ext_class_info, $mangleMap, $scriptPath . '/../../idl/'); $sepExtDirs = getSepExtDirs($extension_src_path, $extensions); $sepExtHeaders = getSepExtHeaders($extension_src_path, $extensions); foreach ($sepExtDirs as $dir) { parseIDLForFunctions($ext_func_info, $mangleMap, $dir, 0); parseIDLForMethods($ext_class_info, $mangleMap, $dir); } $ext_hhvm_cpp_tempnam = null; $ext_hhvm_cpp = null; try { $ext_hhvm_cpp_tempnam = tempnam('/tmp', 'ext_hhvm.cpp.tmp'); $ext_hhvm_cpp = fopen($ext_hhvm_cpp_tempnam, 'w'); emit_all_includes($ext_hhvm_cpp, $sepExtHeaders); fwrite($ext_hhvm_cpp, "namespace HPHP {\n\n"); // Generate code for extension functions foreach ($ext_func_info as $obj) { if (!$obj->mangledName) { continue; } // Emit the fh_ function declaration $indent = ''; emitRemappedFuncDecl($obj, $ext_hhvm_cpp, $indent, 'fh_', $mangleMap); // Emit the fg1_ function if needed if ($obj->numTypeChecks > 0) { fwrite($ext_hhvm_cpp, "TypedValue * fg1_" . $obj->name . "(TypedValue* rv, HPHP::VM::ActRec* ar, long long count) " . "__attribute__((noinline,cold));\n"); fwrite($ext_hhvm_cpp, "TypedValue * fg1_" . $obj->name . "(TypedValue* rv, HPHP::VM::ActRec* ar, long long count) {\n"); $indent = ' '; emitSlowPathHelper($obj, $ext_hhvm_cpp, $indent, 'fh_'); fwrite($ext_hhvm_cpp, "}\n\n"); } // Start emitting the fg_ function fwrite($ext_hhvm_cpp, "TypedValue* fg_" . $obj->name . "(HPHP::VM::ActRec *ar) {\n"); $indent = ' '; $indent .= ' '; fwrite($ext_hhvm_cpp, $indent . "TypedValue rv;\n"); fwrite($ext_hhvm_cpp, $indent . "long long count = ar->numArgs();\n"); fwrite($ext_hhvm_cpp, $indent . "TypedValue* args UNUSED = ((TypedValue*)ar) - 1;\n"); $firstParam = true; $needElseClause = false; if ($obj->isVarargs) { if ($obj->minNumParams > 0) { fwrite($ext_hhvm_cpp, $indent . 'if (count >= ' . $obj->minNumParams . 'LL) {' . "\n"); $indent .= ' '; $needElseClause = true; } } else { if ($obj->minNumParams == $obj->maxNumParams) { fwrite($ext_hhvm_cpp, $indent . 'if (count == ' . $obj->minNumParams . 'LL) {' . "\n"); } else { if ($obj->minNumParams == 0) { fwrite($ext_hhvm_cpp, $indent . 'if (count <= ' . $obj->maxNumParams . 'LL) {' . "\n"); } else { fwrite($ext_hhvm_cpp, $indent . 'if (count >= ' . $obj->minNumParams . 'LL && count <= ' . $obj->maxNumParams . 'LL) {' . "\n"); } } $indent .= ' '; $needElseClause = true; } if ($obj->numTypeChecks > 0) { fwrite($ext_hhvm_cpp, $indent . 'if ('); emitTypeCheckCondition($obj, $ext_hhvm_cpp); fwrite($ext_hhvm_cpp, ") {\n"); $indent .= ' '; } emitExtCall($obj, $ext_hhvm_cpp, $indent, 'fh_'); if ($obj->numTypeChecks > 0) { $indent = substr($indent, 2); fwrite($ext_hhvm_cpp, $indent . "} else {\n"); $indent .= ' '; fwrite($ext_hhvm_cpp, $indent . "fg1_" . $obj->name . "(&rv, ar, count);\n"); fwrite($ext_hhvm_cpp, copyAndReturnRV($indent, $obj)); $indent = substr($indent, 2); fwrite($ext_hhvm_cpp, $indent . "}\n"); } if ($needElseClause) { $indent = substr($indent, 2); fwrite($ext_hhvm_cpp, $indent . '} else {' . "\n"); $indent .= ' '; if ($obj->isVarargs) { fwrite($ext_hhvm_cpp, $indent . 'throw_missing_arguments_nr("' . $obj->name . '", count+1, 1);' . "\n"); } else { if ($obj->minNumParams == 0) { fwrite($ext_hhvm_cpp, $indent . 'throw_toomany_arguments_nr("' . $obj->name . '", ' . $obj->maxNumParams . ', 1);' . "\n"); } else { fwrite($ext_hhvm_cpp, $indent . 'throw_wrong_arguments_nr("' . $obj->name . '", count, ' . $obj->minNumParams . ', ' . $obj->maxNumParams . ', 1);' . "\n"); } } $indent = substr($indent, 2); fwrite($ext_hhvm_cpp, $indent . '}' . "\n"); fwrite($ext_hhvm_cpp, $indent . 'rv.m_data.num = 0LL;' . "\n"); fwrite($ext_hhvm_cpp, $indent . 'rv._count = 0;' . "\n"); fwrite($ext_hhvm_cpp, $indent . 'rv.m_type = KindOfNull;' . "\n"); fwrite($ext_hhvm_cpp, copyAndReturnRV($indent, $obj)); } $indent = substr($indent, 2); fwrite($ext_hhvm_cpp, $indent . "return &ar->m_r;\n"); fwrite($ext_hhvm_cpp, "}\n\n\n\n"); } // Extension classes; member functions and the actual instance // object. foreach ($ext_class_info as $cname => $method_info) { foreach ($method_info as $obj) { if (!$obj->mangledName) { continue; } // Emit the instance definition only in in the file that // contains the classes' constructor function. This is just to // avoid multiple definition issues when an extension class is // spread among a few cpp files. if ($obj->name == "__construct") { emit_ctor_helper($ext_hhvm_cpp, $cname); } $indent = ''; // Emit the th_ function declaration emitRemappedFuncDecl($obj, $ext_hhvm_cpp, $indent, 'th_', $mangleMap); // Emit the tg1_ function if needed if ($obj->numTypeChecks > 0) { fwrite($ext_hhvm_cpp, "TypedValue* tg1_" . getUniqueFuncName($obj) . "(TypedValue* rv, HPHP::VM::ActRec* ar, long long count" . (!$obj->isStatic ? ", ObjectData* this_" : "") . ") __attribute__((noinline,cold));\n"); fwrite($ext_hhvm_cpp, "TypedValue* tg1_" . getUniqueFuncName($obj) . "(TypedValue* rv, HPHP::VM::ActRec* ar, long long count" . (!$obj->isStatic ? ", ObjectData* this_" : "") . ") {\n"); $indent = ' '; emitSlowPathHelper($obj, $ext_hhvm_cpp, $indent, 'th_'); fwrite($ext_hhvm_cpp, "}\n\n"); $indent = ''; } // Start emitting the tg_ function fwrite($ext_hhvm_cpp, "TypedValue* tg_" . getUniqueFuncName($obj) . "(HPHP::VM::ActRec *ar) {\n"); $indent = ' '; $indent .= ' '; fwrite($ext_hhvm_cpp, $indent . "TypedValue rv;\n"); fwrite($ext_hhvm_cpp, $indent . "long long count = ar->numArgs();\n"); fwrite($ext_hhvm_cpp, $indent . "TypedValue* args UNUSED " . "= ((TypedValue*)ar) - 1;\n"); if (!$obj->isStatic) { fwrite($ext_hhvm_cpp, $indent . "ObjectData* this_ = (ar->hasThis() ? " . "ar->getThis() : NULL);\n"); } $firstParam = true; $needElseClause = false; $needsNullReturn = false; if (!$obj->isStatic) { fwrite($ext_hhvm_cpp, $indent . "if (this_) {\n"); $indent .= ' '; $needsNullReturn = true; } if ($obj->isVarargs) { if ($obj->minNumParams > 0) { fwrite($ext_hhvm_cpp, $indent . 'if (count >= ' . $obj->minNumParams . 'LL) {' . "\n"); $indent .= ' '; $needElseClause = true; $needsNullReturn = true; } } else { if ($obj->minNumParams == $obj->maxNumParams) { fwrite($ext_hhvm_cpp, $indent . 'if (count == ' . $obj->minNumParams . 'LL) {' . "\n"); } else { if ($obj->minNumParams == 0) { fwrite($ext_hhvm_cpp, $indent . 'if (count <= ' . $obj->maxNumParams . 'LL) {' . "\n"); } else { fwrite($ext_hhvm_cpp, $indent . 'if (count >= ' . $obj->minNumParams . 'LL && count <= ' . $obj->maxNumParams . 'LL) {' . "\n"); } } $indent .= ' '; $needElseClause = true; $needsNullReturn = true; } if ($obj->numTypeChecks > 0) { fwrite($ext_hhvm_cpp, $indent . 'if ('); emitTypeCheckCondition($obj, $ext_hhvm_cpp); fwrite($ext_hhvm_cpp, ") {\n"); $indent .= ' '; } emitExtCall($obj, $ext_hhvm_cpp, $indent, 'th_'); if ($obj->numTypeChecks > 0) { $indent = substr($indent, 2); fwrite($ext_hhvm_cpp, $indent . "} else {\n"); $indent .= ' '; fwrite($ext_hhvm_cpp, $indent . "tg1_" . getUniqueFuncName($obj) . "(&rv, ar, count " . (!$obj->isStatic ? ", this_" : "") . ");\n"); fwrite($ext_hhvm_cpp, copyAndReturnRV($indent, $obj)); $indent = substr($indent, 2); fwrite($ext_hhvm_cpp, $indent . "}\n"); } if ($needElseClause) { $indent = substr($indent, 2); fwrite($ext_hhvm_cpp, $indent . '} else {' . "\n"); $indent .= ' '; if ($obj->isVarargs) { fwrite($ext_hhvm_cpp, $indent . 'throw_missing_arguments_nr("' . $obj->className . '::' . $obj->name . '", count+1, 1);' . "\n"); } else { if ($obj->minNumParams == 0) { fwrite($ext_hhvm_cpp, $indent . 'throw_toomany_arguments_nr("' . $obj->className . '::' . $obj->name . '", ' . $obj->maxNumParams . ', 1);' . "\n"); } else { fwrite($ext_hhvm_cpp, $indent . 'throw_wrong_arguments_nr("' . $obj->className . '::' . $obj->name . '", count, ' . $obj->minNumParams . ', ' . $obj->maxNumParams . ', 1);' . "\n"); } } $indent = substr($indent, 2); fwrite($ext_hhvm_cpp, $indent . '}' . "\n"); } if (!$obj->isStatic) { $indent = substr($indent, 2); fwrite($ext_hhvm_cpp, $indent . "} else {\n"); $indent .= ' '; fwrite($ext_hhvm_cpp, $indent . 'throw_instance_method_fatal("' . $obj->className . '::' . $obj->name . '");' . "\n"); $indent = substr($indent, 2); fwrite($ext_hhvm_cpp, $indent . "}\n"); } if ($needsNullReturn) { fwrite($ext_hhvm_cpp, $indent . 'rv.m_data.num = 0LL;' . "\n"); fwrite($ext_hhvm_cpp, $indent . 'rv._count = 0;' . "\n"); fwrite($ext_hhvm_cpp, $indent . 'rv.m_type = KindOfNull;' . "\n"); fwrite($ext_hhvm_cpp, copyAndReturnRV($indent, $obj)); } $indent = substr($indent, 2); fwrite($ext_hhvm_cpp, $indent . "return &ar->m_r;\n"); fwrite($ext_hhvm_cpp, "}\n\n"); } } fwrite($ext_hhvm_cpp, "\n} // !HPHP\n\n"); fclose($ext_hhvm_cpp); $ext_hhvm_cpp = null; `mv -f {$ext_hhvm_cpp_tempnam} {$output_file}`; } catch (Exception $e) { if ($ext_hhvm_cpp) { fclose($ext_hhvm_cpp); } if ($ext_hhvm_cpp_tempnam) { `rm -rf {$ext_hhvm_cpp_tempnam}`; } } }